char_clif.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "char_clif.hpp"
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <memory>
  7. #include <unordered_map>
  8. #include <vector>
  9. #include <common/malloc.hpp>
  10. #include <common/mapindex.hpp>
  11. #include <common/mmo.hpp>
  12. #include <common/random.hpp>
  13. #include <common/showmsg.hpp>
  14. #include <common/socket.hpp>
  15. #include <common/sql.hpp>
  16. #include <common/strlib.hpp>
  17. #include <common/timer.hpp>
  18. #include <common/utilities.hpp>
  19. #include <common/utils.hpp>
  20. #include "char.hpp"
  21. #include "char_logif.hpp"
  22. #include "char_mapif.hpp"
  23. #include "inter.hpp"
  24. #include "packets.hpp"
  25. using namespace rathena;
  26. std::vector<struct s_point_str> accessible_maps{
  27. s_point_str{ MAP_PRONTERA, 273, 354 },
  28. s_point_str{ MAP_GEFFEN, 120, 100 },
  29. s_point_str{ MAP_MORROC, 160, 94 },
  30. s_point_str{ MAP_ALBERTA, 116, 57 },
  31. s_point_str{ MAP_PAYON, 87, 117 },
  32. s_point_str{ MAP_IZLUDE, 94, 103 }
  33. };
  34. #if PACKETVER_SUPPORTS_PINCODE
  35. bool pincode_allowed( char* pincode );
  36. #endif
  37. //------------------------------------------------
  38. //Add On system
  39. //------------------------------------------------
  40. // reason
  41. // 0: success
  42. // 1: failed
  43. void chclif_moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  44. WFIFOHEAD(fd,8);
  45. WFIFOW(fd,0) = HEADER_HC_ACK_CHANGE_CHARACTER_SLOT;
  46. WFIFOW(fd,2) = 8;
  47. WFIFOW(fd,4) = reason;
  48. WFIFOW(fd,6) = sd->char_moves[index];
  49. WFIFOSET(fd,8);
  50. }
  51. /*
  52. * Client is requesting to move a charslot
  53. */
  54. int chclif_parse_moveCharSlot( int fd, struct char_session_data* sd){
  55. FIFOSD_CHECK(8);
  56. uint16 from, to;
  57. from = RFIFOW(fd,2);
  58. to = RFIFOW(fd,4);
  59. //Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
  60. RFIFOSKIP(fd,8);
  61. // Have we changed to often or is it disabled?
  62. if( (charserv_config.charmove_config.char_move_enabled)==0
  63. || ( (charserv_config.charmove_config.char_moves_unlimited)==0 && sd->char_moves[from] <= 0 ) ){
  64. chclif_moveCharSlotReply( fd, sd, from, 1 );
  65. return 1;
  66. }
  67. // We don't even have a character on the chosen slot?
  68. if( sd->found_char[from] <= 0 || to >= sd->char_slots ){
  69. chclif_moveCharSlotReply( fd, sd, from, 1 );
  70. return 1;
  71. }
  72. if( sd->found_char[to] > 0 ){
  73. // We want to move to a used position
  74. if( charserv_config.charmove_config.char_movetoused ){ // TODO: check if the target is in deletion process
  75. // Admin is friendly and uses triangle exchange
  76. if( SQL_ERROR == Sql_QueryStr(sql_handle, "START TRANSACTION")
  77. || 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] )
  78. || 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] )
  79. || SQL_ERROR == Sql_QueryStr(sql_handle, "COMMIT")
  80. ){
  81. chclif_moveCharSlotReply( fd, sd, from, 1 );
  82. Sql_ShowDebug(sql_handle);
  83. Sql_QueryStr(sql_handle,"ROLLBACK");
  84. return 1;
  85. }
  86. }else{
  87. // Admin doesn't allow us to
  88. chclif_moveCharSlotReply( fd, sd, from, 1 );
  89. return 1;
  90. }
  91. }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] ) ){
  92. Sql_ShowDebug(sql_handle);
  93. chclif_moveCharSlotReply( fd, sd, from, 1 );
  94. return 1;
  95. }
  96. if( (charserv_config.charmove_config.char_moves_unlimited)==0 ){
  97. sd->char_moves[from]--;
  98. 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] );
  99. }
  100. // We successfully moved the char - time to notify the client
  101. chclif_moveCharSlotReply( fd, sd, from, 0 );
  102. chclif_mmo_char_send(fd, sd);
  103. return 1;
  104. }
  105. #if PACKETVER_SUPPORTS_PINCODE
  106. /* pincode_sendstate transmist the pincode state to client
  107. * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
  108. * state :
  109. * 0 = disabled / pin is correct
  110. * 1 = ask for pin - client sends 0x8b8
  111. * 2 = create new pin - client sends 0x8ba
  112. * 3 = pin must be changed - client 0x8be
  113. * 4 = create new pin - client sends 0x8ba
  114. * 5 = client shows msgstr(1896)
  115. * 6 = client shows msgstr(1897) Unable to use your KSSN number
  116. * 7 = char select window shows a button - client sends 0x8c5
  117. * 8 = pincode was incorrect
  118. */
  119. void chclif_pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
  120. WFIFOHEAD(fd, 12);
  121. WFIFOW(fd, 0) = 0x8b9;
  122. WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  123. WFIFOL(fd, 6) = sd->account_id;
  124. WFIFOW(fd,10) = state;
  125. WFIFOSET(fd,12);
  126. }
  127. /*
  128. * Client just entering charserv from login, send him pincode confirmation
  129. */
  130. int chclif_parse_reqpincode_window(int fd, struct char_session_data* sd){
  131. FIFOSD_CHECK(6);
  132. if( charserv_config.pincode_config.pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  133. if( strlen( sd->pincode ) <= 0 ){
  134. chclif_pincode_sendstate( fd, sd, PINCODE_NEW );
  135. }else{
  136. chclif_pincode_sendstate( fd, sd, PINCODE_ASK );
  137. }
  138. }
  139. RFIFOSKIP(fd,6);
  140. return 1;
  141. }
  142. /*
  143. * Client as anwsered pincode questionning, checking if valid anwser
  144. */
  145. int chclif_parse_pincode_check( int fd, struct char_session_data* sd ){
  146. FIFOSD_CHECK(10);
  147. char pin[PINCODE_LENGTH+1];
  148. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id ) {
  149. set_eof(fd);
  150. return 1;
  151. }
  152. memset(pin,0,PINCODE_LENGTH+1);
  153. strncpy((char*)pin, RFIFOCP(fd, 6), PINCODE_LENGTH);
  154. RFIFOSKIP(fd,10);
  155. if (!char_pincode_decrypt(sd->pincode_seed, pin )) {
  156. set_eof(fd);
  157. return 1;
  158. }
  159. if( char_pincode_compare( fd, sd, pin ) ){
  160. sd->pincode_correct = true;
  161. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  162. }
  163. return 1;
  164. }
  165. /*
  166. * Helper function to check if a new pincode contains illegal characters or combinations
  167. */
  168. bool pincode_allowed( char* pincode ){
  169. int i;
  170. char c, n, compare[PINCODE_LENGTH+1];
  171. memset( compare, 0, PINCODE_LENGTH+1);
  172. // Sanity check for bots to prevent errors
  173. for( i = 0; i < PINCODE_LENGTH; i++ ){
  174. c = pincode[i];
  175. if( c < '0' || c > '9' ){
  176. return false;
  177. }
  178. }
  179. // Is it forbidden to use only the same character?
  180. if( !charserv_config.pincode_config.pincode_allow_repeated ){
  181. c = pincode[0];
  182. // Check if the first character equals the rest of the input
  183. for( i = 0; i < PINCODE_LENGTH; i++ ){
  184. compare[i] = c;
  185. }
  186. if( strncmp( pincode, compare, PINCODE_LENGTH + 1 ) == 0 ){
  187. return false;
  188. }
  189. }
  190. // Is it forbidden to use a sequential combination of numbers?
  191. if( !charserv_config.pincode_config.pincode_allow_sequential ){
  192. c = pincode[0];
  193. // Check if it is an ascending sequence
  194. for( i = 0; i < PINCODE_LENGTH; i++ ){
  195. n = c + i;
  196. if( n > '9' ){
  197. compare[i] = '0' + ( n - '9' ) - 1;
  198. }else{
  199. compare[i] = n;
  200. }
  201. }
  202. if( strncmp( pincode, compare, PINCODE_LENGTH + 1 ) == 0 ){
  203. return false;
  204. }
  205. // Check if it is an descending sequence
  206. for( i = 0; i < PINCODE_LENGTH; i++ ){
  207. n = c - i;
  208. if( n < '0' ){
  209. compare[i] = '9' - ( '0' - n ) + 1;
  210. }else{
  211. compare[i] = n;
  212. }
  213. }
  214. if( strncmp( pincode, compare, PINCODE_LENGTH + 1 ) == 0 ){
  215. return false;
  216. }
  217. }
  218. return true;
  219. }
  220. /*
  221. * Client request to change pincode
  222. */
  223. int chclif_parse_pincode_change( int fd, struct char_session_data* sd ){
  224. FIFOSD_CHECK(14);
  225. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id ) {
  226. set_eof(fd);
  227. return 1;
  228. }
  229. else {
  230. char oldpin[PINCODE_LENGTH+1];
  231. char newpin[PINCODE_LENGTH+1];
  232. memset(oldpin,0,PINCODE_LENGTH+1);
  233. memset(newpin,0,PINCODE_LENGTH+1);
  234. strncpy(oldpin, RFIFOCP(fd,6), PINCODE_LENGTH);
  235. strncpy(newpin, RFIFOCP(fd,10), PINCODE_LENGTH);
  236. RFIFOSKIP(fd,14);
  237. if (!char_pincode_decrypt(sd->pincode_seed,oldpin) || !char_pincode_decrypt(sd->pincode_seed,newpin)) {
  238. set_eof(fd);
  239. return 1;
  240. }
  241. if( !char_pincode_compare( fd, sd, oldpin ) )
  242. return 1;
  243. if( pincode_allowed(newpin) ){
  244. chlogif_pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  245. strncpy(sd->pincode, newpin, sizeof(newpin));
  246. ShowInfo("Pincode changed for AID: %d\n", sd->account_id);
  247. sd->pincode_correct = true;
  248. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  249. }else{
  250. chclif_pincode_sendstate( fd, sd, PINCODE_ILLEGAL );
  251. }
  252. }
  253. return 1;
  254. }
  255. /*
  256. * activate PIN system and set first PIN
  257. */
  258. int chclif_parse_pincode_setnew( int fd, struct char_session_data* sd ){
  259. FIFOSD_CHECK(10);
  260. if( charserv_config.pincode_config.pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id ) {
  261. set_eof(fd);
  262. return 1;
  263. } else if (strnlen(sd->pincode, PINCODE_LENGTH) > 0) {
  264. set_eof(fd);
  265. return 1;
  266. } else {
  267. char newpin[PINCODE_LENGTH+1];
  268. memset(newpin,0,PINCODE_LENGTH+1);
  269. strncpy( newpin, RFIFOCP(fd,6), PINCODE_LENGTH );
  270. RFIFOSKIP(fd,10);
  271. if (!char_pincode_decrypt( sd->pincode_seed, newpin )) {
  272. set_eof(fd);
  273. return 1;
  274. }
  275. if( pincode_allowed(newpin) ){
  276. chlogif_pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  277. strncpy( sd->pincode, newpin, sizeof( newpin ) );
  278. sd->pincode_correct = true;
  279. chclif_pincode_sendstate( fd, sd, PINCODE_PASSED );
  280. }else{
  281. chclif_pincode_sendstate( fd, sd, PINCODE_ILLEGAL );
  282. }
  283. }
  284. return 1;
  285. }
  286. #endif
  287. //----------------------------------------
  288. // Tell client how many pages, kRO sends 17 (Yommy)
  289. //----------------------------------------
  290. void chclif_charlist_notify( int fd, struct char_session_data* sd ){
  291. // This is needed on RE clients from october 2015 onwards
  292. #if defined(PACKETVER_RE) && PACKETVER >= 20151001 && PACKETVER < 20180103
  293. WFIFOHEAD(fd, 10);
  294. WFIFOW(fd, 0) = 0x9a0;
  295. // pages to req / send them all in 1 until mmo_chars_fromsql can split them up
  296. WFIFOL(fd, 2) = (sd->char_slots>3)?sd->char_slots/3:1; //int TotalCnt (nb page to load)
  297. WFIFOL(fd, 6) = sd->char_slots;
  298. WFIFOSET(fd,10);
  299. #else
  300. WFIFOHEAD(fd, 6);
  301. WFIFOW(fd, 0) = 0x9a0;
  302. // pages to req / send them all in 1 until mmo_chars_fromsql can split them up
  303. WFIFOL(fd, 2) = (sd->char_slots>3)?sd->char_slots/3:1; //int TotalCnt (nb page to load)
  304. WFIFOSET(fd,6);
  305. #endif
  306. }
  307. //----------------------------------------
  308. // Function to send characters to a player
  309. //----------------------------------------
  310. int chclif_mmo_send006b(int fd, struct char_session_data* sd){
  311. int j, offset;
  312. #if PACKETVER >= 20100413
  313. offset = 3;
  314. #else
  315. offset = 0;
  316. #endif
  317. if (charserv_config.save_log)
  318. ShowInfo("Loading Char Data (" CL_BOLD "%d" CL_RESET ")\n",sd->account_id);
  319. j = 24 + offset; // offset
  320. WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF);
  321. WFIFOW(fd,0) = 0x6b;
  322. #if PACKETVER >= 20100413
  323. WFIFOB(fd,4) = MAX_CHARS; // Max slots.
  324. WFIFOB(fd,5) = MIN_CHARS; // Available slots. (PremiumStartSlot)
  325. WFIFOB(fd,6) = MIN_CHARS+sd->chars_vip; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red)
  326. #endif
  327. memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes
  328. j+=char_mmo_chars_fromsql(sd, WFIFOP(fd,j));
  329. WFIFOW(fd,2) = j; // packet len
  330. WFIFOSET(fd,j);
  331. return 0;
  332. }
  333. //----------------------------------------
  334. // Notify client about charselect window data [Ind]
  335. //----------------------------------------
  336. void chclif_mmo_send082d(int fd, struct char_session_data* sd) {
  337. if (charserv_config.save_log)
  338. ShowInfo("Loading Char Data (" CL_BOLD "%d" CL_RESET ")\n",sd->account_id);
  339. WFIFOHEAD(fd,29);
  340. WFIFOW(fd,0) = 0x82d;
  341. WFIFOW(fd,2) = 29;
  342. WFIFOB(fd,4) = MIN_CHARS; // normal_slot
  343. WFIFOB(fd,5) = sd->chars_vip; // premium_slot
  344. WFIFOB(fd,6) = sd->chars_billing; // billing_slot
  345. WFIFOB(fd,7) = sd->char_slots; // producible_slot
  346. WFIFOB(fd,8) = MAX_CHARS; // valid_slot
  347. memset(WFIFOP(fd,9), 0, 20); // unused bytes
  348. WFIFOSET(fd,29);
  349. }
  350. void chclif_mmo_send099d(int fd, struct char_session_data *sd) {
  351. uint8 count = 0;
  352. WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF));
  353. WFIFOW(fd,0) = HEADER_HC_ACK_CHARINFO_PER_PAGE;
  354. WFIFOW(fd,2) = char_mmo_chars_fromsql(sd, WFIFOP(fd,4), &count) + 4;
  355. WFIFOSET(fd,WFIFOW(fd,2));
  356. // This is something special Gravity came up with.
  357. // The client triggers some finalization code only if count is != 3.
  358. if( count == 3 ){
  359. WFIFOHEAD(fd,4);
  360. WFIFOW(fd,0) = HEADER_HC_ACK_CHARINFO_PER_PAGE;
  361. WFIFOW(fd,2) = 4;
  362. WFIFOSET(fd,4);
  363. }
  364. }
  365. /*
  366. * Function to choose wich kind of charlist to send to client depending on his version
  367. */
  368. void chclif_mmo_char_send(int fd, struct char_session_data* sd){
  369. #if PACKETVER >= 20130000
  370. chclif_mmo_send082d(fd, sd);
  371. chclif_mmo_send006b(fd, sd);
  372. chclif_charlist_notify(fd, sd);
  373. #else
  374. chclif_mmo_send006b(fd,sd);
  375. //@FIXME dump from kro doesn't show 6b transmission
  376. #endif
  377. #if PACKETVER >= 20060819
  378. chclif_block_character(fd,sd);
  379. #endif
  380. }
  381. /*
  382. * Transmit auth result to client
  383. * <result>.B ()
  384. * result :
  385. * 1 : Server closed
  386. * 2 : Someone has already logged in with this id
  387. * 8 : already online
  388. */
  389. void chclif_send_auth_result(int fd,char result){
  390. WFIFOHEAD(fd,3);
  391. WFIFOW(fd,0) = 0x81;
  392. WFIFOB(fd,2) = result;
  393. WFIFOSET(fd,3);
  394. }
  395. /// @param result
  396. /// 0 (0x718): An unknown error has occurred.
  397. /// 1: none/success
  398. /// 3 (0x719): A database error occurred.
  399. /// 4 (0x71a): To delete a character you must withdraw from the guild.
  400. /// 5 (0x71b): To delete a character you must withdraw from the party.
  401. /// Any (0x718): An unknown error has occurred.
  402. /// HC: <0828>.W <char id>.L <Msg:0-5>.L <deleteDate>.L
  403. void chclif_char_delete2_ack(int fd, uint32 char_id, uint32 result, time_t delete_date) {
  404. WFIFOHEAD(fd,14);
  405. WFIFOW(fd,0) = 0x828;
  406. WFIFOL(fd,2) = char_id;
  407. WFIFOL(fd,6) = result;
  408. #if PACKETVER_CHAR_DELETEDATE
  409. WFIFOL(fd,10) = TOL(delete_date-time(nullptr));
  410. #else
  411. WFIFOL(fd,10) = TOL(delete_date);
  412. #endif
  413. WFIFOSET(fd,14);
  414. }
  415. /// @param result
  416. /// 0 (0x718): An unknown error has occurred.
  417. /// 1: none/success
  418. /// 2 (0x71c): Due to system settings can not be deleted.
  419. /// 3 (0x719): A database error occurred.
  420. /// 4 (0x71d): Deleting not yet possible time.
  421. /// 5 (0x71e): Date of birth do not match.
  422. /// 6 Name does not match.
  423. /// 7 Character Deletion has failed because you have entered an incorrect e-mail address.
  424. /// Any (0x718): An unknown error has occurred.
  425. /// HC: <082a>.W <char id>.L <Msg>.L
  426. void chclif_char_delete2_accept_ack(int fd, uint32 char_id, uint32 result) {
  427. #if PACKETVER >= 20130000
  428. if(result == 1 ){
  429. chclif_mmo_char_send(fd, (char_session_data*)session[fd]->session_data);
  430. }
  431. #endif
  432. WFIFOHEAD(fd,10);
  433. WFIFOW(fd,0) = 0x82a;
  434. WFIFOL(fd,2) = char_id;
  435. WFIFOL(fd,6) = result;
  436. WFIFOSET(fd,10);
  437. }
  438. /// @param result
  439. /// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
  440. /// 2 (0x719): A database error occurred.
  441. /// Any (0x718): An unknown error has occurred.
  442. /// HC: <082c>.W <char id>.L <Msg:1-2>.L
  443. void chclif_char_delete2_cancel_ack(int fd, uint32 char_id, uint32 result) {
  444. WFIFOHEAD(fd,10);
  445. WFIFOW(fd,0) = 0x82c;
  446. WFIFOL(fd,2) = char_id;
  447. WFIFOL(fd,6) = result;
  448. WFIFOSET(fd,10);
  449. }
  450. // CH: <0827>.W <char id>.L
  451. int chclif_parse_char_delete2_req(int fd, struct char_session_data* sd) {
  452. FIFOSD_CHECK(6)
  453. {
  454. uint32 char_id, i, guild_id, party_id;
  455. char* data;
  456. time_t delete_date;
  457. char_id = RFIFOL(fd,2);
  458. RFIFOSKIP(fd,6);
  459. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  460. if( i == MAX_CHARS )
  461. {// character not found
  462. chclif_char_delete2_ack(fd, char_id, 3, 0);
  463. return 1;
  464. }
  465. if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date`,`party_id`,`guild_id` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
  466. {
  467. Sql_ShowDebug(sql_handle);
  468. chclif_char_delete2_ack(fd, char_id, 3, 0);
  469. return 1;
  470. }
  471. Sql_GetData(sql_handle, 0, &data, nullptr); delete_date = strtoul(data, nullptr, 10);
  472. Sql_GetData(sql_handle, 1, &data, nullptr); party_id = strtoul(data, nullptr, 10);
  473. Sql_GetData(sql_handle, 2, &data, nullptr); guild_id = strtoul(data, nullptr, 10);
  474. if( delete_date ) {// character already queued for deletion
  475. chclif_char_delete2_ack(fd, char_id, 0, 0);
  476. return 1;
  477. }
  478. if (charserv_config.char_config.char_del_restriction&CHAR_DEL_RESTRICT_GUILD && guild_id) // character is in guild
  479. {
  480. chclif_char_delete2_ack(fd, char_id, 4, 0);
  481. return 1;
  482. }
  483. if (charserv_config.char_config.char_del_restriction&CHAR_DEL_RESTRICT_PARTY && party_id) // character is in party
  484. {
  485. chclif_char_delete2_ack(fd, char_id, 5, 0);
  486. return 1;
  487. }
  488. // success
  489. delete_date = time(nullptr)+(charserv_config.char_config.char_del_delay);
  490. 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) )
  491. {
  492. Sql_ShowDebug(sql_handle);
  493. chclif_char_delete2_ack(fd, char_id, 3, 0);
  494. return 1;
  495. }
  496. chclif_char_delete2_ack(fd, char_id, 1, delete_date);
  497. }
  498. return 1;
  499. }
  500. /**
  501. * Check char deletion code
  502. * @param sd
  503. * @param delcode E-mail or birthdate
  504. * @param flag Delete flag
  505. * @return true:Success, false:Failure
  506. **/
  507. bool chclif_delchar_check(struct char_session_data *sd, char *delcode, uint8 flag) {
  508. // E-Mail check
  509. if (flag&CHAR_DEL_EMAIL && (
  510. !stricmp(delcode, sd->email) || //email does not match or
  511. (
  512. !stricmp("a@a.com", sd->email) && //it is default email and
  513. !strcmp("", delcode) //user sent an empty email
  514. ))) {
  515. ShowInfo("" CL_RED "Char Deleted" CL_RESET " " CL_GREEN "(E-Mail)" CL_RESET ".\n");
  516. return true;
  517. }
  518. // Birthdate (YYMMDD)
  519. if (flag&CHAR_DEL_BIRTHDATE && (
  520. !strcmp(sd->birthdate+2, delcode) || // +2 to cut off the century
  521. (
  522. !strcmp("",sd->birthdate) && // it is default birthdate and
  523. !strcmp("",delcode) // user sent an empty birthdate
  524. ))) {
  525. ShowInfo("" CL_RED "Char Deleted" CL_RESET " " CL_GREEN "(Birthdate)" CL_RESET ".\n");
  526. return true;
  527. }
  528. return false;
  529. }
  530. // CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
  531. int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
  532. FIFOSD_CHECK(12)
  533. {
  534. char birthdate[8+1];
  535. uint32 char_id;
  536. char_id = RFIFOL(fd,2);
  537. ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%d (%d)" CL_RESET "\n", sd->account_id, char_id);
  538. // construct "YY-MM-DD"
  539. birthdate[0] = RFIFOB(fd,6);
  540. birthdate[1] = RFIFOB(fd,7);
  541. birthdate[2] = '-';
  542. birthdate[3] = RFIFOB(fd,8);
  543. birthdate[4] = RFIFOB(fd,9);
  544. birthdate[5] = '-';
  545. birthdate[6] = RFIFOB(fd,10);
  546. birthdate[7] = RFIFOB(fd,11);
  547. birthdate[8] = 0;
  548. RFIFOSKIP(fd,12);
  549. // Only check for birthdate
  550. if (!chclif_delchar_check(sd, birthdate, CHAR_DEL_BIRTHDATE)) {
  551. chclif_char_delete2_accept_ack(fd, char_id, 5);
  552. return 1;
  553. }
  554. switch( char_delete(sd,char_id) ){
  555. // success
  556. case CHAR_DELETE_OK:
  557. chclif_char_delete2_accept_ack(fd, char_id, 1);
  558. break;
  559. // data error
  560. case CHAR_DELETE_DATABASE:
  561. // character not found
  562. case CHAR_DELETE_NOTFOUND:
  563. chclif_char_delete2_accept_ack(fd, char_id, 3);
  564. break;
  565. // in a party
  566. case CHAR_DELETE_PARTY:
  567. // in a guild
  568. case CHAR_DELETE_GUILD:
  569. // character level config restriction
  570. case CHAR_DELETE_BASELEVEL:
  571. chclif_char_delete2_accept_ack(fd, char_id, 2);
  572. break;
  573. // not queued or delay not yet passed
  574. case CHAR_DELETE_TIME:
  575. chclif_char_delete2_accept_ack(fd, char_id, 4);
  576. break;
  577. }
  578. }
  579. return 1;
  580. }
  581. // CH: <082b>.W <char id>.L
  582. int chclif_parse_char_delete2_cancel(int fd, struct char_session_data* sd) {
  583. FIFOSD_CHECK(6);
  584. uint32 char_id, i;
  585. char_id = RFIFOL(fd,2);
  586. RFIFOSKIP(fd,6);
  587. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  588. if( i == MAX_CHARS )
  589. {// character not found
  590. chclif_char_delete2_cancel_ack(fd, char_id, 2);
  591. return 1;
  592. }
  593. // there is no need to check, whether or not the character was
  594. // queued for deletion, as the client prints an error message by
  595. // itself, if it was not the case (@see char_delete2_cancel_ack)
  596. if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", schema_config.char_db, char_id) )
  597. {
  598. Sql_ShowDebug(sql_handle);
  599. chclif_char_delete2_cancel_ack(fd, char_id, 2);
  600. return 1;
  601. }
  602. chclif_char_delete2_cancel_ack(fd, char_id, 1);
  603. return 1;
  604. }
  605. /*
  606. * Register a new mapserver into that char-serv
  607. * charserv can handle a MAX_SERVERS mapservs
  608. */
  609. int chclif_parse_maplogin(int fd){
  610. if (RFIFOREST(fd) < 60)
  611. return 0;
  612. else {
  613. int i;
  614. char* l_user = RFIFOCP(fd,2);
  615. char* l_pass = RFIFOCP(fd,26);
  616. l_user[23] = '\0';
  617. l_pass[23] = '\0';
  618. ARR_FIND( 0, ARRAYLENGTH(map_server), i, map_server[i].fd <= 0 );
  619. if( !global_core->is_running() ||
  620. i == ARRAYLENGTH(map_server) ||
  621. strcmp(l_user, charserv_config.userid) != 0 ||
  622. strcmp(l_pass, charserv_config.passwd) != 0 )
  623. {
  624. chmapif_connectack(fd, 3); //fail
  625. } else {
  626. chmapif_connectack(fd, 0); //success
  627. map_server[i].fd = fd;
  628. map_server[i].ip = ntohl(RFIFOL(fd,54));
  629. map_server[i].port = ntohs(RFIFOW(fd,58));
  630. map_server[i].users = 0;
  631. map_server[i].maps = {};
  632. session[fd]->func_parse = chmapif_parse;
  633. session[fd]->flag.server = 1;
  634. realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  635. chmapif_init(fd);
  636. }
  637. RFIFOSKIP(fd,60);
  638. }
  639. return 0;
  640. }
  641. // 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  642. int chclif_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
  643. if( RFIFOREST(fd) < 17 ) // request to connect
  644. return 0;
  645. else {
  646. uint32 account_id = RFIFOL(fd,2);
  647. uint32 login_id1 = RFIFOL(fd,6);
  648. uint32 login_id2 = RFIFOL(fd,10);
  649. int sex = RFIFOB(fd,16);
  650. RFIFOSKIP(fd,17);
  651. ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  652. if (sd) {
  653. //Received again auth packet for already authentified account?? Discard it.
  654. //TODO: Perhaps log this as a hack attempt?
  655. //TODO: and perhaps send back a reply?
  656. ShowInfo("Already registered break\n");
  657. return 1;
  658. }
  659. CREATE(session[fd]->session_data, struct char_session_data, 1);
  660. sd = (struct char_session_data*)session[fd]->session_data;
  661. sd->account_id = account_id;
  662. sd->login_id1 = login_id1;
  663. sd->login_id2 = login_id2;
  664. sd->sex = sex;
  665. sd->auth = false; // not authed yet
  666. sd->pincode_correct = false; // not entered pincode correctly yet
  667. // send back account_id
  668. WFIFOHEAD(fd,4);
  669. WFIFOL(fd,0) = account_id;
  670. WFIFOSET(fd,4);
  671. if( !global_core->is_running() ){
  672. chclif_reject(fd, 0); // rejected from server
  673. return 1;
  674. }
  675. // search authentification
  676. std::shared_ptr<struct auth_node> node = util::umap_find( char_get_authdb(), account_id);
  677. if( node != nullptr &&
  678. node->account_id == account_id &&
  679. node->login_id1 == login_id1 &&
  680. node->login_id2 == login_id2 /*&&
  681. node->ip == ipl*/ )
  682. {// authentication found (coming from map server)
  683. char_get_authdb().erase(account_id);
  684. char_auth_ok(fd, sd);
  685. sd->pincode_correct = true; // already entered pincode correctly yet
  686. }
  687. else
  688. {// authentication not found (coming from login server)
  689. if (session_isValid(login_fd)) { // don't send request if no login-server
  690. WFIFOHEAD(login_fd,23);
  691. WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  692. WFIFOL(login_fd,2) = sd->account_id;
  693. WFIFOL(login_fd,6) = sd->login_id1;
  694. WFIFOL(login_fd,10) = sd->login_id2;
  695. WFIFOB(login_fd,14) = sd->sex;
  696. WFIFOL(login_fd,15) = htonl(ipl);
  697. WFIFOL(login_fd,19) = fd;
  698. WFIFOSET(login_fd,23);
  699. } else { // if no login-server, we must refuse connection
  700. chclif_reject(fd, 0); // rejected from server
  701. }
  702. }
  703. }
  704. return 1;
  705. }
  706. //struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
  707. int chclif_parse_req_charlist(int fd, struct char_session_data* sd){
  708. FIFOSD_CHECK(2);
  709. RFIFOSKIP(fd,2);
  710. chclif_mmo_send099d(fd,sd);
  711. return 1;
  712. }
  713. //Send player to map
  714. void chclif_send_map_data( int fd, std::shared_ptr<struct mmo_charstatus> cd, uint32 ipl, int map_server_index ){
  715. #if PACKETVER >= 20170315
  716. int cmd = 0xAC5;
  717. int size = 156;
  718. #else
  719. int cmd = 0x71;
  720. int size = 28;
  721. #endif
  722. WFIFOHEAD(fd,size);
  723. WFIFOW(fd,0) = cmd;
  724. WFIFOL(fd,2) = cd->char_id;
  725. mapindex_getmapname_ext( cd->last_point.map, WFIFOCP( fd, 6 ) );
  726. uint32 subnet_map_ip = char_lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  727. WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : map_server[map_server_index].ip);
  728. WFIFOW(fd,26) = ntows(htons(map_server[map_server_index].port)); // [!] LE byte order here [!]
  729. #if PACKETVER >= 20170315
  730. memset(WFIFOP(fd, 28), 0, 128); // Unknown
  731. #endif
  732. #ifdef DEBUG
  733. ShowDebug("Sending the client (%d %d.%d.%d.%d) to map-server with ip %d.%d.%d.%d and port %hu\n",
  734. cd->account_id, CONVIP(ipl), CONVIP((subnet_map_ip) ? subnet_map_ip : map_server[map_server_index].ip),
  735. map_server[map_server_index].port);
  736. #endif
  737. WFIFOSET(fd,size);
  738. }
  739. int chclif_parse_select_accessible_map( int fd, struct char_session_data* sd, uint32 ipl ){
  740. #if PACKETVER >= 20100714
  741. struct PACKET_CH_SELECT_ACCESSIBLE_MAPNAME p;
  742. FIFOSD_CHECK( sizeof( p ) );
  743. memcpy( &p, RFIFOP( fd, 0 ), sizeof( p ) );
  744. RFIFOSKIP( fd, sizeof( p ) );
  745. char* data;
  746. // Check if the character exists and is not scheduled for deletion
  747. if( SQL_SUCCESS != Sql_Query( sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d' AND `delete_date` = 0", schema_config.char_db, sd->account_id, p.slot )
  748. || SQL_SUCCESS != Sql_NextRow( sql_handle )
  749. || SQL_SUCCESS != Sql_GetData( sql_handle, 0, &data, nullptr ) ){
  750. // Not found?? May be forged packet.
  751. Sql_ShowDebug( sql_handle );
  752. Sql_FreeResult( sql_handle );
  753. chclif_reject( fd, 0 ); // rejected from server
  754. return 1;
  755. }
  756. uint32 char_id = atoi( data );
  757. Sql_FreeResult( sql_handle );
  758. // Prevent select a char while retrieving guild bound items
  759. if( sd->flag&1 ){
  760. chclif_reject( fd, 0 ); // rejected from server
  761. return 1;
  762. }
  763. /* client doesn't let it get to this point if you're banned, so its a forged packet */
  764. if( sd->found_char[p.slot] == char_id && sd->unban_time[p.slot] > time(nullptr) ) {
  765. chclif_reject( fd, 0 ); // rejected from server
  766. return 1;
  767. }
  768. /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  769. char_set_char_online( -2, char_id, sd->account_id );
  770. struct mmo_charstatus char_dat;
  771. if( !char_mmo_char_fromsql( char_id, &char_dat, true ) ) {
  772. /* failed? set it back offline */
  773. char_set_char_offline( char_id, sd->account_id );
  774. /* failed to load something. REJECT! */
  775. chclif_reject( fd, 0 ); /* jump off this boat */
  776. return 1;
  777. }
  778. // Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  779. std::shared_ptr<struct mmo_charstatus> cd = util::umap_find( char_get_chardb(), char_id );
  780. if( charserv_config.log_char ){
  781. char esc_name[NAME_LENGTH*2+1];
  782. Sql_EscapeStringLen( sql_handle, esc_name, char_dat.name, strnlen( char_dat.name, NAME_LENGTH ) );
  783. if( SQL_ERROR == Sql_Query( sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", schema_config.charlog_db, sd->account_id, p.slot, esc_name ) ){
  784. Sql_ShowDebug( sql_handle );
  785. }
  786. }
  787. ShowInfo( "Selected char: (Account %d: %d - %s)\n", sd->account_id, p.slot, char_dat.name );
  788. // Check if there is really no mapserver for the last point where the player was
  789. int32 mapserver = char_search_mapserver( cd->last_point.map, -1, -1 );
  790. // It was not an unavailable map
  791. if( mapserver >= 0 ){
  792. chclif_reject( fd, 0 ); // rejected from server
  793. return 1;
  794. }
  795. if( static_cast<size_t>( p.mapnumber ) >= accessible_maps.size() ){
  796. chclif_reject( fd, 0 ); // rejected from server
  797. return 1;
  798. }
  799. s_point_str& accessible_map = accessible_maps[p.mapnumber];
  800. safestrncpy( cd->last_point.map, accessible_map.map, sizeof( cd->last_point.map ) );
  801. cd->last_point.x = accessible_map.x;
  802. cd->last_point.y = accessible_map.y;
  803. mapserver = char_search_mapserver( cd->last_point.map, -1, -1 );
  804. // No mapserver found for our accessible map
  805. if( mapserver < 0 ){
  806. chclif_reject( fd, 0 ); // rejected from server
  807. return 1;
  808. }
  809. int map_fd;
  810. // Send NEW auth packet [Kevin]
  811. // FIXME: is this case even possible? [ultramage]
  812. if( ( map_fd = map_server[mapserver].fd ) < 1 || session[map_fd] == nullptr ){
  813. ShowError( "parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, mapserver );
  814. map_server[mapserver] = {};
  815. map_server[mapserver].fd = -1;
  816. chclif_send_auth_result( fd, 1 ); // Send server closed.
  817. return 1;
  818. }
  819. chclif_send_map_data( fd, cd, ipl, mapserver );
  820. // create temporary auth entry
  821. std::shared_ptr<struct auth_node> node = std::make_shared<struct auth_node>();
  822. node->account_id = sd->account_id;
  823. node->char_id = cd->char_id;
  824. node->login_id1 = sd->login_id1;
  825. node->login_id2 = sd->login_id2;
  826. node->sex = sd->sex;
  827. node->expiration_time = sd->expiration_time;
  828. node->group_id = sd->group_id;
  829. node->ip = ipl;
  830. char_get_authdb()[node->account_id] = node;
  831. return 1;
  832. #else
  833. return 0;
  834. #endif
  835. }
  836. void chclif_accessible_maps( int fd ){
  837. #if PACKETVER >= 20100714
  838. PACKET_HC_NOTIFY_ACCESSIBLE_MAPNAME* p = reinterpret_cast<PACKET_HC_NOTIFY_ACCESSIBLE_MAPNAME*>( packet_buffer );
  839. p->packetType = HEADER_HC_NOTIFY_ACCESSIBLE_MAPNAME;
  840. p->packetLength = sizeof( *p );
  841. int count = 0;
  842. for( s_point_str& accessible_map : accessible_maps ){
  843. int32 mapserver = char_search_mapserver( accessible_map.map, -1, -1 );
  844. if( mapserver < 0 ){
  845. p->maps[count].status = 1;
  846. }else{
  847. p->maps[count].status = 0;
  848. }
  849. mapindex_getmapname_ext( accessible_map.map, p->maps[count].map );
  850. p->packetLength += sizeof( p->maps[0] );
  851. count++;
  852. }
  853. WFIFOHEAD( fd, p->packetLength );
  854. memcpy( WFIFOP( fd, 0 ), p, p->packetLength );
  855. WFIFOSET( fd, p->packetLength );
  856. #else
  857. chclif_send_auth_result( fd, 1 ); // 01 = Server closed
  858. #endif
  859. }
  860. int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
  861. FIFOSD_CHECK(3)
  862. {
  863. struct mmo_charstatus char_dat;
  864. char* data;
  865. uint32 char_id;
  866. int i, map_fd, server_id;
  867. int slot = RFIFOB(fd,2);
  868. RFIFOSKIP(fd,3);
  869. ARR_FIND( 0, ARRAYLENGTH(map_server), server_id, session_isValid(map_server[server_id].fd) && !map_server[server_id].maps.empty() );
  870. // Map-server not available, tell the client to wait (client wont close, char select will respawn)
  871. if (server_id == ARRAYLENGTH(map_server)) {
  872. chclif_accessible_maps( fd );
  873. return 1;
  874. }
  875. // Check if the character exists and is not scheduled for deletion
  876. if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d' AND `delete_date` = 0", schema_config.char_db, sd->account_id, slot)
  877. || SQL_SUCCESS != Sql_NextRow(sql_handle)
  878. || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, nullptr) )
  879. { //Not found?? May be forged packet.
  880. Sql_ShowDebug(sql_handle);
  881. Sql_FreeResult(sql_handle);
  882. chclif_reject(fd, 0); // rejected from server
  883. return 1;
  884. }
  885. char_id = atoi(data);
  886. Sql_FreeResult(sql_handle);
  887. // Prevent select a char while retrieving guild bound items
  888. if (sd->flag&1) {
  889. chclif_reject(fd, 0); // rejected from server
  890. return 1;
  891. }
  892. /* client doesn't let it get to this point if you're banned, so its a forged packet */
  893. if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(nullptr) ) {
  894. chclif_reject(fd, 0); // rejected from server
  895. return 1;
  896. }
  897. /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  898. char_set_char_online(-2,char_id,sd->account_id);
  899. if( !char_mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  900. char_set_char_offline(char_id, sd->account_id);
  901. /* failed to load something. REJECT! */
  902. chclif_reject(fd, 0); /* jump off this boat */
  903. return 1;
  904. }
  905. //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  906. std::shared_ptr<struct mmo_charstatus> cd = util::umap_find( char_get_chardb(), char_id );
  907. if (charserv_config.log_char) {
  908. char esc_name[NAME_LENGTH*2+1];
  909. Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  910. if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  911. schema_config.charlog_db, sd->account_id, slot, esc_name) )
  912. Sql_ShowDebug(sql_handle);
  913. }
  914. ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  915. // searching map server
  916. i = char_search_mapserver( cd->last_point.map, -1, -1 );
  917. // if map is not found, we check major cities
  918. if( i < 0 ){
  919. #if PACKETVER >= 20100714
  920. // Let the user select a map
  921. chclif_accessible_maps( fd );
  922. return 0;
  923. #else
  924. // Try to select a map for the user
  925. unsigned short j;
  926. //First check that there's actually a map server online.
  927. ARR_FIND( 0, ARRAYLENGTH(map_server), j, session_isValid(map_server[j].fd) && !map_server[j].maps.empty() );
  928. if (j == ARRAYLENGTH(map_server)) {
  929. ShowInfo("Connection Closed. No map servers available.\n");
  930. chclif_send_auth_result(fd,1); // 01 = Server closed
  931. return 1;
  932. }
  933. for( struct s_point_str& accessible_map : accessible_maps ){
  934. i = char_search_mapserver( accessible_map.map, -1, -1 );
  935. // Found a map-server for a map
  936. if( i >= 0 ){
  937. ShowWarning( "Unable to find map-server for '%s', sending to major city '%s'.\n", cd->last_point.map, accessible_map.map );
  938. memcpy( &cd->last_point, &accessible_map, sizeof( cd->last_point ) );
  939. break;
  940. }
  941. }
  942. if( i < 0 ){
  943. ShowInfo( "Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", cd->last_point.map );
  944. chclif_send_auth_result(fd,1); // 01 = Server closed
  945. return 1;
  946. }
  947. #endif
  948. }
  949. //Send NEW auth packet [Kevin]
  950. //FIXME: is this case even possible? [ultramage]
  951. if ((map_fd = map_server[i].fd) < 1 || session[map_fd] == nullptr)
  952. {
  953. ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  954. map_server[i] = {};
  955. map_server[i].fd = -1;
  956. chclif_send_auth_result(fd,1); //Send server closed.
  957. return 1;
  958. }
  959. chclif_send_map_data( fd, cd, ipl, i );
  960. // create temporary auth entry
  961. std::shared_ptr<struct auth_node> node = std::make_shared<struct auth_node>();
  962. node->account_id = sd->account_id;
  963. node->char_id = cd->char_id;
  964. node->login_id1 = sd->login_id1;
  965. node->login_id2 = sd->login_id2;
  966. node->sex = sd->sex;
  967. node->expiration_time = sd->expiration_time;
  968. node->group_id = sd->group_id;
  969. node->ip = ipl;
  970. char_get_authdb()[node->account_id] = node;
  971. }
  972. return 1;
  973. }
  974. // S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  975. // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  976. // S 0a39 <name>.24B <slot>.B <hair color>.W <hair style>.W <starting job ID>.W <Unknown>.(W or 2 B's)??? <sex>.B
  977. int chclif_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
  978. if (cmd == 0xa39) FIFOSD_CHECK(36) //>=20151001
  979. else if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
  980. else if (cmd == 0x67) FIFOSD_CHECK(37)
  981. else return 0;
  982. int char_id;
  983. if( (charserv_config.char_new)==0 ) //turn character creation on/off [Kevin]
  984. char_id = -2;
  985. else {
  986. char name[NAME_LENGTH];
  987. int str, agi, vit, int_, dex, luk;
  988. int slot;
  989. int hair_color;
  990. int hair_style;
  991. short start_job;
  992. int sex;
  993. #if PACKETVER >= 20151001
  994. // Sent values
  995. safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
  996. slot = RFIFOB( fd, 26 );
  997. hair_color = RFIFOW( fd, 27 );
  998. hair_style = RFIFOW( fd, 29 );
  999. start_job = RFIFOW( fd, 31 );
  1000. // Unknown RFIFOW( fd, 32 )
  1001. sex = RFIFOB( fd, 35 );
  1002. // Default values
  1003. str = 1;
  1004. agi = 1;
  1005. vit = 1;
  1006. int_ = 1;
  1007. dex = 1;
  1008. luk = 1;
  1009. RFIFOSKIP( fd, 36 );
  1010. #elif PACKETVER >= 20120307
  1011. // Sent values
  1012. safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
  1013. slot = RFIFOB( fd, 26 );
  1014. hair_color = RFIFOW( fd, 27 );
  1015. hair_style = RFIFOW( fd, 29 );
  1016. // Default values
  1017. str = 1;
  1018. agi = 1;
  1019. vit = 1;
  1020. int_ = 1;
  1021. dex = 1;
  1022. luk = 1;
  1023. start_job = JOB_NOVICE;
  1024. sex = sd->sex;
  1025. RFIFOSKIP( fd, 31 );
  1026. #else
  1027. // Sent values
  1028. safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
  1029. str = RFIFOB( fd, 26 );
  1030. agi = RFIFOB( fd, 27 );
  1031. vit = RFIFOB( fd, 28 );
  1032. int_ = RFIFOB( fd, 29 );
  1033. dex = RFIFOB( fd, 30 );
  1034. luk = RFIFOB( fd, 31 );
  1035. slot = RFIFOB( fd, 32 );
  1036. hair_color = RFIFOW( fd, 33 );
  1037. hair_style = RFIFOW( fd, 35 );
  1038. // Default values
  1039. start_job = JOB_NOVICE;
  1040. sex = sd->sex;
  1041. RFIFOSKIP( fd, 37 );
  1042. #endif
  1043. char_id = char_make_new_char( sd, name, str, agi, vit, int_, dex, luk, slot, hair_color, hair_style, start_job, sex );
  1044. }
  1045. if (char_id < 0) {
  1046. // deny character creation
  1047. WFIFOHEAD(fd,3);
  1048. WFIFOW(fd,0) = 0x6e;
  1049. switch (char_id) {
  1050. // 'Charname already exists' (-1)
  1051. case -1: WFIFOB(fd,2) = 0x00; break;
  1052. // 'Char creation denied' (-2)
  1053. case -2: WFIFOB(fd,2) = 0xFF; break;
  1054. // 'You are underaged' (-3)
  1055. case -3: WFIFOB(fd,2) = 0x01; break;
  1056. // 'You are not elegible to open the Character Slot' (-4)
  1057. case -4: WFIFOB(fd,2) = 0x03; break;
  1058. /* Unused: 0x02 = Symbols in Character Names are forbidden [Ind]*/
  1059. }
  1060. WFIFOSET(fd,3);
  1061. } else {
  1062. int len;
  1063. // retrieve data
  1064. struct mmo_charstatus char_dat;
  1065. char_mmo_char_fromsql(char_id, &char_dat, false); //Only the short data is needed.
  1066. // send to player
  1067. WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  1068. WFIFOW(fd,0) = HEADER_HC_ACCEPT_MAKECHAR;
  1069. len = 2 + char_mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  1070. WFIFOSET(fd,len);
  1071. // add new entry to the chars list
  1072. sd->found_char[char_dat.slot] = char_id;
  1073. }
  1074. return 1;
  1075. }
  1076. /**
  1077. * Inform client that his deletion request was refused
  1078. * 0x70 <ErrorCode>B HC_REFUSE_DELETECHAR
  1079. * @param fd
  1080. * @param ErrorCode
  1081. * 00 = Incorrect Email address
  1082. * 01 = Invalid Slot
  1083. * 02 = In a party or guild
  1084. */
  1085. void chclif_refuse_delchar(int fd, uint8 errCode){
  1086. WFIFOHEAD(fd,3);
  1087. WFIFOW(fd,0) = 0x70;
  1088. WFIFOB(fd,2) = errCode;
  1089. WFIFOSET(fd,3);
  1090. }
  1091. int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){
  1092. if (cmd == 0x68) FIFOSD_CHECK(46)
  1093. else if (cmd == 0x1fb) FIFOSD_CHECK(56)
  1094. else return 0;
  1095. {
  1096. char email[40];
  1097. uint32 cid = RFIFOL(fd,2);
  1098. ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%u (%u)" CL_RESET "\n", sd->account_id, cid);
  1099. memcpy(email, RFIFOP(fd,6), 40);
  1100. RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  1101. if (!chclif_delchar_check(sd, email, charserv_config.char_config.char_del_option)) {
  1102. chclif_refuse_delchar(fd,0); // 00 = Incorrect Email address
  1103. return 1;
  1104. }
  1105. /* Delete character */
  1106. switch( char_delete(sd,cid) ){
  1107. case CHAR_DELETE_OK:
  1108. break;
  1109. case CHAR_DELETE_DATABASE:
  1110. case CHAR_DELETE_BASELEVEL:
  1111. case CHAR_DELETE_TIME:
  1112. chclif_refuse_delchar(fd, 0);
  1113. return 1;
  1114. case CHAR_DELETE_NOTFOUND:
  1115. chclif_refuse_delchar(fd, 1);
  1116. return 1;
  1117. case CHAR_DELETE_GUILD:
  1118. case CHAR_DELETE_PARTY:
  1119. chclif_refuse_delchar(fd, 2);
  1120. return 1;
  1121. }
  1122. /* Char successfully deleted.*/
  1123. WFIFOHEAD(fd,2);
  1124. WFIFOW(fd,0) = 0x6f;
  1125. WFIFOSET(fd,2);
  1126. }
  1127. return 1;
  1128. }
  1129. // R 0187 <account ID>.l
  1130. int chclif_parse_keepalive(int fd){
  1131. if (RFIFOREST(fd) < 6)
  1132. return 0;
  1133. //int aid = RFIFOL(fd,2);
  1134. RFIFOSKIP(fd,6);
  1135. return 1;
  1136. }
  1137. // Tells the client if the name was accepted or not
  1138. // 028e <result>.W (HC_ACK_IS_VALID_CHARNAME)
  1139. // result:
  1140. // 0 = name is not OK
  1141. // 1 = name is OK
  1142. void chclif_reqrename_response( int fd, struct char_session_data* sd, bool name_valid ){
  1143. WFIFOHEAD(fd, 4);
  1144. WFIFOW(fd, 0) = 0x28e;
  1145. WFIFOW(fd, 2) = name_valid;
  1146. WFIFOSET(fd, 4);
  1147. }
  1148. // Request for checking the new name on character renaming
  1149. // 028d <account ID>.l <char ID>.l <new name>.24B (CH_REQ_IS_VALID_CHARNAME)
  1150. int chclif_parse_reqrename( int fd, struct char_session_data* sd ){
  1151. FIFOSD_CHECK(34);
  1152. int i, cid, aid;
  1153. char name[NAME_LENGTH];
  1154. char esc_name[NAME_LENGTH*2+1];
  1155. aid = RFIFOL(fd,2);
  1156. cid = RFIFOL(fd,6);
  1157. safestrncpy(name, RFIFOCP(fd,10), NAME_LENGTH);
  1158. RFIFOSKIP(fd,34);
  1159. if( aid != sd->account_id )
  1160. return 1;
  1161. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  1162. if( i == MAX_CHARS )
  1163. return 1;
  1164. normalize_name(name,TRIM_CHARS);
  1165. Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  1166. if( !char_check_char_name(name,esc_name) ) {
  1167. i = 1;
  1168. safestrncpy(sd->new_name, name, NAME_LENGTH);
  1169. }
  1170. else
  1171. i = 0;
  1172. chclif_reqrename_response(fd, sd, i > 0);
  1173. return 1;
  1174. }
  1175. TIMER_FUNC(charblock_timer){
  1176. struct char_session_data* sd=nullptr;
  1177. int i=0;
  1178. ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == id);
  1179. if(sd == nullptr || sd->charblock_timer==INVALID_TIMER) //has disconected or was required to stop
  1180. return 0;
  1181. if (sd->charblock_timer != tid){
  1182. sd->charblock_timer = INVALID_TIMER;
  1183. return 0;
  1184. }
  1185. chclif_block_character(i,sd);
  1186. return 0;
  1187. }
  1188. /*
  1189. * 0x20d <PacketLength>.W <TAG_CHARACTER_BLOCK_INFO>24B (HC_BLOCK_CHARACTER)
  1190. * <GID>L <szExpireDate>20B (TAG_CHARACTER_BLOCK_INFO)
  1191. */
  1192. void chclif_block_character( int fd, struct char_session_data* sd){
  1193. int i=0, j=0, len=4;
  1194. time_t now = time(nullptr);
  1195. WFIFOHEAD(fd, 4+MAX_CHARS*24);
  1196. WFIFOW(fd, 0) = 0x20d;
  1197. for(i=0; i<MAX_CHARS; i++){
  1198. if(sd->found_char[i] == -1)
  1199. continue;
  1200. if(sd->unban_time[i]){
  1201. if( sd->unban_time[i] > now ) {
  1202. char szExpireDate[21];
  1203. WFIFOL(fd, 4+j*24) = sd->found_char[i];
  1204. timestamp2string(szExpireDate, 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S");
  1205. memcpy(WFIFOP(fd,8+j*24),szExpireDate,20);
  1206. }
  1207. else {
  1208. WFIFOL(fd, 4+j*24) = 0;
  1209. sd->unban_time[i] = 0;
  1210. 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]) )
  1211. Sql_ShowDebug(sql_handle);
  1212. }
  1213. len+=24;
  1214. j++; //pkt list idx
  1215. }
  1216. }
  1217. WFIFOW(fd, 2) = len; //packet len
  1218. WFIFOSET(fd,len);
  1219. ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i] > now); //sd->charslot only have productible char
  1220. if(i < MAX_CHARS ){
  1221. sd->charblock_timer = add_timer(
  1222. gettick() + 10000, // each 10s resend that list
  1223. charblock_timer, sd->account_id, 0);
  1224. }
  1225. }
  1226. // Sends the response to a rename request to the client.
  1227. // 0290 <result>.W (HC_ACK_CHANGE_CHARNAME)
  1228. // 08fd <result>.L (HC_ACK_CHANGE_CHARACTERNAME)
  1229. // result:
  1230. // 0: Successful
  1231. // 1: This character's name has already been changed. You cannot change a character's name more than once.
  1232. // 2: User information is not correct.
  1233. // 3: You have failed to change this character's name.
  1234. // 4: Another user is using this character name, so please select another one.
  1235. // 5: In order to change the character name, you must leave the guild.
  1236. // 6: In order to change the character name, you must leave the party.
  1237. // 7: Length exceeds the maximum size of the character name you want to change.
  1238. // 8: Name contains invalid characters. Character name change failed.
  1239. // 9: The name change is prohibited. Character name change failed.
  1240. // 10: Character name change failed, due an unknown error.
  1241. void chclif_rename_response(int fd, struct char_session_data* sd, int16 response) {
  1242. #if PACKETVER >= 20111101
  1243. WFIFOHEAD(fd, 6);
  1244. WFIFOW(fd, 0) = 0x8fd;
  1245. WFIFOL(fd, 2) = response;
  1246. WFIFOSET(fd, 6);
  1247. #else
  1248. WFIFOHEAD(fd, 4);
  1249. WFIFOW(fd, 0) = 0x290;
  1250. WFIFOW(fd, 2) = response;
  1251. WFIFOSET(fd, 4);
  1252. #endif
  1253. }
  1254. // Request to change a character name
  1255. // 028f <char_id>.L (CH_REQ_CHANGE_CHARNAME)
  1256. // 08fc <char_id>.L <new name>.24B (CH_REQ_CHANGE_CHARACTERNAME)
  1257. int chclif_parse_ackrename(int fd, struct char_session_data* sd){
  1258. #if PACKETVER >= 20111101
  1259. FIFOSD_CHECK(30)
  1260. {
  1261. int i, cid;
  1262. char name[NAME_LENGTH], esc_name[NAME_LENGTH * 2 + 1];
  1263. cid = RFIFOL(fd, 2);
  1264. safestrncpy(name, RFIFOCP(fd, 6), NAME_LENGTH);
  1265. RFIFOSKIP(fd, 30);
  1266. ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid);
  1267. if (i == MAX_CHARS)
  1268. return 1;
  1269. normalize_name(name, TRIM_CHARS);
  1270. Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  1271. safestrncpy(sd->new_name, name, NAME_LENGTH);
  1272. // Start the renaming process
  1273. i = char_rename_char_sql(sd, cid);
  1274. chclif_rename_response(fd, sd, i);
  1275. // If the renaming was successful, we need to resend the characters
  1276. if( i == 0 )
  1277. chclif_mmo_char_send(fd, sd);
  1278. return 1;
  1279. }
  1280. #else
  1281. FIFOSD_CHECK(6)
  1282. {
  1283. int i;
  1284. int cid = RFIFOL(fd,2);
  1285. RFIFOSKIP(fd,6);
  1286. ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  1287. if( i == MAX_CHARS )
  1288. return 1;
  1289. i = char_rename_char_sql(sd, cid);
  1290. chclif_rename_response(fd, sd, i);
  1291. }
  1292. return 1;
  1293. #endif
  1294. }
  1295. int chclif_ack_captcha(int fd){
  1296. WFIFOHEAD(fd,5);
  1297. WFIFOW(fd,0) = 0x7e9;
  1298. WFIFOW(fd,2) = 5;
  1299. WFIFOB(fd,4) = 1;
  1300. WFIFOSET(fd,5);
  1301. return 1;
  1302. }
  1303. // R 06C <ErrorCode>B HEADER_HC_REFUSE_ENTER
  1304. void chclif_reject(int fd, uint8 errCode){
  1305. WFIFOHEAD(fd,3);
  1306. WFIFOW(fd,0) = 0x6c;
  1307. WFIFOB(fd,2) = errCode;// rejected from server
  1308. WFIFOSET(fd,3);
  1309. }
  1310. // R 07e5 <?>.w <aid>.l
  1311. int chclif_parse_reqcaptcha(int fd){
  1312. //FIFOSD_CHECK(8)
  1313. RFIFOSKIP(fd,8);
  1314. chclif_ack_captcha(fd);
  1315. return 1;
  1316. }
  1317. // R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  1318. int chclif_parse_chkcaptcha(int fd){
  1319. //FIFOSD_CHECK(32)
  1320. RFIFOSKIP(fd,32);
  1321. chclif_ack_captcha(fd);
  1322. return 1;
  1323. }
  1324. /**
  1325. * Entry point from client to char-serv
  1326. * function that check incoming command then split it to correct handler.
  1327. * @param fd: file descriptor to parse, (link to client)
  1328. */
  1329. int chclif_parse(int fd) {
  1330. struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
  1331. uint32 ipl = session[fd]->client_addr;
  1332. // disconnect any player if no login-server.
  1333. if(login_fd < 0)
  1334. set_eof(fd);
  1335. if(session[fd]->flag.eof) {
  1336. if( sd != nullptr && sd->auth ) { // already authed client
  1337. std::shared_ptr<struct online_char_data> data = util::umap_find( char_get_onlinedb(), sd->account_id );
  1338. if( data != nullptr && data->fd == fd ){
  1339. data->fd = -1;
  1340. }
  1341. // If it is not in any server, send it offline. [Skotlex]
  1342. if( data == nullptr || data->server == -1 ){
  1343. char_set_char_offline(-1,sd->account_id);
  1344. }
  1345. }
  1346. do_close(fd);
  1347. return 0;
  1348. }
  1349. while( RFIFOREST(fd) >= 2 ) {
  1350. int next = 1;
  1351. unsigned short cmd;
  1352. cmd = RFIFOW(fd,0);
  1353. #if PACKETVER_SUPPORTS_PINCODE
  1354. // If the pincode system is enabled
  1355. if( charserv_config.pincode_config.pincode_enabled ){
  1356. switch( cmd ){
  1357. // Connect of player
  1358. case 0x65:
  1359. // Client keep-alive packet (every 12 seconds)
  1360. case 0x187:
  1361. // Checks the entered pin
  1362. case 0x8b8:
  1363. // Request PIN change
  1364. case 0x8be:
  1365. // Request for PIN window
  1366. case 0x8c5:
  1367. // Request character list
  1368. case 0x9a1:
  1369. // Connect of map-server
  1370. case 0x2af8:
  1371. break;
  1372. // Before processing any other packets, do a few checks
  1373. default:
  1374. // To reach this block the client should have attained a session already
  1375. if( sd != nullptr ){
  1376. // If the pincode was entered correctly
  1377. if( sd->pincode_correct ){
  1378. break;
  1379. }
  1380. // If no pincode is set (yet)
  1381. if( strlen( sd->pincode ) <= 0 ){
  1382. break;
  1383. }
  1384. // The pincode was not entered correctly, yet the player (=bot) tried to send a different packet => Goodbye!
  1385. set_eof( fd );
  1386. return 0;
  1387. }else{
  1388. // Unknown packet received
  1389. ShowError( "chclif_parse: Received unknown packet " CL_WHITE "0x%x" CL_RESET " from ip '" CL_WHITE "%s" CL_RESET "'! Disconnecting!\n", cmd, ip2str( ipl, nullptr ) );
  1390. set_eof( fd );
  1391. return 0;
  1392. }
  1393. }
  1394. }
  1395. #endif
  1396. switch( cmd ) {
  1397. case 0x65: next=chclif_parse_reqtoconnect(fd,sd,ipl); break;
  1398. // char select
  1399. case 0x66: next=chclif_parse_charselect(fd,sd,ipl); break;
  1400. // createnewchar
  1401. case 0xa39:
  1402. case 0x970:
  1403. case 0x67: next=chclif_parse_createnewchar(fd,sd,cmd); break;
  1404. // delete char
  1405. case 0x68: next=chclif_parse_delchar(fd,sd,cmd); break; //
  1406. case 0x1fb: next=chclif_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
  1407. // client keep-alive packet (every 12 seconds)
  1408. case 0x187: next=chclif_parse_keepalive(fd); break;
  1409. // char rename
  1410. case 0x28d: next=chclif_parse_reqrename(fd,sd); break; //Check new desired name
  1411. case 0x28f: next=chclif_parse_ackrename(fd,sd); break; //Confirm change name.
  1412. case 0x8fc: next=chclif_parse_ackrename(fd,sd); break; //Rename request without confirmation
  1413. // captcha
  1414. case 0x7e5: next=chclif_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
  1415. case 0x7e7: next=chclif_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
  1416. // deletion timer request
  1417. case 0x827: next=chclif_parse_char_delete2_req(fd, sd); break;
  1418. // deletion accept request
  1419. case 0x829: next=chclif_parse_char_delete2_accept(fd, sd); break;
  1420. // deletion cancel request
  1421. case 0x82b: next=chclif_parse_char_delete2_cancel(fd, sd); break;
  1422. // login as map-server
  1423. case 0x2af8: chclif_parse_maplogin(fd); return 0; // avoid processing of followup packets here
  1424. #if PACKETVER_SUPPORTS_PINCODE
  1425. //pincode
  1426. case 0x8b8: next=chclif_parse_pincode_check( fd, sd ); break; // checks the entered pin
  1427. case 0x8c5: next=chclif_parse_reqpincode_window(fd,sd); break; // request for PIN window
  1428. case 0x8be: next=chclif_parse_pincode_change( fd, sd ); break; // pincode change request
  1429. case 0x8ba: next=chclif_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
  1430. #endif
  1431. // character movement request
  1432. case 0x8d4: next=chclif_parse_moveCharSlot(fd,sd); break;
  1433. case 0x9a1: next=chclif_parse_req_charlist(fd,sd); break;
  1434. case HEADER_CH_SELECT_ACCESSIBLE_MAPNAME:
  1435. next = chclif_parse_select_accessible_map( fd, sd, ipl );
  1436. break;
  1437. // unknown packet received
  1438. default:
  1439. ShowError( "chclif_parse: Received unknown packet " CL_WHITE "0x%x" CL_RESET " from ip '" CL_WHITE "%s" CL_RESET "'! Disconnecting!\n", cmd, ip2str( ipl, nullptr ) );
  1440. set_eof(fd);
  1441. return 0;
  1442. }
  1443. if (next == 0)
  1444. return 0; // avoid processing of followup packets (prev was probably incomplete)
  1445. }
  1446. RFIFOFLUSH(fd);
  1447. return 0;
  1448. }