char_logif.cpp 25 KB

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