char_logif.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/socket.h"
  4. #include "../common/timer.h"
  5. #include "../common/showmsg.h"
  6. #include "../common/sql.h"
  7. #include "../common/utils.h"
  8. #include "../common/strlib.h"
  9. #include "inter.h"
  10. #include "int_guild.h"
  11. #include "char.h"
  12. #include "char_clif.h"
  13. #include "char_mapif.h"
  14. #include "char_logif.h"
  15. #include <stdlib.h>
  16. //early declaration
  17. void chlogif_on_ready(void);
  18. void chlogif_on_disconnect(void);
  19. int chlogif_pincode_notifyLoginPinError( uint32 account_id ){
  20. if (login_fd > 0 && session[login_fd] && !session[login_fd]->flag.eof){
  21. WFIFOHEAD(login_fd,6);
  22. WFIFOW(login_fd,0) = 0x2739;
  23. WFIFOL(login_fd,2) = account_id;
  24. WFIFOSET(login_fd,6);
  25. return 1;
  26. }
  27. return 0;
  28. }
  29. int chlogif_pincode_notifyLoginPinUpdate( uint32 account_id, char* pin ){
  30. if (login_fd > 0 && session[login_fd] && !session[login_fd]->flag.eof){
  31. int size = 8 + PINCODE_LENGTH+1;
  32. WFIFOHEAD(login_fd,size);
  33. WFIFOW(login_fd,0) = 0x2738;
  34. WFIFOW(login_fd,2) = size;
  35. WFIFOL(login_fd,4) = account_id;
  36. strncpy( (char*)WFIFOP(login_fd,8), pin, PINCODE_LENGTH+1 );
  37. WFIFOSET(login_fd,size);
  38. return 1;
  39. }
  40. return 0;
  41. }
  42. void chlogif_pincode_start(int fd, struct char_session_data* sd){
  43. if( charserv_config.pincode_config.pincode_enabled ){
  44. //ShowInfo("Asking to start pincode to AID: %d\n", sd->account_id);
  45. // PIN code system enabled
  46. if( sd->pincode[0] == '\0' ){
  47. // No PIN code has been set yet
  48. if( charserv_config.pincode_config.pincode_force ){
  49. chclif_pincode_sendstate( fd, sd, PINCODE_NEW );
  50. }else{
  51. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  52. }
  53. }else{
  54. if( !(charserv_config.pincode_config.pincode_changetime)
  55. || ( sd->pincode_change + charserv_config.pincode_config.pincode_changetime ) > time(NULL) ){
  56. DBMap* online_char_db = char_get_onlinedb();
  57. struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  58. if( node != NULL && node->pincode_success ){
  59. // User has already passed the check
  60. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  61. }else{
  62. // Ask user for his PIN code
  63. chclif_pincode_sendstate( fd, sd, PINCODE_ASK );
  64. }
  65. }else{
  66. // User hasnt changed his PIN code too long
  67. chclif_pincode_sendstate( fd, sd, PINCODE_EXPIRED );
  68. }
  69. }
  70. }else{
  71. // PIN code system disabled
  72. //ShowInfo("Pincode is disabled.\n");
  73. chclif_pincode_sendstate( fd, sd, PINCODE_OK );
  74. }
  75. }
  76. /**
  77. * Load this character's account id into the 'online accounts' packet
  78. * @see DBApply
  79. */
  80. static int chlogif_send_acc_tologin_sub(DBKey key, DBData *data, va_list ap) {
  81. struct online_char_data* character = db_data2ptr(data);
  82. int* i = va_arg(ap, int*);
  83. if(character->server > -1) {
  84. WFIFOL(login_fd,8+(*i)*4) = character->account_id;
  85. (*i)++;
  86. return 1;
  87. }
  88. return 0;
  89. }
  90. /**
  91. * Timered function to send all account_id connected to login-serv
  92. * @param tid : Timer id
  93. * @param tick : Scheduled tick
  94. * @param id : GID linked to that timered call
  95. * @param data : data transmited for delayed function
  96. * @return
  97. */
  98. int chlogif_send_acc_tologin(int tid, unsigned int tick, int id, intptr_t data) {
  99. if ( chlogif_isconnected() ){
  100. DBMap* online_char_db = char_get_onlinedb();
  101. // send account list to login server
  102. int users = online_char_db->size(online_char_db);
  103. int i = 0;
  104. WFIFOHEAD(login_fd,8+users*4);
  105. WFIFOW(login_fd,0) = 0x272d;
  106. online_char_db->foreach(online_char_db, chlogif_send_acc_tologin_sub, &i, users);
  107. WFIFOW(login_fd,2) = 8+ i*4;
  108. WFIFOL(login_fd,4) = i;
  109. WFIFOSET(login_fd,WFIFOW(login_fd,2));
  110. return 1;
  111. }
  112. return 0;
  113. }
  114. int chlogif_send_usercount(int users){
  115. if( login_fd > 0 && session[login_fd] )
  116. {
  117. // send number of user to login server
  118. WFIFOHEAD(login_fd,6);
  119. WFIFOW(login_fd,0) = 0x2714;
  120. WFIFOL(login_fd,2) = users;
  121. WFIFOSET(login_fd,6);
  122. return 1;
  123. }
  124. return 0;
  125. }
  126. int chlogif_broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data)
  127. {
  128. uint8 buf[6];
  129. int users = char_count_users();
  130. // only send an update when needed
  131. static int prev_users = 0;
  132. if( prev_users == users )
  133. return 0;
  134. prev_users = users;
  135. if( chlogif_isconnected() )
  136. {
  137. // send number of user to login server
  138. WFIFOHEAD(login_fd,6);
  139. WFIFOW(login_fd,0) = 0x2714;
  140. WFIFOL(login_fd,2) = users;
  141. WFIFOSET(login_fd,6);
  142. }
  143. // send number of players to all map-servers
  144. WBUFW(buf,0) = 0x2b00;
  145. WBUFL(buf,2) = users;
  146. chmapif_sendall(buf,6);
  147. return 0;
  148. }
  149. //Send packet forward to login-server for account saving
  150. int chlogif_save_accreg2(unsigned char* buf, int len){
  151. if (login_fd > 0) {
  152. WFIFOHEAD(login_fd,len+4);
  153. memcpy(WFIFOP(login_fd,4), buf, len);
  154. WFIFOW(login_fd,0) = 0x2728;
  155. WFIFOW(login_fd,2) = len+4;
  156. WFIFOSET(login_fd,len+4);
  157. return 1;
  158. }
  159. return 0;
  160. }
  161. int chlogif_request_accreg2(uint32 account_id, uint32 char_id){
  162. if (login_fd > 0) {
  163. WFIFOHEAD(login_fd,10);
  164. WFIFOW(login_fd,0) = 0x272e;
  165. WFIFOL(login_fd,2) = account_id;
  166. WFIFOL(login_fd,6) = char_id;
  167. WFIFOSET(login_fd,10);
  168. return 1;
  169. }
  170. return 0;
  171. }
  172. int chlogif_send_reqaccdata(int fd, struct char_session_data *sd){
  173. //loginif_isconnected
  174. if (login_fd > 0) { // request account data
  175. // request account data
  176. WFIFOHEAD(fd,6);
  177. WFIFOW(fd,0) = 0x2716;
  178. WFIFOL(fd,2) = sd->account_id;
  179. WFIFOSET(fd,6);
  180. return 1;
  181. }
  182. return 0;
  183. }
  184. int chlogif_send_setacconline(int aid){
  185. //loginif_isconnected
  186. if (login_fd > 0 && !session[login_fd]->flag.eof){
  187. WFIFOHEAD(login_fd,6);
  188. WFIFOW(login_fd,0) = 0x272b;
  189. WFIFOL(login_fd,2) = aid;
  190. WFIFOSET(login_fd,6);
  191. return 1;
  192. }
  193. return 0;
  194. }
  195. void chlogif_send_setallaccoffline(int fd){
  196. WFIFOHEAD(fd,2);
  197. WFIFOW(fd,0) = 0x2737;
  198. WFIFOSET(fd,2);
  199. }
  200. int chlogif_send_setaccoffline(int fd, int aid){
  201. if (chlogif_isconnected()){
  202. WFIFOHEAD(fd,6);
  203. WFIFOW(fd,0) = 0x272c;
  204. WFIFOL(fd,2) = aid;
  205. WFIFOSET(fd,6);
  206. return 1;
  207. }
  208. return 0;
  209. }
  210. int chlogif_parse_ackconnect(int fd, struct char_session_data* sd){
  211. if (RFIFOREST(fd) < 3)
  212. return 0;
  213. if (RFIFOB(fd,2)) {
  214. //printf("connect login server error : %d\n", RFIFOB(fd,2));
  215. ShowError("Can not connect to login-server.\n");
  216. ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  217. ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  218. ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  219. set_eof(fd);
  220. return 0;
  221. } else {
  222. ShowStatus("Connected to login-server (connection #%d).\n", fd);
  223. chlogif_on_ready();
  224. }
  225. RFIFOSKIP(fd,3);
  226. return 1;
  227. }
  228. int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){
  229. if (RFIFOREST(fd) < 25)
  230. return 0;
  231. {
  232. uint32 account_id = RFIFOL(fd,2);
  233. uint32 login_id1 = RFIFOL(fd,6);
  234. uint32 login_id2 = RFIFOL(fd,10);
  235. uint8 sex = RFIFOB(fd,14);
  236. uint8 result = RFIFOB(fd,15);
  237. int request_id = RFIFOL(fd,16);
  238. uint32 version = RFIFOL(fd,20);
  239. uint8 clienttype = RFIFOB(fd,24);
  240. RFIFOSKIP(fd,25);
  241. if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  242. !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  243. {
  244. int client_fd = request_id;
  245. sd->version = version;
  246. sd->clienttype = clienttype;
  247. if(sd->version != date2version(PACKETVER))
  248. ShowWarning("s aid=%d has an incorect version=%d in clientinfo. Server compiled for %d\n",
  249. sd->account_id,sd->version,date2version(PACKETVER));
  250. switch( result )
  251. {
  252. case 0:// ok
  253. char_auth_ok(client_fd, sd);
  254. break;
  255. case 1:// auth failed
  256. chclif_reject(client_fd,0); // rejected from server
  257. break;
  258. }
  259. }
  260. }
  261. return 1;
  262. }
  263. int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){
  264. int u_fd; //user fd
  265. if (RFIFOREST(fd) < 75)
  266. return 0;
  267. // find the authenticated session with this account id
  268. ARR_FIND( 0, fd_max, u_fd, session[u_fd] && (sd = (struct char_session_data*)session[u_fd]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
  269. if( u_fd < fd_max )
  270. {
  271. int server_id;
  272. memcpy(sd->email, RFIFOP(fd,6), 40);
  273. sd->expiration_time = (time_t)RFIFOL(fd,46);
  274. sd->group_id = RFIFOB(fd,50);
  275. sd->char_slots = RFIFOB(fd,51);
  276. if( sd->char_slots > MAX_CHARS ) {
  277. ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.h! capping to MAX_CHARS...\n",sd->account_id,sd->char_slots);
  278. sd->char_slots = MAX_CHARS;/* cap to maximum */
  279. } else if ( !sd->char_slots )/* no value aka 0 in sql */
  280. sd->char_slots = MIN_CHARS;/* cap to minimum */
  281. safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  282. safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  283. sd->pincode_change = (time_t)RFIFOL(fd,68);
  284. sd->isvip = RFIFOB(fd,72);
  285. sd->chars_vip = RFIFOB(fd,73);
  286. sd->chars_billing = RFIFOB(fd,74);
  287. ARR_FIND( 0, ARRAYLENGTH(map_server), server_id, map_server[server_id].fd > 0 && map_server[server_id].map[0] );
  288. // continued from char_auth_ok...
  289. if( server_id == ARRAYLENGTH(map_server) || //server not online, bugreport:2359
  290. (charserv_config.max_connect_user == 0 && sd->group_id != charserv_config.gm_allow_group) ||
  291. ( charserv_config.max_connect_user > 0 && char_count_users() >= charserv_config.max_connect_user && sd->group_id != charserv_config.gm_allow_group ) ) {
  292. // refuse connection (over populated)
  293. chclif_reject(u_fd,0);
  294. } else {
  295. // send characters to player
  296. chclif_mmo_char_send(u_fd, sd);
  297. if(sd->version >= date2version(20110309))
  298. chlogif_pincode_start(u_fd,sd);
  299. }
  300. }
  301. RFIFOSKIP(fd,75);
  302. return 1;
  303. }
  304. int chlogif_parse_keepalive(int fd, struct char_session_data* sd){
  305. if (RFIFOREST(fd) < 2)
  306. return 0;
  307. RFIFOSKIP(fd,2);
  308. session[fd]->flag.ping = 0;
  309. return 1;
  310. }
  311. /**
  312. * Performs the necessary operations when changing a character's sex, such as
  313. * correcting the job class and unequipping items, and propagating the
  314. * information to the guild data.
  315. *
  316. * @param sex The new sex (SEX_MALE or SEX_FEMALE).
  317. * @param acc The character's account ID.
  318. * @param char_id The character ID.
  319. * @param class_ The character's current job class.
  320. * @param guild_id The character's guild ID.
  321. */
  322. void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int guild_id)
  323. {
  324. // job modification
  325. if (class_ == JOB_BARD || class_ == JOB_DANCER)
  326. class_ = (sex == SEX_MALE ? JOB_BARD : JOB_DANCER);
  327. else if (class_ == JOB_CLOWN || class_ == JOB_GYPSY)
  328. class_ = (sex == SEX_MALE ? JOB_CLOWN : JOB_GYPSY);
  329. else if (class_ == JOB_BABY_BARD || class_ == JOB_BABY_DANCER)
  330. class_ = (sex == SEX_MALE ? JOB_BABY_BARD : JOB_BABY_DANCER);
  331. else if (class_ == JOB_MINSTREL || class_ == JOB_WANDERER)
  332. class_ = (sex == SEX_MALE ? JOB_MINSTREL : JOB_WANDERER);
  333. else if (class_ == JOB_MINSTREL_T || class_ == JOB_WANDERER_T)
  334. class_ = (sex == SEX_MALE ? JOB_MINSTREL_T : JOB_WANDERER_T);
  335. else if (class_ == JOB_BABY_MINSTREL || class_ == JOB_BABY_WANDERER)
  336. class_ = (sex == SEX_MALE ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  337. else if (class_ == JOB_KAGEROU || class_ == JOB_OBORO)
  338. class_ = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO);
  339. if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'", schema_config.inventory_db, char_id))
  340. Sql_ShowDebug(sql_handle);
  341. if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class` = '%d', `weapon` = '0', `shield` = '0', `head_top` = '0', `head_mid` = '0', `head_bottom` = '0' WHERE `char_id` = '%d'", schema_config.char_db, class_, char_id))
  342. Sql_ShowDebug(sql_handle);
  343. if (guild_id) // If there is a guild, update the guild_member data [Skotlex]
  344. inter_guild_sex_changed(guild_id, acc, char_id, sex);
  345. }
  346. int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd)
  347. {
  348. if (RFIFOREST(fd) < 7)
  349. return 0;
  350. {
  351. unsigned char buf[7];
  352. int acc = RFIFOL(fd,2);
  353. int sex = RFIFOB(fd,6);
  354. RFIFOSKIP(fd,7);
  355. if (acc > 0) { // TODO: Is this even possible?
  356. unsigned char i;
  357. int char_id = 0, class_ = 0, guild_id = 0;
  358. DBMap* auth_db = char_get_authdb();
  359. struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  360. SqlStmt *stmt;
  361. if (node != NULL)
  362. node->sex = sex;
  363. // get characters
  364. stmt = SqlStmt_Malloc(sql_handle);
  365. if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `char_id`, `class`, `guild_id` FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, acc) || SqlStmt_Execute(stmt)) {
  366. SqlStmt_ShowDebug(stmt);
  367. SqlStmt_Free(stmt);
  368. }
  369. SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &char_id, 0, NULL, NULL);
  370. SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &class_, 0, NULL, NULL);
  371. SqlStmt_BindColumn(stmt, 2, SQLDT_INT, &guild_id, 0, NULL, NULL);
  372. for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) {
  373. chlogif_parse_change_sex_sub(sex, acc, char_id, class_, guild_id);
  374. }
  375. SqlStmt_Free(stmt);
  376. }
  377. // notify all mapservers about this change
  378. WBUFW(buf,0) = 0x2b0d;
  379. WBUFL(buf,2) = acc;
  380. WBUFB(buf,6) = sex;
  381. chmapif_sendall(buf, 7);
  382. }
  383. return 1;
  384. }
  385. /**
  386. * Changes a character's sex.
  387. * The information is updated on database, and the character is kicked if it
  388. * currently is online.
  389. *
  390. * @param char_id The character's ID.
  391. * @param sex The new sex.
  392. * @retval 0 in case of success.
  393. * @retval 1 in case of failure.
  394. */
  395. int chlogif_parse_ackchangecharsex(int char_id, int sex)
  396. {
  397. int class_ = 0, guild_id = 0, account_id = 0;
  398. unsigned char buf[7];
  399. char *data;
  400. // get character data
  401. if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`class`,`guild_id` FROM `%s` WHERE `char_id` = '%d'", schema_config.char_db, char_id)) {
  402. Sql_ShowDebug(sql_handle);
  403. return 1;
  404. }
  405. if (Sql_NumRows(sql_handle) != 1 || SQL_ERROR == Sql_NextRow(sql_handle)) {
  406. Sql_FreeResult(sql_handle);
  407. return 1;
  408. }
  409. Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  410. Sql_GetData(sql_handle, 1, &data, NULL); class_ = atoi(data);
  411. Sql_GetData(sql_handle, 2, &data, NULL); guild_id = atoi(data);
  412. Sql_FreeResult(sql_handle);
  413. if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `sex` = '%c' WHERE `char_id` = '%d'", schema_config.char_db, sex == SEX_MALE ? 'M' : 'F', char_id)) {
  414. Sql_ShowDebug(sql_handle);
  415. return 1;
  416. }
  417. chlogif_parse_change_sex_sub(sex, account_id, char_id, class_, guild_id);
  418. // disconnect player if online on char-server
  419. char_disconnect_player(account_id);
  420. // notify all mapservers about this change
  421. WBUFW(buf,0) = 0x2b0d;
  422. WBUFL(buf,2) = account_id;
  423. WBUFB(buf,6) = sex;
  424. chmapif_sendall(buf, 7);
  425. return 0;
  426. }
  427. int chlogif_parse_ackacc2req(int fd, struct char_session_data* sd){
  428. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  429. return 0;
  430. { //Receive account_reg2 registry, forward to map servers.
  431. unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  432. memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  433. WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  434. chmapif_sendall(buf, WBUFW(buf,2));
  435. RFIFOSKIP(fd, RFIFOW(fd,2));
  436. }
  437. return 1;
  438. }
  439. int chlogif_parse_accbannotification(int fd, struct char_session_data* sd){
  440. if (RFIFOREST(fd) < 11)
  441. return 0;
  442. { // send to all map-servers to disconnect the player
  443. unsigned char buf[11];
  444. WBUFW(buf,0) = 0x2b14;
  445. WBUFL(buf,2) = RFIFOL(fd,2);
  446. WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  447. WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  448. chmapif_sendall(buf, 11);
  449. }
  450. // disconnect player if online on char-server
  451. char_disconnect_player(RFIFOL(fd,2));
  452. RFIFOSKIP(fd,11);
  453. return 1;
  454. }
  455. int chlogif_parse_askkick(int fd, struct char_session_data* sd){
  456. if (RFIFOREST(fd) < 6)
  457. return 0;
  458. {
  459. DBMap* online_char_db = char_get_onlinedb();
  460. DBMap* auth_db = char_get_authdb();
  461. int aid = RFIFOL(fd,2);
  462. struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  463. RFIFOSKIP(fd,6);
  464. if( character != NULL )
  465. {// account is already marked as online!
  466. if( character->server > -1 )
  467. { //Kick it from the map server it is on.
  468. mapif_disconnectplayer(map_server[character->server].fd, character->account_id, character->char_id, 2);
  469. if (character->waiting_disconnect == INVALID_TIMER)
  470. character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, char_chardb_waiting_disconnect, character->account_id, 0);
  471. }
  472. else
  473. {// Manual kick from char server.
  474. struct char_session_data *tsd;
  475. int i;
  476. ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  477. if( i < fd_max )
  478. {
  479. chclif_send_auth_result(i,2); //Send "Someone has already logged in with this id"
  480. set_eof(i);
  481. }
  482. else // still moving to the map-server
  483. char_set_char_offline(-1, aid);
  484. }
  485. }
  486. idb_remove(auth_db, aid);// reject auth attempts from map-server
  487. }
  488. return 1;
  489. }
  490. int chlogif_parse_updip(int fd, struct char_session_data* sd){
  491. unsigned char buf[2];
  492. uint32 new_ip = 0;
  493. WBUFW(buf,0) = 0x2b1e;
  494. chmapif_sendall(buf, 2);
  495. new_ip = host2ip(charserv_config.login_ip_str);
  496. if (new_ip && new_ip != charserv_config.login_ip)
  497. charserv_config.login_ip = new_ip; //Update login ip, too.
  498. new_ip = host2ip(charserv_config.char_ip_str);
  499. if (new_ip && new_ip != charserv_config.char_ip)
  500. { //Update ip.
  501. charserv_config.char_ip = new_ip;
  502. ShowInfo("Updating IP for [%s].\n", charserv_config.char_ip_str);
  503. // notify login server about the change
  504. WFIFOHEAD(fd,6);
  505. WFIFOW(fd,0) = 0x2736;
  506. WFIFOL(fd,2) = htonl(charserv_config.char_ip);
  507. WFIFOSET(fd,6);
  508. }
  509. RFIFOSKIP(fd,2);
  510. return 1;
  511. }
  512. /*
  513. * AH 0x2743
  514. * We received the info from login-serv, transmit it to map
  515. */
  516. int chlogif_parse_vipack(int fd) {
  517. #ifdef VIP_ENABLE
  518. if (RFIFOREST(fd) < 20)
  519. return 0;
  520. else {
  521. uint32 aid = RFIFOL(fd,2); //aid
  522. uint32 vip_time = RFIFOL(fd,6); //vip_time
  523. uint8 isvip = RFIFOB(fd,10); //isvip
  524. uint32 groupid = RFIFOL(fd,11); //new group id
  525. uint8 isgm = RFIFOB(fd,15); //isgm
  526. int mapfd = RFIFOL(fd,16); //link to mapserv for ack
  527. RFIFOSKIP(fd,20);
  528. chmapif_vipack(mapfd,aid,vip_time,isvip,isgm,groupid);
  529. }
  530. #endif
  531. return 1;
  532. }
  533. /**
  534. * HZ 0x2b2b
  535. * Request vip data from loginserv
  536. * @param aid : account_id to request the vip data
  537. * @param type : &2 define new duration, &1 load info
  538. * @param add_vip_time : tick to add to vip timestamp
  539. * @param mapfd: link to mapserv for ack
  540. * @return 0 if success
  541. */
  542. int chlogif_reqvipdata(uint32 aid, uint8 type, int32 timediff, int mapfd) {
  543. loginif_check(-1);
  544. #ifdef VIP_ENABLE
  545. WFIFOHEAD(login_fd,15);
  546. WFIFOW(login_fd,0) = 0x2742;
  547. WFIFOL(login_fd,2) = aid; //aid
  548. WFIFOB(login_fd,6) = type; //type
  549. WFIFOL(login_fd,7) = timediff; //req_inc_duration
  550. WFIFOL(login_fd,11) = mapfd; //req_inc_duration
  551. WFIFOSET(login_fd,15);
  552. #endif
  553. return 0;
  554. }
  555. /**
  556. * HA 0x2720
  557. * Request account info to login-server
  558. */
  559. int chlogif_req_accinfo(int fd, int u_fd, int u_aid, int u_group, int account_id, int8 type) {
  560. loginif_check(-1);
  561. //ShowInfo("%d request account info for %d (type %d)\n", u_aid, account_id, type);
  562. WFIFOHEAD(login_fd,23);
  563. WFIFOW(login_fd,0) = 0x2720;
  564. WFIFOL(login_fd,2) = fd;
  565. WFIFOL(login_fd,6) = u_fd;
  566. WFIFOL(login_fd,10) = u_aid;
  567. WFIFOL(login_fd,14) = u_group;
  568. WFIFOL(login_fd,18) = account_id;
  569. WFIFOB(login_fd,22) = type;
  570. WFIFOSET(login_fd,23);
  571. return 1;
  572. }
  573. /**
  574. * AH 0x2721
  575. * Retrieve account info from login-server, ask inter-server to tell player
  576. */
  577. int chlogif_parse_AccInfoAck(int fd) {
  578. if (RFIFOREST(fd) < 19)
  579. return 0;
  580. else {
  581. int8 type = RFIFOB(fd, 18);
  582. if (type == 0 || RFIFOREST(fd) < 155+PINCODE_LENGTH+NAME_LENGTH) {
  583. mapif_accinfo_ack(false, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), 0, -1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  584. RFIFOSKIP(fd,19);
  585. return 1;
  586. }
  587. type>>=1;
  588. mapif_accinfo_ack(true, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), type, RFIFOL(fd,19), RFIFOL(fd,23), RFIFOL(fd,27),
  589. (char*)RFIFOP(fd,31), (char*)RFIFOP(fd,71), (char*)RFIFOP(fd,87), (char*)RFIFOP(fd,111),
  590. (char*)RFIFOP(fd,122), (char*)RFIFOP(fd,155), (char*)RFIFOP(fd,155+PINCODE_LENGTH));
  591. RFIFOSKIP(fd,155+PINCODE_LENGTH+NAME_LENGTH);
  592. }
  593. return 1;
  594. }
  595. int chlogif_parse(int fd) {
  596. struct char_session_data* sd = NULL;
  597. // only process data from the login-server
  598. if( fd != login_fd ) {
  599. ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  600. do_close(fd);
  601. return 0;
  602. }
  603. if( session[fd]->flag.eof ) {
  604. do_close(fd);
  605. login_fd = -1;
  606. chlogif_on_disconnect();
  607. return 0;
  608. } else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  609. if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  610. set_eof(fd);
  611. return 0;
  612. } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  613. WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  614. WFIFOW(fd,0) = 0x2719;
  615. WFIFOSET(fd,2);
  616. session[fd]->flag.ping = 2;
  617. }
  618. }
  619. sd = (struct char_session_data*)session[fd]->session_data;
  620. while(RFIFOREST(fd) >= 2) {
  621. int next=1;
  622. uint16 command = RFIFOW(fd,0);
  623. switch( command )
  624. {
  625. case 0x2743: next = chlogif_parse_vipack(fd); break;
  626. // acknowledgement of connect-to-loginserver request
  627. case 0x2711: next = chlogif_parse_ackconnect(fd,sd); break;
  628. // acknowledgement of account authentication request
  629. case 0x2713: next = chlogif_parse_ackaccreq(fd, sd); break;
  630. // account data
  631. case 0x2717: next = chlogif_parse_reqaccdata(fd, sd); break;
  632. // login-server alive packet
  633. case 0x2718: next = chlogif_parse_keepalive(fd, sd); break;
  634. // changesex reply
  635. case 0x2723: next = chlogif_parse_ackchangesex(fd, sd); break;
  636. // reply to an account_reg2 registry request
  637. case 0x2729: next = chlogif_parse_ackacc2req(fd, sd); break;
  638. // State change of account/ban notification (from login-server)
  639. case 0x2731: next = chlogif_parse_accbannotification(fd, sd); break;
  640. // Login server request to kick a character out. [Skotlex]
  641. case 0x2734: next = chlogif_parse_askkick(fd,sd); break;
  642. // ip address update signal from login server
  643. case 0x2735: next = chlogif_parse_updip(fd,sd); break;
  644. // @accinfo result
  645. case 0x2721: next = chlogif_parse_AccInfoAck(fd); break;
  646. default:
  647. ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  648. set_eof(fd);
  649. return 0;
  650. }
  651. if(next==0) return 0; //do not parse next data
  652. }
  653. RFIFOFLUSH(fd);
  654. return 0;
  655. }
  656. int chlogif_check_connect_logserver(int tid, unsigned int tick, int id, intptr_t data) {
  657. if (login_fd > 0 && session[login_fd] != NULL)
  658. return 0;
  659. ShowInfo("Attempt to connect to login-server...\n");
  660. login_fd = make_connection(charserv_config.login_ip, charserv_config.login_port, false,10);
  661. if (login_fd == -1)
  662. { //Try again later. [Skotlex]
  663. login_fd = 0;
  664. return 0;
  665. }
  666. session[login_fd]->func_parse = chlogif_parse;
  667. session[login_fd]->flag.server = 1;
  668. realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  669. WFIFOHEAD(login_fd,86);
  670. WFIFOW(login_fd,0) = 0x2710;
  671. memcpy(WFIFOP(login_fd,2), charserv_config.userid, 24);
  672. memcpy(WFIFOP(login_fd,26), charserv_config.passwd, 24);
  673. WFIFOL(login_fd,50) = 0;
  674. WFIFOL(login_fd,54) = htonl(charserv_config.char_ip);
  675. WFIFOW(login_fd,58) = htons(charserv_config.char_port);
  676. memcpy(WFIFOP(login_fd,60), charserv_config.server_name, 20);
  677. WFIFOW(login_fd,80) = 0;
  678. WFIFOW(login_fd,82) = charserv_config.char_maintenance;
  679. WFIFOW(login_fd,84) = charserv_config.char_new_display; //only display (New) if they want to [Kevin]
  680. WFIFOSET(login_fd,86);
  681. return 1;
  682. }
  683. int chlogif_isconnected(){
  684. return (login_fd > 0 && session[login_fd] && !session[login_fd]->flag.eof);
  685. }
  686. void do_init_chlogif(void) {
  687. // establish char-login connection if not present
  688. add_timer_func_list(chlogif_check_connect_logserver, "check_connect_login_server");
  689. add_timer_interval(gettick() + 1000, chlogif_check_connect_logserver, 0, 0, 10 * 1000);
  690. // send a list of all online account IDs to login server
  691. add_timer_func_list(chlogif_send_acc_tologin, "send_accounts_tologin");
  692. add_timer_interval(gettick() + 1000, chlogif_send_acc_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour
  693. }
  694. /// Resets all the data.
  695. void chlogif_reset(void){
  696. int id;
  697. // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS]
  698. for( id = 0; id < ARRAYLENGTH(map_server); ++id )
  699. chmapif_server_reset(id);
  700. flush_fifos();
  701. exit(EXIT_FAILURE);
  702. }
  703. /// Checks the conditions for the server to stop.
  704. /// Releases the cookie when all characters are saved.
  705. /// If all the conditions are met, it stops the core loop.
  706. void chlogif_check_shutdown(void)
  707. {
  708. if( runflag != CHARSERVER_ST_SHUTDOWN )
  709. return;
  710. runflag = CORE_ST_STOP;
  711. }
  712. /// Called when the connection to Login Server is disconnected.
  713. void chlogif_on_disconnect(void){
  714. ShowWarning("Connection to Login Server lost.\n\n");
  715. }
  716. /// Called when all the connection steps are completed.
  717. void chlogif_on_ready(void)
  718. {
  719. int i;
  720. chlogif_check_shutdown();
  721. //Send online accounts to login server.
  722. chlogif_send_acc_tologin(INVALID_TIMER, gettick(), 0, 0);
  723. // if no map-server already connected, display a message...
  724. ARR_FIND( 0, ARRAYLENGTH(map_server), i, map_server[i].fd > 0 && map_server[i].map[0] );
  725. if( i == ARRAYLENGTH(map_server) )
  726. ShowStatus("Awaiting maps from map-server.\n");
  727. }
  728. void do_final_chlogif(void)
  729. {
  730. if( login_fd != -1 )
  731. {
  732. do_close(login_fd);
  733. login_fd = -1;
  734. }
  735. }