char_clif.c 38 KB

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