char_clif.cpp 48 KB

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