char_clif.cpp 42 KB

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