char_clif.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/mmo.h"
  4. #include "../common/socket.h"
  5. #include "../common/sql.h"
  6. #include "../common/random.h"
  7. #include "../common/showmsg.h"
  8. #include "../common/mapindex.h"
  9. #include "../common/malloc.h"
  10. #include "../common/strlib.h"
  11. #include "../common/utils.h"
  12. #include "../common/timer.h"
  13. #include "inter.h"
  14. #include "char.h"
  15. #include "char_logif.h"
  16. #include "char_mapif.h"
  17. #include "char_clif.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. //------------------------------------------------
  22. //Add On system
  23. //------------------------------------------------
  24. // reason
  25. // 0: success
  26. // 1: failed
  27. void chclif_moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  28. WFIFOHEAD(fd,8);
  29. WFIFOW(fd,0) = 0x8d5;
  30. WFIFOW(fd,2) = 8;
  31. WFIFOW(fd,4) = reason;
  32. WFIFOW(fd,6) = sd->char_moves[index];
  33. WFIFOSET(fd,8);
  34. }
  35. /*
  36. * Client is requesting to move a charslot
  37. */
  38. int chclif_parse_moveCharSlot( int fd, struct char_session_data* sd){
  39. uint16 from, to;
  40. if( RFIFOREST(fd) < 8 )
  41. return 0;
  42. from = RFIFOW(fd,2);
  43. to = RFIFOW(fd,4);
  44. //Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
  45. RFIFOSKIP(fd,8);
  46. // Have we changed to often or is it disabled?
  47. if( (charserv_config.charmove_config.char_move_enabled)==0
  48. || ( (charserv_config.charmove_config.char_moves_unlimited)==0 && sd->char_moves[from] <= 0 ) ){
  49. chclif_moveCharSlotReply( fd, sd, from, 1 );
  50. return 1;
  51. }
  52. // We don't even have a character on the chosen slot?
  53. if( sd->found_char[from] <= 0 || to >= sd->char_slots ){
  54. chclif_moveCharSlotReply( fd, sd, from, 1 );
  55. return 1;
  56. }
  57. if( sd->found_char[to] > 0 ){
  58. // We want to move to a used position
  59. if( charserv_config.charmove_config.char_movetoused ){ // TODO: check if the target is in deletion process
  60. // Admin is friendly and uses triangle exchange
  61. if( SQL_ERROR == Sql_QueryStr(sql_handle, "START TRANSACTION")
  62. || SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'",schema_config.char_db, to, sd->found_char[from] )
  63. || SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'", schema_config.char_db, from, sd->found_char[to] )
  64. || SQL_ERROR == Sql_QueryStr(sql_handle, "COMMIT")
  65. ){
  66. chclif_moveCharSlotReply( fd, sd, from, 1 );
  67. Sql_ShowDebug(sql_handle);
  68. Sql_QueryStr(sql_handle,"ROLLBACK");
  69. return 1;
  70. }
  71. }else{
  72. // Admin doesn't allow us to
  73. chclif_moveCharSlotReply( fd, sd, from, 1 );
  74. return 1;
  75. }
  76. }else if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id`='%d'", schema_config.char_db, to, sd->found_char[from] ) ){
  77. Sql_ShowDebug(sql_handle);
  78. chclif_moveCharSlotReply( fd, sd, from, 1 );
  79. return 1;
  80. }
  81. if( (charserv_config.charmove_config.char_moves_unlimited)==0 ){
  82. sd->char_moves[from]--;
  83. Sql_Query(sql_handle, "UPDATE `%s` SET `moves`='%d' WHERE `char_id`='%d'", schema_config.char_db, sd->char_moves[from], sd->found_char[from] );
  84. }
  85. // We successfully moved the char - time to notify the client
  86. chclif_moveCharSlotReply( fd, sd, from, 0 );
  87. chclif_mmo_char_send(fd, sd);
  88. return 1;
  89. }
  90. /* pincode_sendstate transmist the pincode state to client
  91. * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
  92. * state :
  93. * 0 = disabled / pin is correct
  94. * 1 = ask for pin - client sends 0x8b8
  95. * 2 = create new pin - client sends 0x8ba
  96. * 3 = pin must be changed - client 0x8be
  97. * 4 = create new pin - client sends 0x8ba
  98. * 5 = client shows msgstr(1896)
  99. * 6 = client shows msgstr(1897) Unable to use your KSSN number
  100. * 7 = char select window shows a button - client sends 0x8c5
  101. * 8 = pincode was incorrect
  102. */
  103. void chclif_pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
  104. WFIFOHEAD(fd, 12);
  105. WFIFOW(fd, 0) = 0x8b9;
  106. WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  107. WFIFOL(fd, 6) = sd->account_id;
  108. WFIFOW(fd,10) = state;
  109. WFIFOSET(fd,12);
  110. }
  111. /*
  112. * Client just entering charserv from login, send him pincode confirmation
  113. */
  114. int chclif_parse_reqpincode_window(int fd, struct char_session_data* sd){
  115. if( RFIFOREST(fd) < 6 )
  116. return 0;
  117. if( charserv_config.pincode_config.pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  118. if( strlen( sd->pincode ) <= 0 ){
  119. chclif_pincode_sendstate( fd, sd, PINCODE_NEW );
  120. }else{
  121. chclif_pincode_sendstate( fd, sd, PINCODE_ASK );
  122. }
  123. }
  124. RFIFOSKIP(fd,6);
  125. return 1;
  126. }
  127. /*
  128. * Client as anwsered pincode questionning, checking if valid anwser
  129. */
  130. int chclif_parse_pincode_check( int fd, struct char_session_data* sd ){
  131. char pin[PINCODE_LENGTH+1];
  132. if( RFIFOREST(fd) < 10 )
  133. return 0;
  134. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  135. return 1;
  136. memset(pin,0,PINCODE_LENGTH+1);
  137. strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  138. RFIFOSKIP(fd,10);
  139. char_pincode_decrypt(sd->pincode_seed, pin );
  140. if( char_pincode_compare( fd, sd, pin ) ){
  141. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  142. }
  143. return 1;
  144. }
  145. /*
  146. * Client request to change pincode
  147. */
  148. int chclif_parse_pincode_change( int fd, struct char_session_data* sd ){
  149. if( RFIFOREST(fd) < 14 )
  150. return 0;
  151. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  152. return 1;
  153. else {
  154. char oldpin[PINCODE_LENGTH+1];
  155. char newpin[PINCODE_LENGTH+1];
  156. memset(oldpin,0,PINCODE_LENGTH+1);
  157. memset(newpin,0,PINCODE_LENGTH+1);
  158. strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  159. strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  160. RFIFOSKIP(fd,14);
  161. char_pincode_decrypt(sd->pincode_seed,oldpin);
  162. if( !char_pincode_compare( fd, sd, oldpin ) )
  163. return 1;
  164. char_pincode_decrypt(sd->pincode_seed,newpin);
  165. chlogif_pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  166. strncpy(sd->pincode, newpin, sizeof(newpin));
  167. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  168. }
  169. return 1;
  170. }
  171. /*
  172. * activate PIN system and set first PIN
  173. */
  174. int chclif_parse_pincode_setnew( int fd, struct char_session_data* sd ){
  175. if( RFIFOREST(fd) < 10 )
  176. return 0;
  177. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  178. return 1;
  179. else {
  180. char newpin[PINCODE_LENGTH+1];
  181. memset(newpin,0,PINCODE_LENGTH+1);
  182. strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
  183. RFIFOSKIP(fd,10);
  184. char_pincode_decrypt( sd->pincode_seed, newpin );
  185. chlogif_pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  186. strncpy( sd->pincode, newpin, strlen( newpin ) );
  187. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  188. }
  189. return 1;
  190. }
  191. //----------------------------------------
  192. // Tell client how many pages, kRO sends 17 (Yommy)
  193. //----------------------------------------
  194. void chclif_charlist_notify( int fd, struct char_session_data* sd ){
  195. WFIFOHEAD(fd, 6);
  196. WFIFOW(fd, 0) = 0x9a0;
  197. // pages to req / send them all in 1 until mmo_chars_fromsql can split them up
  198. WFIFOL(fd, 2) = (sd->char_slots>3)?sd->char_slots/3:1; //int TotalCnt (nb page to load)
  199. WFIFOSET(fd,6);
  200. }
  201. //----------------------------------------
  202. // Function to send characters to a player
  203. //----------------------------------------
  204. int chclif_mmo_send006b(int fd, struct char_session_data* sd){
  205. int j, offset = 0;
  206. bool newvers = (sd->version >= date2version(20100413) );
  207. if(newvers) //20100413
  208. offset += 3;
  209. if (charserv_config.save_log)
  210. ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
  211. j = 24 + offset; // offset
  212. WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF);
  213. WFIFOW(fd,0) = 0x6b;
  214. if(newvers){ //20100413
  215. WFIFOB(fd,4) = MAX_CHARS; // Max slots.
  216. WFIFOB(fd,5) = sd->char_slots; // Available slots. (PremiumStartSlot)
  217. WFIFOB(fd,6) = MAX_CHARS; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red)
  218. }
  219. memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes
  220. j+=char_mmo_chars_fromsql(sd, WFIFOP(fd,j));
  221. WFIFOW(fd,2) = j; // packet len
  222. WFIFOSET(fd,j);
  223. return 0;
  224. }
  225. //----------------------------------------
  226. // Notify client about charselect window data [Ind]
  227. //----------------------------------------
  228. void chclif_mmo_send082d(int fd, struct char_session_data* sd) {
  229. if (charserv_config.save_log)
  230. ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
  231. WFIFOHEAD(fd,29);
  232. WFIFOW(fd,0) = 0x82d;
  233. WFIFOW(fd,2) = 29;
  234. WFIFOB(fd,4) = sd->char_slots;
  235. WFIFOB(fd,5) = MAX_CHARS - sd->char_slots;
  236. WFIFOB(fd,6) = MAX_CHARS - sd->char_slots;
  237. WFIFOB(fd,7) = sd->char_slots;
  238. WFIFOB(fd,8) = sd->char_slots;
  239. memset(WFIFOP(fd,9), 0, 20); // unused bytes
  240. WFIFOSET(fd,29);
  241. }
  242. void chclif_mmo_send099d(int fd, struct char_session_data *sd) {
  243. WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF));
  244. WFIFOW(fd,0) = 0x99d;
  245. WFIFOW(fd,2) = char_mmo_chars_fromsql(sd, WFIFOP(fd,4)) + 4;
  246. WFIFOSET(fd,WFIFOW(fd,2));
  247. }
  248. /*
  249. * Function to choose wich kind of charlist to send to client depending on his version
  250. */
  251. void chclif_mmo_char_send(int fd, struct char_session_data* sd){
  252. ShowInfo("sd->version = %d\n",sd->version);
  253. if(sd->version >= date2version(20130000) ){
  254. chclif_mmo_send082d(fd,sd);
  255. chclif_charlist_notify(fd,sd);
  256. chclif_block_character(fd,sd);
  257. }
  258. //@FIXME dump from kro doesn't show 6b transmission
  259. chclif_mmo_send006b(fd,sd);
  260. }
  261. /*
  262. * Transmit auth result to client
  263. * <result>.B ()
  264. * result :
  265. * 1 : Server closed
  266. * 2 : Someone has already logged in with this id
  267. * 8 : already online
  268. */
  269. void chclif_send_auth_result(int fd,char result){
  270. WFIFOHEAD(fd,3);
  271. WFIFOW(fd,0) = 0x81;
  272. WFIFOB(fd,2) = result;
  273. WFIFOSET(fd,3);
  274. }
  275. /// @param result
  276. /// 0 (0x718): An unknown error has occurred.
  277. /// 1: none/success
  278. /// 3 (0x719): A database error occurred.
  279. /// 4 (0x71a): To delete a character you must withdraw from the guild.
  280. /// 5 (0x71b): To delete a character you must withdraw from the party.
  281. /// Any (0x718): An unknown error has occurred.
  282. /// HC: <0828>.W <char id>.L <Msg:0-5>.L <deleteDate>.L
  283. void chclif_char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) {
  284. WFIFOHEAD(fd,14);
  285. WFIFOW(fd,0) = 0x828;
  286. WFIFOL(fd,2) = char_id;
  287. WFIFOL(fd,6) = result;
  288. WFIFOL(fd,10) = TOL(delete_date-time(NULL));
  289. WFIFOSET(fd,14);
  290. }
  291. /// @param result
  292. /// 0 (0x718): An unknown error has occurred.
  293. /// 1: none/success
  294. /// 2 (0x71c): Due to system settings can not be deleted.
  295. /// 3 (0x719): A database error occurred.
  296. /// 4 (0x71d): Deleting not yet possible time.
  297. /// 5 (0x71e): Date of birth do not match.
  298. /// Any (0x718): An unknown error has occurred.
  299. /// HC: <082a>.W <char id>.L <Msg:0-5>.L
  300. void chclif_char_delete2_accept_ack(int fd, int char_id, uint32 result) {
  301. WFIFOHEAD(fd,10);
  302. WFIFOW(fd,0) = 0x82a;
  303. WFIFOL(fd,2) = char_id;
  304. WFIFOL(fd,6) = result;
  305. WFIFOSET(fd,10);
  306. }
  307. /// @param result
  308. /// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
  309. /// 2 (0x719): A database error occurred.
  310. /// Any (0x718): An unknown error has occurred.
  311. /// HC: <082c>.W <char id>.L <Msg:1-2>.L
  312. void chclif_char_delete2_cancel_ack(int fd, int char_id, uint32 result) {
  313. WFIFOHEAD(fd,10);
  314. WFIFOW(fd,0) = 0x82c;
  315. WFIFOL(fd,2) = char_id;
  316. WFIFOL(fd,6) = result;
  317. WFIFOSET(fd,10);
  318. }
  319. // CH: <0827>.W <char id>.L
  320. int chclif_parse_char_delete2_req(int fd, struct char_session_data* sd) {
  321. FIFOSD_CHECK(6)
  322. {
  323. int char_id, i;
  324. char* data;
  325. time_t delete_date;
  326. char_id = RFIFOL(fd,2);
  327. RFIFOSKIP(fd,6);
  328. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  329. if( i == MAX_CHARS )
  330. {// character not found
  331. chclif_char_delete2_ack(fd, char_id, 3, 0);
  332. return 1;
  333. }
  334. if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
  335. {
  336. Sql_ShowDebug(sql_handle);
  337. chclif_char_delete2_ack(fd, char_id, 3, 0);
  338. return 1;
  339. }
  340. Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
  341. if( delete_date ) {// character already queued for deletion
  342. chclif_char_delete2_ack(fd, char_id, 0, 0);
  343. return 1;
  344. }
  345. /*
  346. // Aegis imposes these checks probably to avoid dead member
  347. // entries in guilds/parties, otherwise they are not required.
  348. // TODO: Figure out how these are enforced during waiting.
  349. if( guild_id )
  350. {// character in guild
  351. chclif_char_delete2_ack(fd, char_id, 4, 0);
  352. return 1;
  353. }
  354. if( party_id )
  355. {// character in party
  356. chclif_char_delete2_ack(fd, char_id, 5, 0);
  357. return 1;
  358. }
  359. */
  360. // success
  361. delete_date = time(NULL)+(charserv_config.char_config.char_del_delay);
  362. if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", schema_config.char_db, (unsigned long)delete_date, char_id) )
  363. {
  364. Sql_ShowDebug(sql_handle);
  365. chclif_char_delete2_ack(fd, char_id, 3, 0);
  366. return 1;
  367. }
  368. chclif_char_delete2_ack(fd, char_id, 1, delete_date);
  369. }
  370. return 1;
  371. }
  372. // CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
  373. int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
  374. FIFOSD_CHECK(12)
  375. {
  376. char birthdate[8+1];
  377. int char_id, i, k;
  378. unsigned int base_level;
  379. char* data;
  380. time_t delete_date;
  381. char_id = RFIFOL(fd,2);
  382. ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
  383. // construct "YY-MM-DD"
  384. birthdate[0] = RFIFOB(fd,6);
  385. birthdate[1] = RFIFOB(fd,7);
  386. birthdate[2] = '-';
  387. birthdate[3] = RFIFOB(fd,8);
  388. birthdate[4] = RFIFOB(fd,9);
  389. birthdate[5] = '-';
  390. birthdate[6] = RFIFOB(fd,10);
  391. birthdate[7] = RFIFOB(fd,11);
  392. birthdate[8] = 0;
  393. RFIFOSKIP(fd,12);
  394. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  395. if( i == MAX_CHARS )
  396. {// character not found
  397. chclif_char_delete2_accept_ack(fd, char_id, 3);
  398. return 1;
  399. }
  400. if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
  401. {// data error
  402. Sql_ShowDebug(sql_handle);
  403. chclif_char_delete2_accept_ack(fd, char_id, 3);
  404. return 1;
  405. }
  406. Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
  407. Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10);
  408. if( !delete_date || delete_date>time(NULL) )
  409. {// not queued or delay not yet passed
  410. chclif_char_delete2_accept_ack(fd, char_id, 4);
  411. return 1;
  412. }
  413. if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century
  414. {// birth date is wrong
  415. chclif_char_delete2_accept_ack(fd, char_id, 5);
  416. return 1;
  417. }
  418. if( ( charserv_config.char_config.char_del_level > 0 && base_level >= (unsigned int)charserv_config.char_config.char_del_level )
  419. || ( charserv_config.char_config.char_del_level < 0 && base_level <= (unsigned int)(-charserv_config.char_config.char_del_level) ) )
  420. {// character level config restriction
  421. chclif_char_delete2_accept_ack(fd, char_id, 2);
  422. return 1;
  423. }
  424. // success
  425. if( char_delete_char_sql(char_id) < 0 ){
  426. chclif_char_delete2_accept_ack(fd, char_id, 3);
  427. return 1;
  428. }
  429. // refresh character list cache
  430. for(k = i; k < MAX_CHARS-1; k++){
  431. sd->found_char[k] = sd->found_char[k+1];
  432. }
  433. sd->found_char[MAX_CHARS-1] = -1;
  434. chclif_char_delete2_accept_ack(fd, char_id, 1);
  435. }
  436. return 1;
  437. }
  438. // CH: <082b>.W <char id>.L
  439. int chclif_parse_char_delete2_cancel(int fd, struct char_session_data* sd) {
  440. int char_id, i;
  441. FIFOSD_CHECK(6)
  442. char_id = RFIFOL(fd,2);
  443. RFIFOSKIP(fd,6);
  444. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  445. if( i == MAX_CHARS )
  446. {// character not found
  447. chclif_char_delete2_cancel_ack(fd, char_id, 2);
  448. return 1;
  449. }
  450. // there is no need to check, whether or not the character was
  451. // queued for deletion, as the client prints an error message by
  452. // itself, if it was not the case (@see char_delete2_cancel_ack)
  453. if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", schema_config.char_db, char_id) )
  454. {
  455. Sql_ShowDebug(sql_handle);
  456. chclif_char_delete2_cancel_ack(fd, char_id, 2);
  457. return 1;
  458. }
  459. chclif_char_delete2_cancel_ack(fd, char_id, 1);
  460. return 1;
  461. }
  462. /*
  463. * Register a new mapserver into that char-serv
  464. * charserv can handle a MAX_SERVERS mapservs
  465. */
  466. int chclif_parse_maplogin(int fd){
  467. int i;
  468. if (RFIFOREST(fd) < 60)
  469. return 0;
  470. else {
  471. char* l_user = (char*)RFIFOP(fd,2);
  472. char* l_pass = (char*)RFIFOP(fd,26);
  473. l_user[23] = '\0';
  474. l_pass[23] = '\0';
  475. ARR_FIND( 0, ARRAYLENGTH(map_server), i, map_server[i].fd <= 0 );
  476. if( runflag != CHARSERVER_ST_RUNNING ||
  477. i == ARRAYLENGTH(map_server) ||
  478. strcmp(l_user, charserv_config.userid) != 0 ||
  479. strcmp(l_pass, charserv_config.passwd) != 0 )
  480. {
  481. WFIFOHEAD(fd,3);
  482. WFIFOW(fd,0) = 0x2af9;
  483. WFIFOB(fd,2) = 3;
  484. WFIFOSET(fd,3);
  485. } else {
  486. WFIFOHEAD(fd,3);
  487. WFIFOW(fd,0) = 0x2af9;
  488. WFIFOB(fd,2) = 0;
  489. WFIFOSET(fd,3);
  490. map_server[i].fd = fd;
  491. map_server[i].ip = ntohl(RFIFOL(fd,54));
  492. map_server[i].port = ntohs(RFIFOW(fd,58));
  493. map_server[i].users = 0;
  494. memset(map_server[i].map, 0, sizeof(map_server[i].map));
  495. session[fd]->func_parse = chmapif_parse;
  496. session[fd]->flag.server = 1;
  497. realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  498. chmapif_init(fd);
  499. }
  500. RFIFOSKIP(fd,60);
  501. }
  502. return 0;
  503. }
  504. // 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  505. int chclif_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
  506. if( RFIFOREST(fd) < 17 ) // request to connect
  507. return 0;
  508. else {
  509. struct auth_node* node;
  510. DBMap *auth_db = char_get_authdb();
  511. int account_id = RFIFOL(fd,2);
  512. uint32 login_id1 = RFIFOL(fd,6);
  513. uint32 login_id2 = RFIFOL(fd,10);
  514. int sex = RFIFOB(fd,16);
  515. RFIFOSKIP(fd,17);
  516. ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  517. if (sd) {
  518. //Received again auth packet for already authentified account?? Discard it.
  519. //TODO: Perhaps log this as a hack attempt?
  520. //TODO: and perhaps send back a reply?
  521. ShowInfo("Already registered break\n");
  522. return 1;
  523. }
  524. CREATE(session[fd]->session_data, struct char_session_data, 1);
  525. sd = (struct char_session_data*)session[fd]->session_data;
  526. sd->account_id = account_id;
  527. sd->login_id1 = login_id1;
  528. sd->login_id2 = login_id2;
  529. sd->sex = sex;
  530. sd->auth = false; // not authed yet
  531. // send back account_id
  532. WFIFOHEAD(fd,4);
  533. WFIFOL(fd,0) = account_id;
  534. WFIFOSET(fd,4);
  535. if( runflag != CHARSERVER_ST_RUNNING )
  536. {
  537. WFIFOHEAD(fd,3);
  538. WFIFOW(fd,0) = 0x6c;
  539. WFIFOB(fd,2) = 0;// rejected from server
  540. WFIFOSET(fd,3);
  541. return 1;
  542. }
  543. // search authentification
  544. node = (struct auth_node*)idb_get(auth_db, account_id);
  545. if( node != NULL &&
  546. node->account_id == account_id &&
  547. node->login_id1 == login_id1 &&
  548. node->login_id2 == login_id2 /*&&
  549. node->ip == ipl*/ )
  550. {// authentication found (coming from map server)
  551. sd->version = node->version;
  552. idb_remove(auth_db, account_id);
  553. char_auth_ok(fd, sd);
  554. }
  555. else
  556. {// authentication not found (coming from login server)
  557. if (login_fd > 0) { // don't send request if no login-server
  558. WFIFOHEAD(login_fd,23);
  559. WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  560. WFIFOL(login_fd,2) = sd->account_id;
  561. WFIFOL(login_fd,6) = sd->login_id1;
  562. WFIFOL(login_fd,10) = sd->login_id2;
  563. WFIFOB(login_fd,14) = sd->sex;
  564. WFIFOL(login_fd,15) = htonl(ipl);
  565. WFIFOL(login_fd,19) = fd;
  566. WFIFOSET(login_fd,23);
  567. } else { // if no login-server, we must refuse connection
  568. WFIFOHEAD(fd,3);
  569. WFIFOW(fd,0) = 0x6c;
  570. WFIFOB(fd,2) = 0;
  571. WFIFOSET(fd,3);
  572. }
  573. }
  574. }
  575. return 1;
  576. }
  577. //struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
  578. int chclif_parse_req_charlist(int fd, struct char_session_data* sd){
  579. if( RFIFOREST(fd) < 2 )
  580. return 0;
  581. RFIFOSKIP(fd,2);
  582. chclif_mmo_send099d(fd,sd);
  583. return 1;
  584. }
  585. int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
  586. FIFOSD_CHECK(3);
  587. {
  588. struct mmo_charstatus char_dat;
  589. struct mmo_charstatus *cd;
  590. char* data;
  591. int char_id;
  592. uint32 subnet_map_ip;
  593. struct auth_node* node;
  594. int i, map_fd;
  595. DBMap *auth_db = char_get_authdb();
  596. DBMap *char_db_ = char_get_chardb();
  597. int slot = RFIFOB(fd,2);
  598. RFIFOSKIP(fd,3);
  599. if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", schema_config.char_db, sd->account_id, slot)
  600. || SQL_SUCCESS != Sql_NextRow(sql_handle)
  601. || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  602. { //Not found?? May be forged packet.
  603. Sql_ShowDebug(sql_handle);
  604. Sql_FreeResult(sql_handle);
  605. WFIFOHEAD(fd,3);
  606. WFIFOW(fd,0) = 0x6c;
  607. WFIFOB(fd,2) = 0; // rejected from server
  608. WFIFOSET(fd,3);
  609. return 1;
  610. }
  611. char_id = atoi(data);
  612. Sql_FreeResult(sql_handle);
  613. /* client doesn't let it get to this point if you're banned, so its a forged packet */
  614. if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(NULL) ) {
  615. WFIFOHEAD(fd,3);
  616. WFIFOW(fd,0) = 0x6c;
  617. WFIFOB(fd,2) = 0; // rejected from server
  618. WFIFOSET(fd,3);
  619. return 1;
  620. }
  621. /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  622. char_set_char_online(-2,char_id,sd->account_id);
  623. if( !char_mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  624. char_set_char_offline(char_id, sd->account_id);
  625. /* failed to load something. REJECT! */
  626. WFIFOHEAD(fd,3);
  627. WFIFOW(fd,0) = 0x6c;
  628. WFIFOB(fd,2) = 0;
  629. WFIFOSET(fd,3);
  630. return 1;/* jump off this boat */
  631. }
  632. //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  633. cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  634. cd->sex = sd->sex;
  635. if (charserv_config.log_char) {
  636. char esc_name[NAME_LENGTH*2+1];
  637. Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  638. if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  639. schema_config.charlog_db, sd->account_id, slot, esc_name) )
  640. Sql_ShowDebug(sql_handle);
  641. }
  642. ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  643. // searching map server
  644. i = char_search_mapserver(cd->last_point.map, -1, -1);
  645. // if map is not found, we check major cities
  646. if (i < 0 || !cd->last_point.map) {
  647. unsigned short j;
  648. //First check that there's actually a map server online.
  649. ARR_FIND( 0, ARRAYLENGTH(map_server), j, map_server[j].fd >= 0 && map_server[j].map[0] );
  650. if (j == ARRAYLENGTH(map_server)) {
  651. ShowInfo("Connection Closed. No map servers available.\n");
  652. chclif_send_auth_result(fd,1); // 01 = Server closed
  653. return 1;
  654. }
  655. if ((i = char_search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  656. cd->last_point.x = 273;
  657. cd->last_point.y = 354;
  658. } else if ((i = char_search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  659. cd->last_point.x = 120;
  660. cd->last_point.y = 100;
  661. } else if ((i = char_search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  662. cd->last_point.x = 160;
  663. cd->last_point.y = 94;
  664. } else if ((i = char_search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  665. cd->last_point.x = 116;
  666. cd->last_point.y = 57;
  667. } else if ((i = char_search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  668. cd->last_point.x = 87;
  669. cd->last_point.y = 117;
  670. } else if ((i = char_search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  671. cd->last_point.x = 94;
  672. cd->last_point.y = 103;
  673. } else {
  674. ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
  675. chclif_send_auth_result(fd,1); // 01 = Server closed
  676. return 1;
  677. }
  678. ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  679. cd->last_point.map = j;
  680. }
  681. //Send NEW auth packet [Kevin]
  682. //FIXME: is this case even possible? [ultramage]
  683. if ((map_fd = map_server[i].fd) < 1 || session[map_fd] == NULL)
  684. {
  685. ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  686. map_server[i].fd = -1;
  687. memset(&map_server[i], 0, sizeof(struct mmo_map_server));
  688. chclif_send_auth_result(fd,1); //Send server closed.
  689. return 1;
  690. }
  691. //Send player to map
  692. WFIFOHEAD(fd,28);
  693. WFIFOW(fd,0) = 0x71;
  694. WFIFOL(fd,2) = cd->char_id;
  695. mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  696. subnet_map_ip = char_lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  697. WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : map_server[i].ip);
  698. WFIFOW(fd,26) = ntows(htons(map_server[i].port)); // [!] LE byte order here [!]
  699. WFIFOSET(fd,28);
  700. // create temporary auth entry
  701. CREATE(node, struct auth_node, 1);
  702. node->account_id = sd->account_id;
  703. node->char_id = cd->char_id;
  704. node->login_id1 = sd->login_id1;
  705. node->login_id2 = sd->login_id2;
  706. node->sex = sd->sex;
  707. node->expiration_time = sd->expiration_time;
  708. node->group_id = sd->group_id;
  709. node->ip = ipl;
  710. idb_put(auth_db, sd->account_id, node);
  711. }
  712. return 1;
  713. }
  714. // S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  715. // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  716. int chclif_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
  717. int i=0, ch;
  718. if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
  719. else if (cmd == 0x67) FIFOSD_CHECK(37)
  720. else return 0;
  721. if( (charserv_config.char_new)==0 ) //turn character creation on/off [Kevin]
  722. i = -2;
  723. else {
  724. #if PACKETVER < 20120307
  725. i = char_make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
  726. RFIFOSKIP(fd,37);
  727. #else
  728. i = char_make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  729. RFIFOSKIP(fd,31);
  730. #endif
  731. }
  732. //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  733. if (i < 0) {
  734. WFIFOHEAD(fd,3);
  735. WFIFOW(fd,0) = 0x6e;
  736. /* Others I found [Ind] */
  737. /* 0x02 = Symbols in Character Names are forbidden */
  738. /* 0x03 = You are not elegible to open the Character Slot. */
  739. switch (i) {
  740. case -1: WFIFOB(fd,2) = 0x00; break;
  741. case -2: WFIFOB(fd,2) = 0xFF; break;
  742. case -3: WFIFOB(fd,2) = 0x01; break;
  743. case -4: WFIFOB(fd,2) = 0x03; break;
  744. }
  745. WFIFOSET(fd,3);
  746. } else {
  747. int len;
  748. // retrieve data
  749. struct mmo_charstatus char_dat;
  750. char_mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  751. // send to player
  752. WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  753. WFIFOW(fd,0) = 0x6d;
  754. len = 2 + char_mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  755. WFIFOSET(fd,len);
  756. // add new entry to the chars list
  757. ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  758. if( ch < MAX_CHARS )
  759. sd->found_char[ch] = i; // the char_id of the new char
  760. }
  761. return 1;
  762. }
  763. int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){
  764. if (cmd == 0x68) FIFOSD_CHECK(46)
  765. else if (cmd == 0x1fb) FIFOSD_CHECK(56)
  766. else return 0;
  767. {
  768. char email[40];
  769. int i, ch;
  770. int cid = RFIFOL(fd,2);
  771. ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  772. memcpy(email, RFIFOP(fd,6), 40);
  773. RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  774. // Check if e-mail is correct
  775. if(strcmpi(email, sd->email) && //email does not matches and
  776. (
  777. strcmp("a@a.com", sd->email) || //it is not default email, or
  778. (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default
  779. )) { //Fail
  780. WFIFOHEAD(fd,3);
  781. WFIFOW(fd,0) = 0x70;
  782. WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  783. WFIFOSET(fd,3);
  784. return 1;
  785. }
  786. // check if this char exists
  787. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  788. if( i == MAX_CHARS )
  789. { // Such a character does not exist in the account
  790. WFIFOHEAD(fd,3);
  791. WFIFOW(fd,0) = 0x70;
  792. WFIFOB(fd,2) = 0;
  793. WFIFOSET(fd,3);
  794. return 1;
  795. }
  796. // remove char from list and compact it
  797. for(ch = i; ch < MAX_CHARS-1; ch++)
  798. sd->found_char[ch] = sd->found_char[ch+1];
  799. sd->found_char[MAX_CHARS-1] = -1;
  800. /* Delete character */
  801. if(char_delete_char_sql(cid)<0){
  802. //can't delete the char
  803. //either SQL error or can't delete by some CONFIG conditions
  804. //del fail
  805. WFIFOHEAD(fd,3);
  806. WFIFOW(fd, 0) = 0x70;
  807. WFIFOB(fd, 2) = 0;
  808. WFIFOSET(fd, 3);
  809. return 1;
  810. }
  811. /* Char successfully deleted.*/
  812. WFIFOHEAD(fd,2);
  813. WFIFOW(fd,0) = 0x6f;
  814. WFIFOSET(fd,2);
  815. }
  816. return 1;
  817. }
  818. // R 0187 <account ID>.l
  819. int chclif_parse_keepalive(int fd){
  820. if (RFIFOREST(fd) < 6)
  821. return 0;
  822. //int aid = RFIFOL(fd,2);
  823. RFIFOSKIP(fd,6);
  824. return 1;
  825. }
  826. // R 08fc <char ID>.l <new name>.24B
  827. // R 028d <account ID>.l <char ID>.l <new name>.24B
  828. int chclif_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
  829. int i, cid=0;
  830. char name[NAME_LENGTH];
  831. char esc_name[NAME_LENGTH*2+1];
  832. if(cmd == 0x8fc){
  833. FIFOSD_CHECK(30)
  834. cid =RFIFOL(fd,2);
  835. safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
  836. RFIFOSKIP(fd,30);
  837. }
  838. else if(cmd == 0x28d) {
  839. int aid;
  840. FIFOSD_CHECK(34);
  841. aid = RFIFOL(fd,2);
  842. cid =RFIFOL(fd,6);
  843. safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  844. RFIFOSKIP(fd,34);
  845. if( aid != sd->account_id )
  846. return 1;
  847. }
  848. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  849. if( i == MAX_CHARS )
  850. return 1;
  851. normalize_name(name,TRIM_CHARS);
  852. Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  853. if( !char_check_char_name(name,esc_name) )
  854. {
  855. i = 1;
  856. safestrncpy(sd->new_name, name, NAME_LENGTH);
  857. }
  858. else
  859. i = 0;
  860. WFIFOHEAD(fd, 4);
  861. WFIFOW(fd,0) = 0x28e;
  862. WFIFOW(fd,2) = i;
  863. WFIFOSET(fd,4);
  864. return 1;
  865. }
  866. int charblock_timer(int tid, unsigned int tick, int id, intptr_t data)
  867. {
  868. struct char_session_data* sd=NULL;
  869. int i=0;
  870. ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == id);
  871. if(sd == NULL || sd->charblock_timer==INVALID_TIMER) //has disconected or was required to stop
  872. return 0;
  873. if (sd->charblock_timer != tid){
  874. sd->charblock_timer = INVALID_TIMER;
  875. return 0;
  876. }
  877. chclif_block_character(i,sd);
  878. return 0;
  879. }
  880. /*
  881. * 0x20d <PacketLength>.W <TAG_CHARACTER_BLOCK_INFO>24B (HC_BLOCK_CHARACTER)
  882. * <GID>L <szExpireDate>20B (TAG_CHARACTER_BLOCK_INFO)
  883. */
  884. void chclif_block_character( int fd, struct char_session_data* sd){
  885. int i=0, j=0, len=4;
  886. time_t now = time(NULL);
  887. WFIFOHEAD(fd, 4+MAX_CHARS*24);
  888. WFIFOW(fd, 0) = 0x20d;
  889. for(i=0; i<MAX_CHARS; i++){
  890. if(sd->found_char[i] == -1)
  891. continue;
  892. if(sd->unban_time[i]){
  893. if( sd->unban_time[i] > now ) {
  894. char szExpireDate[21];
  895. WFIFOL(fd, 4+j*24) = sd->found_char[i];
  896. timestamp2string(szExpireDate, 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S");
  897. memcpy(WFIFOP(fd,8+j*24),szExpireDate,20);
  898. }
  899. else {
  900. WFIFOL(fd, 4+j*24) = 0;
  901. sd->unban_time[i] = 0;
  902. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `unban_time`='0' WHERE `char_id`='%d' LIMIT 1", schema_config.char_db, sd->found_char[i]) )
  903. Sql_ShowDebug(sql_handle);
  904. }
  905. len+=24;
  906. j++; //pkt list idx
  907. }
  908. }
  909. WFIFOW(fd, 2) = len; //packet len
  910. WFIFOSET(fd,len);
  911. ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i] > now); //sd->charslot only have productible char
  912. if(i < MAX_CHARS ){
  913. sd->charblock_timer = add_timer(
  914. gettick() + 10000, // each 10s resend that list
  915. charblock_timer, sd->account_id, 0);
  916. }
  917. }
  918. // 0x28f <char_id>.L
  919. int chclif_parse_ackrename(int fd, struct char_session_data* sd){
  920. // 0: Successful
  921. // 1: This character's name has already been changed. You cannot change a character's name more than once.
  922. // 2: User information is not correct.
  923. // 3: You have failed to change this character's name.
  924. // 4: Another user is using this character name, so please select another one.
  925. FIFOSD_CHECK(6)
  926. {
  927. int i;
  928. int cid = RFIFOL(fd,2);
  929. RFIFOSKIP(fd,6);
  930. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  931. if( i == MAX_CHARS )
  932. return 1;
  933. i = char_rename_char_sql(sd, cid);
  934. WFIFOHEAD(fd, 4);
  935. WFIFOW(fd,0) = 0x290;
  936. WFIFOW(fd,2) = i;
  937. WFIFOSET(fd,4);
  938. }
  939. return 1;
  940. }
  941. int chclif_ack_captcha(int fd){
  942. WFIFOHEAD(fd,5);
  943. WFIFOW(fd,0) = 0x7e9;
  944. WFIFOW(fd,2) = 5;
  945. WFIFOB(fd,4) = 1;
  946. WFIFOSET(fd,5);
  947. return 1;
  948. }
  949. // R 07e5 <?>.w <aid>.l
  950. int chclif_parse_reqcaptcha(int fd){
  951. //FIFOSD_CHECK(8)
  952. RFIFOSKIP(fd,8);
  953. chclif_ack_captcha(fd);
  954. return 1;
  955. }
  956. // R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  957. int chclif_parse_chkcaptcha(int fd){
  958. //FIFOSD_CHECK(32)
  959. RFIFOSKIP(fd,32);
  960. chclif_ack_captcha(fd);
  961. return 1;
  962. }
  963. /**
  964. * Entry point from client to char-serv
  965. * function that check incoming command then split it to correct handler.
  966. * @param fd: file descriptor to parse, (link to client)
  967. */
  968. int chclif_parse(int fd) {
  969. unsigned short cmd;
  970. struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
  971. uint32 ipl = session[fd]->client_addr;
  972. // disconnect any player if no login-server.
  973. if(login_fd < 0)
  974. set_eof(fd);
  975. if(session[fd]->flag.eof)
  976. {
  977. if( sd != NULL && sd->auth )
  978. { // already authed client
  979. DBMap *online_char_db = char_get_onlinedb();
  980. struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  981. if( data != NULL && data->fd == fd)
  982. data->fd = -1;
  983. if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  984. char_set_char_offline(-1,sd->account_id);
  985. }
  986. do_close(fd);
  987. return 0;
  988. }
  989. while( RFIFOREST(fd) >= 2 )
  990. {
  991. int next=1;
  992. cmd = RFIFOW(fd,0);
  993. switch( cmd )
  994. {
  995. case 0x65: next=chclif_parse_reqtoconnect(fd,sd,ipl); break;
  996. // char select
  997. case 0x66: next=chclif_parse_charselect(fd,sd,ipl); break;
  998. // createnewchar
  999. case 0x970: next=chclif_parse_createnewchar(fd,sd,cmd); break;
  1000. case 0x67: next=chclif_parse_createnewchar(fd,sd,cmd); break;
  1001. // delete char
  1002. case 0x68: next=chclif_parse_delchar(fd,sd,cmd); break; //
  1003. case 0x1fb: next=chclif_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
  1004. // client keep-alive packet (every 12 seconds)
  1005. case 0x187: next=chclif_parse_keepalive(fd); break;
  1006. // char rename
  1007. case 0x8fc: next=chclif_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  1008. case 0x28d: next=chclif_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  1009. case 0x28f: next=chclif_parse_ackrename(fd,sd); break; //Confirm change name.
  1010. // captcha
  1011. case 0x7e5: next=chclif_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
  1012. case 0x7e7: next=chclif_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
  1013. // deletion timer request
  1014. case 0x827: next=chclif_parse_char_delete2_req(fd, sd); break;
  1015. // deletion accept request
  1016. case 0x829: next=chclif_parse_char_delete2_accept(fd, sd); break;
  1017. // deletion cancel request
  1018. case 0x82b: next=chclif_parse_char_delete2_cancel(fd, sd); break;
  1019. // login as map-server
  1020. case 0x2af8: chclif_parse_maplogin(fd); return 0; // avoid processing of followup packets here
  1021. //pincode
  1022. case 0x8b8: next=chclif_parse_pincode_check( fd, sd ); break; // checks the entered pin
  1023. case 0x8c5: next=chclif_parse_reqpincode_window(fd,sd); break; // request for PIN window
  1024. case 0x8be: next=chclif_parse_pincode_change( fd, sd ); break; // pincode change request
  1025. case 0x8ba: next=chclif_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
  1026. // character movement request
  1027. case 0x8d4: next=chclif_parse_moveCharSlot(fd,sd); break;
  1028. case 0x9a1: next=chclif_parse_req_charlist(fd,sd); break;
  1029. // unknown packet received
  1030. default:
  1031. ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL));
  1032. set_eof(fd);
  1033. return 0;
  1034. }
  1035. if(next==0) return 0; // avoid processing of followup packets (prev was probably incomplete)
  1036. }
  1037. RFIFOFLUSH(fd);
  1038. return 0;
  1039. }