char_logif.cpp 25 KB

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