char_clif.cpp 47 KB

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