char_logif.cpp 26 KB

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