char_clif.cpp 42 KB

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