ini.inc 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633
  1. /**--------------------------------------------------------------------------**\
  2. ===================================
  3. y_users - Registration functions.
  4. ===================================
  5. Description:
  6. Provides access to a user system for registering and saving users.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the YSI malloc include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2011
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. ZeeX - Very productive conversations.
  26. koolk - IsPlayerinAreaEx code.
  27. TheAlpha - Danish translation.
  28. breadfish - German translation.
  29. Fireburn - Dutch translation.
  30. yom - French translation.
  31. 50p - Polish translation.
  32. Zamaroht - Spanish translation.
  33. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  34. for me to strive to better.
  35. Pixels^ - Running XScripters where the idea was born.
  36. Matite - Pestering me to release it and using it.
  37. Very special thanks to:
  38. Thiadmer - PAWN, whose limits continue to amaze me!
  39. Kye/Kalcor - SA:MP.
  40. SA:MP Team past, present and future - SA:MP.
  41. Version:
  42. 2.2
  43. Changelog:
  44. 02/02/13:
  45. Added bits and join timestamp to preload data.
  46. Added backwards compatible salting to the hash.
  47. 15/11/11:
  48. Added comments.
  49. Added language to the top-level player data (needed for login).
  50. 11/11/11:
  51. First version.
  52. Functions:
  53. Public
  54. -
  55. Core:
  56. -
  57. Stock:
  58. -
  59. Static:
  60. -
  61. Inline:
  62. -
  63. API:
  64. -
  65. Callbacks:
  66. -
  67. Definitions:
  68. -
  69. Enums:
  70. -
  71. Macros:
  72. -
  73. Tags:
  74. -
  75. Variables:
  76. Global:
  77. -
  78. Static:
  79. -
  80. Commands:
  81. -
  82. Compile options:
  83. -
  84. Operators:
  85. -
  86. </remarks>
  87. \**--------------------------------------------------------------------------**/
  88. /*
  89. ad88888ba
  90. d8" "8b ,d
  91. Y8, 88
  92. `Y8aaaaa, ,adPPYba, MM88MMM 88 88 8b,dPPYba,
  93. `"""""8b, a8P_____88 88 88 88 88P' "8a
  94. `8b 8PP""""""" 88 88 88 88 d8
  95. Y8a a8P "8b, ,aa 88, "8a, ,a88 88b, ,a8"
  96. "Y88888P" `"Ybbd8"' "Y888 `"YbbdP'Y8 88`YbbdP"'
  97. 88
  98. 88
  99. */
  100. loadtext core[ysi_players];
  101. enum E_USER_PRELOAD
  102. {
  103. E_USER_PRELOAD_YID,
  104. Language:E_USER_PRELOAD_LANG,
  105. E_USER_PRELOAD_PASS[MAX_PASSWORD_LENGTH + 1],
  106. E_USER_PRELOAD_BITS,
  107. E_USER_PRELOAD_DATE
  108. }
  109. static stock
  110. YSI_g_sPlayerIndexFile,
  111. INI:YSI_g_sPlayerWriteFile = INI_NO_FILE,
  112. YSI_g_sPlayerYID[MAX_PLAYERS] = {-2, ...},
  113. YSI_g_sPreloadData[MAX_PLAYERS][E_USER_PRELOAD];
  114. #define Player_GetIndexFile(%0,%1) ((YSI_g_sPlayerIndexFile=%1),%0[USER_FILE_LENGTH+4]=(('a'<=(YSI_g_sPlayerIndexFile|0x20)<='z')?(YSI_g_sPlayerIndexFile|0x20):(('0'<=YSI_g_sPlayerIndexFile<='9')?('0'):('_'))))
  115. /*
  116. 88888888ba 88 88
  117. 88 "8b 88 88
  118. 88 ,8P 88 88
  119. 88aaaaaa8P' 8b,dPPYba, ,adPPYba, 88 ,adPPYba, ,adPPYYba, ,adPPYb,88
  120. 88""""""' 88P' "Y8 a8P_____88 88 a8" "8a "" `Y8 a8" `Y88
  121. 88 88 8PP""""""" 88 8b d8 ,adPPPPP88 8b 88
  122. 88 88 "8b, ,aa 88 "8a, ,a8" 88, ,88 "8a, ,d88
  123. 88 88 `"Ybbd8"' 88 `"YbbdP"' `"8bbdP"Y8 `"8bbdP"Y8
  124. */
  125. /**--------------------------------------------------------------------------**\
  126. <summary>Player_Reload</summary>
  127. <param name="playerid">Player who changed name.</param>
  128. <returns>
  129. -
  130. </returns>
  131. <remarks>
  132. Reload a player's basic data when they change name.
  133. </remarks>
  134. \**--------------------------------------------------------------------------**/
  135. stock Player_Reload(playerid)
  136. {
  137. new
  138. name[MAX_PLAYER_NAME];
  139. GetPlayerName(playerid, name, sizeof (name));
  140. Player_Preload(name, YSI_g_sPreloadData[playerid]);
  141. }
  142. stock Player_SetPreload(playerid, data[E_USER_PRELOAD])
  143. {
  144. if (VALID_PLAYERID(playerid))
  145. {
  146. YSI_g_sPreloadData[playerid] = data;
  147. }
  148. }
  149. /**--------------------------------------------------------------------------**\
  150. <summary>Player_Preload</summary>
  151. <param name="playerid">Player who is logging in.</param>
  152. <returns>
  153. -
  154. </returns>
  155. <remarks>
  156. Loads a player's data to an array.
  157. </remarks>
  158. \**--------------------------------------------------------------------------**/
  159. #if _YSI_PLUGINS_MYSQL == 7
  160. public _Player_Preload(ret[E_USER_PRELOAD])
  161. {
  162. // Need to use some clever AMX hacking to pass the "ret" array...
  163. }
  164. #endif
  165. stock Player_Preload(string:name[], ret[E_USER_PRELOAD])
  166. {
  167. // First, find the player's file. This should be the ONLY place where the
  168. // password is to be loaded.
  169. P:4("Player_Preload called: %s", name);
  170. ret[E_USER_PRELOAD_YID] = -2;
  171. memset(ret[E_USER_PRELOAD_PASS], 0, MAX_PASSWORD_LENGTH);
  172. ret[E_USER_PRELOAD_LANG] = NO_LANGUAGE;
  173. ret[E_USER_PRELOAD_BITS] = 0;
  174. ret[E_USER_PRELOAD_DATE] = 0;
  175. new
  176. namelen = strlen(name),
  177. filename[] = USER_FILE_PATH "ind_X.YSI",
  178. File:fIndex;
  179. Player_GetIndexFile(filename, name[0]);
  180. fIndex = fopen(filename, io_read);
  181. if (fIndex)
  182. {
  183. P:5("Player_Preload: fIndex OK");
  184. new
  185. line[INDEX_DATA_LINE_LENGTH],
  186. len;
  187. while ((len = fread(fIndex, line)))
  188. {
  189. P:6("Player_Preload: while");
  190. //new
  191. // len;
  192. //len = strlen(line);
  193. // Check if the line is the right length (could be one of three
  194. // lengths depending on newlines). Skip blanks.
  195. if (len < INDEX_DATA_LINE_LENGTH - 3)
  196. {
  197. continue;
  198. }
  199. P:6("Player_Preload: Not len");
  200. // Check the name on the line.
  201. if (!strcmp(line[MAX_INDEX_LENGTH + 1], name, false, namelen) && line[MAX_INDEX_LENGTH + 1 + namelen] == ' ')
  202. {
  203. P:6("Player_Preload: checked name");
  204. // Found the section on this one player.
  205. //P:6("Player_Preload: check pass: %s ?= %s", hash, line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1]);
  206. // Save the loaded data.
  207. line[MAX_INDEX_LENGTH] = '\0';
  208. //printf("line: %s", line);
  209. ret[E_USER_PRELOAD_YID] = strval(line);
  210. //printf("%d %d %d", ret[E_USER_PRELOAD_YID], strval(line), strval("00000022"));
  211. //printf("%d", strval(line));
  212. line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1 + 2] = '\0';
  213. ret[E_USER_PRELOAD_LANG] = Langs_GetLanguage(line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1]);
  214. strcat(ret[E_USER_PRELOAD_PASS], line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1], MAX_PASSWORD_LENGTH + 1);
  215. // Load the 32 extra "bits".
  216. ret[E_USER_PRELOAD_BITS] = hexstr(line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1 + 2 + 1]);
  217. // Load the user registration date (if they have one).
  218. ret[E_USER_PRELOAD_DATE] = hexstr(line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1 + 2 + 1 + 8 + 1]);
  219. P:6("Player_Preload: %s %d %d %x %x", ret[E_USER_PRELOAD_PASS], ret[E_USER_PRELOAD_YID], _:ret[E_USER_PRELOAD_LANG], ret[E_USER_PRELOAD_BITS], ret[E_USER_PRELOAD_DATE]);
  220. fclose(fIndex);
  221. return 1;
  222. }
  223. }
  224. fclose(fIndex);
  225. }
  226. else if (fexist(filename))
  227. {
  228. P:E("Error reading index %c.", filename[sizeof (filename) - 6]);
  229. return -1;
  230. }
  231. ret[E_USER_PRELOAD_YID] = -1;
  232. return 0;
  233. }
  234. stock Language:Player_GetPreloadLanguage(playerid)
  235. {
  236. return Language:YSI_g_sPreloadData[playerid][E_USER_PRELOAD_LANG];
  237. }
  238. stock Player_GetPreloadBits(playerid)
  239. {
  240. return YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS];
  241. }
  242. static remotefunc void:_Player_SetPreloadBits(playerid, bits)
  243. {
  244. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS] = bits;
  245. }
  246. stock Player_SetPreloadBits(playerid, bits)
  247. {
  248. broadcastfunc _Player_SetPreloadBits(playerid, bits);
  249. Player_RewritePreload(playerid);
  250. }
  251. stock Player_GetPreloadDate(playerid)
  252. {
  253. if (0 <= YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] < 1234567890)
  254. {
  255. return -1;
  256. }
  257. return YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE];
  258. }
  259. stock Player_IsRegistered(playerid)
  260. {
  261. return YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID] != -1;
  262. }
  263. /*
  264. 88 88 88
  265. 88 88 88
  266. 88 88 88
  267. 88aaaaaaaa88 ,adPPYba, ,adPPYba, 88 ,d8 ,adPPYba,
  268. 88""""""""88 a8" "8a a8" "8a 88 ,a8" I8[ ""
  269. 88 88 8b d8 8b d8 8888[ `"Y8ba,
  270. 88 88 "8a, ,a8" "8a, ,a8" 88`"Yba, aa ]8I
  271. 88 88 `"YbbdP"' `"YbbdP"' 88 `Y8a `"YbbdP"'
  272. */
  273. hook OnScriptInit()
  274. {
  275. switch (ftouch(USER_FILE_PATH "index.YSI"))
  276. {
  277. case -1:
  278. {
  279. P:E(USER_FILE_PATH "index.YSI does not exist and couldn't be created.");
  280. }
  281. case 1:
  282. {
  283. if (Player_CreateNewID())
  284. {
  285. // Don't need upgrades.
  286. if (ftouch(USER_FILE_PATH "y_users_v2_1.YSI") == -1)
  287. {
  288. P:E("Could not touch upgrade file 1.");
  289. // Use "else" so we don't try do upgrade 2 without upgrade
  290. // 1. That would really mess up the files (that don't yet
  291. // exist, but could do).
  292. }
  293. else if (ftouch(USER_FILE_PATH "y_users_v2_2.YSI") == -1)
  294. {
  295. P:E("Could not touch upgrade file 2.");
  296. }
  297. }
  298. else
  299. {
  300. P:E(USER_FILE_PATH "index.YSI does not exist and couldn't be created.");
  301. }
  302. }
  303. }
  304. }
  305. public OnGameModeInit()
  306. {
  307. if (YSI_FILTERSCRIPT)
  308. {
  309. #if defined Users_OnGameModeInit
  310. Users_OnGameModeInit();
  311. #endif
  312. }
  313. else
  314. {
  315. #if defined Users_OnGameModeInit
  316. Users_OnGameModeInit();
  317. #endif
  318. Users_DoUpgrade0();
  319. Users_DoUpgrade1();
  320. }
  321. return 1;
  322. }
  323. #if defined _ALS_OnGameModeInit
  324. #undef OnGameModeInit
  325. #else
  326. #define _ALS_OnGameModeInit
  327. #endif
  328. #if defined Users_OnGameModeInit
  329. forward Users_OnGameModeInit();
  330. #endif
  331. #define OnGameModeInit(%0) Users_OnGameModeInit(%0)
  332. public OnFilterScriptInit()
  333. {
  334. // DO ALL (MOST) OTHER INITS FIRST. ENSURE WE COME LATER.
  335. #if defined Users_OnFilterScriptInit
  336. Users_OnFilterScriptInit();
  337. #endif
  338. Users_DoUpgrade0();
  339. Users_DoUpgrade1();
  340. return 1;
  341. }
  342. #if defined _ALS_OnFilterScriptInit
  343. #undef OnFilterScriptInit
  344. #else
  345. #define _ALS_OnFilterScriptInit
  346. #endif
  347. #if defined Users_OnFilterScriptInit
  348. forward Users_OnFilterScriptInit();
  349. #endif
  350. #define OnFilterScriptInit(%0) Users_OnFilterScriptInit(%0)
  351. hook OnPlayerConnect(playerid)
  352. {
  353. P:1("Users_OnPlayerConnect called: %d", playerid);
  354. // -2 means unknown.
  355. YSI_g_sPlayerYID[playerid] = -2;
  356. broadcastfunc _Player_IsLoggedIn(playerid);
  357. if (existproperty(8, YSIM_LOG_IN))
  358. {
  359. new
  360. uid = getproperty(8, YSIM_LOG_IN);
  361. P:5("Users_OnPlayerConnect: Exists %d", uid);
  362. if (uid == -1)
  363. {
  364. new
  365. name[MAX_PLAYER_NAME];
  366. GetPlayerName(playerid, name, sizeof (name));
  367. Player_Preload(name, YSI_g_sPreloadData[playerid]);
  368. }
  369. else
  370. {
  371. // This DOES NOT use "broadcastfunc" as it's local only.
  372. Player_DoLogin(playerid, uid);
  373. }
  374. deleteproperty(8, YSIM_LOG_IN);
  375. }
  376. else
  377. {
  378. P:5("Users_OnPlayerConnect: Doesn't exist");
  379. new
  380. name[MAX_PLAYER_NAME];
  381. GetPlayerName(playerid, name, sizeof (name));
  382. Player_Preload(name, YSI_g_sPreloadData[playerid]);
  383. P:5("Users_OnPlayerConnect: Done Preload");
  384. // Can do checking in here to see if they just rejoined.
  385. }
  386. YSI_g_sPlayerYID[playerid] = -1;
  387. }
  388. hook OnPlayerDisconnect(playerid, reason)
  389. {
  390. P:2("Users_OnPlayerDisconnect called: %d %d %d", playerid, reason, YSI_g_sPlayerYID[playerid]);
  391. if (YSI_g_sPlayerYID[playerid] >= 0)
  392. {
  393. // DO NOT broadcastfunc this in case it's just because of one script being
  394. // unloaded, not the player actually leaving (and thus do everything in
  395. // different scripts separately).
  396. _Player_ForceSave(playerid, true);
  397. }
  398. YSI_g_sPlayerYID[playerid] = -2;
  399. }
  400. static remotefunc void:_Player_IsLoggedIn(playerid)
  401. {
  402. P:4("_Player_IsLoggedIn called: %d %d", playerid, YSI_g_sPlayerYID[playerid]);
  403. if (YSI_g_sPlayerYID[playerid] != -2)
  404. {
  405. setproperty(8, YSIM_LOG_IN, YSI_g_sPlayerYID[playerid]);
  406. }
  407. }
  408. stock bool:Player_IsLoggedIn(playerid)
  409. {
  410. // -2 should never be an issue, but if it is...
  411. return YSI_g_sPlayerYID[playerid] >= 0;
  412. }
  413. stock Player_GetYID(playerid)
  414. {
  415. return YSI_g_sPlayerYID[playerid];
  416. }
  417. /**--------------------------------------------------------------------------**\
  418. <summary>Player_TryLogin</summary>
  419. <param name="playerid">Player who is logging in.</param>
  420. <param name="password[]">Password they entered.</param>
  421. <param name="f">Show the failed to login message?</param>
  422. <returns>
  423. -
  424. </returns>
  425. <remarks>
  426. Tries to log in a player - hashes and checks their password and if it's
  427. right calls the core login code. It doesn't matter WHICH script does this
  428. as they ALL get called and ALL track the login status of a player.
  429. </remarks>
  430. \**--------------------------------------------------------------------------**/
  431. //stock Player_TryLogin(playerid, string:password[], f = 0)
  432. //{
  433. //return _Player_TryLogin(playerid, password, f);
  434. //}
  435. global Player_TryLogin(playerid, string:password[])
  436. {
  437. P:2("Player_TryLogin start");
  438. if (Player_IsLoggedIn(playerid))
  439. {
  440. // They are already logged in.
  441. Text_Send(playerid, $YSI_LOGIN_ALREADY);
  442. return 1;
  443. }
  444. new
  445. hash[MAX_PASSWORD_LENGTH + 8 + 1];
  446. Player_HashPass(password, hash);
  447. format(hash[MAX_PASSWORD_LENGTH], sizeof (hash) - MAX_PASSWORD_LENGTH, "%04x%04x", YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] & 0xFFFF);
  448. //printf("HASH 1: %s", hash);
  449. Player_HashPass(hash, hash);
  450. //printf("HASH 2: %s", hash);
  451. //Player_HashPass(hash, hash);
  452. switch (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID])
  453. {
  454. case -2:
  455. {
  456. Text_Send(playerid, $YSI_LOGIN_INDERR);
  457. }
  458. case -1:
  459. {
  460. Text_Send(playerid, $YSI_LOGIN_NOTF);
  461. }
  462. default:
  463. {
  464. // Match the password.
  465. if (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS][0] && !strcmp(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], hash, false, MAX_PASSWORD_LENGTH))
  466. {
  467. // Wipe the password from memory.
  468. memset(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], 0, MAX_PASSWORD_LENGTH);
  469. // Extract the uid and call in to the login code.
  470. Langs_SetPlayerLanguage(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_LANG]);
  471. broadcastfunc Player_DoLogin(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID]);
  472. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  473. return 1;
  474. }
  475. else
  476. {
  477. Text_Send(playerid, $YSI_LOGIN_WRONG);
  478. }
  479. }
  480. }
  481. return 0;
  482. }
  483. /**--------------------------------------------------------------------------**\
  484. <summary>Player_ForceLogin</summary>
  485. <param name="playerid">Player who is logging in.</param>
  486. <returns>
  487. -
  488. </returns>
  489. <remarks>
  490. Like "Player_TryLogin" but doesn't take a password so always works.
  491. </remarks>
  492. \**--------------------------------------------------------------------------**/
  493. global Player_ForceLogin(playerid)
  494. {
  495. P:2("Player_TryLogin start");
  496. if (Player_IsLoggedIn(playerid))
  497. {
  498. // They are already logged in.
  499. Text_Send(playerid, $YSI_LOGIN_ALREADY);
  500. return 1;
  501. }
  502. switch (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID])
  503. {
  504. case -2:
  505. {
  506. Text_Send(playerid, $YSI_LOGIN_INDERR);
  507. }
  508. case -1:
  509. {
  510. Text_Send(playerid, $YSI_LOGIN_NOTF);
  511. }
  512. default:
  513. {
  514. // Extract the uid and call in to the login code.
  515. //YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS] = '\0';
  516. memset(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], 0, MAX_PASSWORD_LENGTH);
  517. Langs_SetPlayerLanguage(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_LANG]);
  518. broadcastfunc Player_DoLogin(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID]);
  519. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  520. return 1;
  521. }
  522. }
  523. return 0;
  524. }
  525. /*static*/ remotefunc void:Player_DoLogin(playerid, uid)
  526. {
  527. // Called when a player logs in - either locally (new script) or globally
  528. // (actually only just logged in).
  529. YSI_g_sPlayerYID[playerid] = uid;
  530. // Load any "uvar" variables.
  531. // Call the hooks version of this.
  532. new
  533. filename[64];
  534. format(filename, sizeof (filename), USER_FILE_PATH "%0" #MAX_INDEX_LENGTH "d.INI", uid);
  535. // INI_ParseFile will ONLY load the data for THIS mode, as well as data
  536. // which is mode independent (though there should be none).
  537. INI_ParseFile(filename, "@yU_%s", .bExtra = true, .extra = playerid, .bLocal = true, .bFilter = false, .filter = #MODE_NAME);
  538. //Hooks_OnPlayerLogin(playerid, uid);
  539. //if (YSI_g_sCallbacks & 1)
  540. //{
  541. //CallLocalFunction("OnPlayerLogin", "ii", playerid, uid);
  542. call OnPlayerLogin(playerid, uid);
  543. //}
  544. }
  545. /**--------------------------------------------------------------------------**\
  546. <summary>Player_RemoveEntry</summary>
  547. <param name="name[]">Item to remove.</param>
  548. <returns>
  549. -
  550. </returns>
  551. <remarks>
  552. Wrapper for Player_AddToBuffer for removing data.
  553. </remarks>
  554. \**--------------------------------------------------------------------------**/
  555. stock Player_RemoveEntry(name[])
  556. {
  557. INI_RemoveEntry(YSI_g_sPlayerWriteFile, name);
  558. }
  559. /**--------------------------------------------------------------------------**\
  560. <summary>Player_WriteString</summary>
  561. <param name="name[]">Data name.</param>
  562. <param name="data[]">Data.</param>
  563. <returns>
  564. -
  565. </returns>
  566. <remarks>
  567. Wrapper for Player_AddToBuffer for strings.
  568. </remarks>
  569. \**--------------------------------------------------------------------------**/
  570. stock Player_WriteString(name[], data[])
  571. {
  572. INI_WriteString(YSI_g_sPlayerWriteFile, name, data);
  573. }
  574. stock Player_WriteArray(const name[], data[], len)
  575. {
  576. //printf("name = %s", name);
  577. //printf("data = %d, %d, %d", data[0], data[1], data[2]);
  578. //printf("len = %d", len);
  579. INI_WriteArray(YSI_g_sPlayerWriteFile, name, data, len);
  580. return 1;
  581. }
  582. /**--------------------------------------------------------------------------**\
  583. <summary>Player_WriteInt</summary>
  584. <param name="name[]">Data name.</param>
  585. <param name="data">Integer data.</param>
  586. <returns>
  587. -
  588. </returns>
  589. <remarks>
  590. Wrapper for Player_AddToBuffer for integers.
  591. </remarks>
  592. \**--------------------------------------------------------------------------**/
  593. stock Player_WriteInt(name[], data)
  594. {
  595. INI_WriteInt(YSI_g_sPlayerWriteFile, name, data);
  596. }
  597. /**--------------------------------------------------------------------------**\
  598. <summary>Player_WriteHex</summary>
  599. <param name="name[]">Data name.</param>
  600. <param name="data">Hex data.</param>
  601. <returns>
  602. -
  603. </returns>
  604. <remarks>
  605. Wrapper for Player_AddToBuffer for integers to be written as hex values.
  606. </remarks>
  607. \**--------------------------------------------------------------------------**/
  608. stock Player_WriteHex(name[], data)
  609. {
  610. INI_WriteHex(YSI_g_sPlayerWriteFile, name, data);
  611. }
  612. /**--------------------------------------------------------------------------**\
  613. <summary>Player_WriteBin</summary>
  614. <param name="name[]">Data name.</param>
  615. <param name="data">Binary data.</param>
  616. <returns>
  617. -
  618. </returns>
  619. <remarks>
  620. Wrapper for Player_AddToBuffer for integers to be written as binary values.
  621. </remarks>
  622. \**--------------------------------------------------------------------------**/
  623. stock Player_WriteBin(name[], data)
  624. {
  625. INI_WriteBin(YSI_g_sPlayerWriteFile, name, data);
  626. }
  627. /**--------------------------------------------------------------------------**\
  628. <summary>Player_WriteBool</summary>
  629. <param name="name[]">Data name.</param>
  630. <param name="data">Boolean data.</param>
  631. <returns>
  632. -
  633. </returns>
  634. <remarks>
  635. Wrapper for Player_AddToBuffer for booleans.
  636. </remarks>
  637. \**--------------------------------------------------------------------------**/
  638. stock Player_WriteBool(name[], bool:data)
  639. {
  640. INI_WriteBool(YSI_g_sPlayerWriteFile, name, data);
  641. }
  642. /**--------------------------------------------------------------------------**\
  643. <summary>Player_WriteFloat</summary>
  644. <param name="name[]">Data name.</param>
  645. <param name="Float:data">Float data.</param>
  646. <param name="accuracy">number of decimal places to write.</param>
  647. <returns>
  648. -
  649. </returns>
  650. <remarks>
  651. Wrapper for Player_AddToBuffer for floats. Uses custom code instead of
  652. format() as it's actually faster for something simple like this.
  653. </remarks>
  654. \**--------------------------------------------------------------------------**/
  655. stock Player_WriteFloat(name[], Float:data, accuracy = 6)
  656. {
  657. INI_WriteFloat(YSI_g_sPlayerWriteFile, name, data, accuracy);
  658. }
  659. stock Player_SetTag(tag[])
  660. {
  661. // Make sure we ALWAYS store mode tags with a special prefix.
  662. new
  663. tag2[MAX_INI_TAG] = "@@" #MODE_NAME "-";
  664. strcat(tag2, tag);
  665. INI_SetTag(YSI_g_sPlayerWriteFile, tag2);
  666. }
  667. stock Player_DeleteTag(tag[])
  668. {
  669. INI_DeleteTag(YSI_g_sPlayerWriteFile, tag);
  670. }
  671. stock _Player_ForceSave(playerid, bool:logout = false)
  672. {
  673. new
  674. uid = YSI_g_sPlayerYID[playerid],
  675. filename[64];
  676. format(filename, sizeof (filename), USER_FILE_PATH "%0" #MAX_INDEX_LENGTH "d.INI", uid);
  677. YSI_g_sPlayerWriteFile = INI_Open(filename);
  678. if (YSI_g_sPlayerWriteFile != INI_NO_FILE)
  679. {
  680. if (logout)
  681. {
  682. call OnPlayerLogout(playerid, uid);
  683. }
  684. // Now a first-class citizen and thus always called last.
  685. #if defined _Uvar_DoSavePlayer
  686. _Uvar_DoSavePlayer(playerid);
  687. #endif
  688. //CallLocalFunction("OnPlayerSaved", "ii", playerid, uid);
  689. INI_Close(YSI_g_sPlayerWriteFile);
  690. }
  691. return 1;
  692. }
  693. /**--------------------------------------------------------------------------**\
  694. <summary>Player_HashPass</summary>
  695. <param name="pass[]">Data to hash.</param>
  696. <returns>
  697. -
  698. </returns>
  699. <remarks>
  700. Based on my Dad's hash system but slightly modifed. Updated for reverse
  701. compatability with other login systems. Needs more code for Whirlpool.
  702. </remarks>
  703. \**--------------------------------------------------------------------------**/
  704. static stock Player_HashPass(pass[], target[])
  705. {
  706. #if defined PP_ADLER32
  707. new
  708. s1 = 1,
  709. s2 = 0,
  710. i,
  711. You_REALLY_shouldnt_use_Adler32;
  712. while (pass[i])
  713. {
  714. s1 = (s1 + pass[i++]) % 65521;
  715. s2 = (s2 + s1) % 65521;
  716. }
  717. format(target, sizeof (target), "%" #MAX_PASSWORD_LENGTH "d", (s2 << 16) + s1);
  718. #elseif defined PP_MD5 && defined MD5_Hash
  719. new
  720. You_REALLY_shouldnt_use_MD5;
  721. strcpy(target, MD5_Hash(pass, strlen(pass)));
  722. #elseif defined PP_SHA1
  723. #error SHA1 unsupported.
  724. #elseif defined PP_YSI
  725. static
  726. charset[] = "A,UbRgdnS#|rT_%5+ZvEK¬NF<9¦IH[(C)2O07 Y-Less]$Qw^?/om4;@'8k£Pp.c{&l\\3zay>DfxV:WXjuG6*!1\"i~=Mh`JB}qt",
  727. css = 99;
  728. new
  729. j,
  730. sum = j,
  731. tmp = 0,
  732. i,
  733. mod;
  734. j = strlen(pass);
  735. for (i = 0; i < MAX_PASSWORD_LENGTH || i < j; i++)
  736. {
  737. mod = i % MAX_PASSWORD_LENGTH;
  738. tmp = (i >= j) ? charset[(7 * i) % css] : pass[i];
  739. sum = (sum + chrfind(tmp, charset) + 1) % css;
  740. target[mod] = charset[(sum + target[mod]) % css];
  741. }
  742. target[MAX_PASSWORD_LENGTH] = '\0';
  743. #elseif defined WP_Hash
  744. WP_Hash(target, MAX_PASSWORD_LENGTH + 1, pass);
  745. #else
  746. #error Whirlpool (or other) hash not found.
  747. #endif
  748. }
  749. // Hooray for bizare bugs! I think this is because the function above is
  750. // secretly a macro with "if/else" and a block statement, not a real function.
  751. stock Player_SomeWeirdBugFix()
  752. {
  753. }
  754. /*stock Anything0()
  755. {
  756. }*/
  757. /*stock Anything1()
  758. {
  759. }
  760. stock Anything2()
  761. {
  762. }
  763. stock Anything3()
  764. {
  765. }*/
  766. /*stock Anything4()
  767. {
  768. }
  769. stock Anything5()
  770. {
  771. }
  772. stock Anything6()
  773. {
  774. }
  775. stock Anything7()
  776. {
  777. }*/
  778. /**--------------------------------------------------------------------------**\
  779. <summary>Player_TryRegister</summary>
  780. <param name="playerid">Player who is registering.</param>
  781. <param name="string:password[]">The password they entered.</param>
  782. <returns>
  783. -
  784. </returns>
  785. <remarks>
  786. Register the player with the given password if there is no-one else with the
  787. name already. Or log them in if the username and password match an existing
  788. account. Note that there is no "Player_ForceRegister" as it would do the
  789. same thing with no less parameters (a password MUST be given to write in the
  790. file).
  791. </remarks>
  792. \**--------------------------------------------------------------------------**/
  793. global Player_TryRegister(playerid, string:password[])
  794. {
  795. P:2("Player_TryRegister called");
  796. if (Player_IsLoggedIn(playerid))
  797. {
  798. // They are already logged in.
  799. Text_Send(playerid, $YSI_LOGIN_ALREADY);
  800. return 1;
  801. }
  802. new
  803. hash[MAX_PASSWORD_LENGTH + 1 + 8];
  804. Player_HashPass(password, hash);
  805. switch (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID])
  806. {
  807. case -2:
  808. {
  809. Text_Send(playerid, $YSI_LOGIN_INDERR);
  810. }
  811. case -1:
  812. {
  813. }
  814. default:
  815. {
  816. // Already registered, just try log them in.
  817. // Get the salt.
  818. format(hash[MAX_PASSWORD_LENGTH], sizeof (hash) - MAX_PASSWORD_LENGTH, "%04x%04x", YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] & 0xFFFF);
  819. Player_HashPass(hash, hash);
  820. // Match the password.
  821. if (!strcmp(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], hash, false, MAX_PASSWORD_LENGTH) && YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS][0])
  822. {
  823. // Extract the uid and call in to the login code.
  824. //YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS] = '\0';
  825. memset(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], 0, MAX_PASSWORD_LENGTH);
  826. Langs_SetPlayerLanguage(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_LANG]);
  827. broadcastfunc Player_DoLogin(playerid, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID]);
  828. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  829. return 1;
  830. }
  831. else
  832. {
  833. //Text_Send(playerid, $YSI_LOGIN_WRONG);
  834. Text_Send(playerid, $YSI_REG_TAKEN);
  835. return 0;
  836. }
  837. }
  838. }
  839. new
  840. name[MAX_PLAYER_NAME + 1];
  841. GetPlayerName(playerid, name, sizeof (name));
  842. //format(name, sizeof (name), "%" #MAX_PLAYER_NAME "s", name);
  843. new
  844. filename[64] = USER_FILE_PATH "ind_X.YSI",
  845. File:fIndex;//,
  846. //hash[MAX_PASSWORD_LENGTH + 1];
  847. //Player_HashPass(password, hash);
  848. Player_GetIndexFile(filename, name[0]);
  849. fIndex = fopen(filename, io_read);
  850. P:5("Player_TryRegister: fIndex");
  851. new
  852. line[INDEX_DATA_LINE_LENGTH];
  853. if ((fIndex = fopen(filename, io_append)))
  854. {
  855. P:5("Player_TryRegister: Write index.");
  856. // Write the new user to the index file.
  857. new
  858. uid = Player_GetNewID();
  859. if (uid == -1)
  860. {
  861. Text_Send(playerid, $YSI_LOGIN_INDERR);
  862. return 0;
  863. }
  864. new
  865. d = gettime(),
  866. date[9];
  867. format(date, sizeof (date), "%04x%04x", d >>> 16, d & 0xFFFF);
  868. strcat(hash, date);
  869. Player_HashPass(hash, hash);
  870. format(line, sizeof (line), "%0" #MAX_INDEX_LENGTH "d %" #MAX_PLAYER_NAME "s %" #MAX_PASSWORD_LENGTH "s %02s 00000000 %s" INI_NEW_LINE, uid, name, hash, Langs_GetCode(Langs_GetPlayerLanguage(playerid)), date);
  871. fwrite(fIndex, line);
  872. fclose(fIndex);
  873. format(filename, sizeof (filename), USER_FILE_PATH "%0" #MAX_INDEX_LENGTH "d.INI", uid);
  874. new
  875. INI:x = INI_Open(filename);
  876. if (x == INI_NO_FILE)
  877. {
  878. Text_Send(playerid, $YSI_LOGIN_NOLOAD);
  879. }
  880. else
  881. {
  882. INI_SetTag(x, "ysi_names");
  883. INI_WriteString(x, name, "name");
  884. INI_Close(x);
  885. }
  886. // Call in all scripts.
  887. broadcastfunc Player_DoLogin(playerid, uid);
  888. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  889. return 1;
  890. }
  891. else
  892. {
  893. Text_Send(playerid, $YSI_ADDU_INDER2);
  894. return 0;
  895. }
  896. }
  897. global Player_ChangePassword(playerid, string:password[])
  898. {
  899. #pragma unused password
  900. new
  901. uid = Player_GetYID(playerid);
  902. if (uid < 0)
  903. {
  904. return 0;
  905. }
  906. // Create the new password.
  907. new
  908. hash[MAX_PASSWORD_LENGTH + 8 + 1];
  909. Player_HashPass(password, hash);
  910. format(hash[MAX_PASSWORD_LENGTH], sizeof (hash) - MAX_PASSWORD_LENGTH, "%04x%04x", YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] & 0xFFFF);
  911. Player_HashPass(hash, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS]);
  912. // Save it.
  913. Player_RewritePreload(playerid);
  914. // Wipe it.
  915. memset(YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS], 0, MAX_PASSWORD_LENGTH);
  916. return 1;
  917. }
  918. global Player_ChangeLanguage(playerid, string:code[])
  919. {
  920. new
  921. uid = Player_GetYID(playerid);
  922. if (uid < 0)
  923. {
  924. return 0;
  925. }
  926. Langs_SetPlayerCode(playerid, code);
  927. Player_RewritePreload(playerid);
  928. return 1;
  929. }
  930. /**--------------------------------------------------------------------------**\
  931. <summary>Player_RewritePreload</summary>
  932. <param name="playerid">Player whose data should be saved.</param>
  933. <returns>
  934. -
  935. </returns>
  936. <remarks>
  937. When a player's preload data is modifed (new bit data or changed password),
  938. it needs to be written back out to file.
  939. </remarks>
  940. \**--------------------------------------------------------------------------**/
  941. static stock Player_RewritePreload(playerid)
  942. {
  943. if (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID] < 0)
  944. {
  945. return 0;
  946. }
  947. // First, find the player's file. This should be the ONLY place where the
  948. // password is to be loaded.
  949. //ret[E_USER_PRELOAD_YID] = -2;
  950. //ret[E_USER_PRELOAD_PASS] = '\0';
  951. //ret[E_USER_PRELOAD_LANG] = NO_LANGUAGE;
  952. //ret[E_USER_PRELOAD_BITS] = 0;
  953. //ret[E_USER_PRELOAD_DATE] = 0;
  954. new
  955. name[MAX_PLAYER_NAME + 1];
  956. GetPlayerName(playerid, name, sizeof (name));
  957. P:4("Player_RewritePreload called: %s", name);
  958. #if _YSI_PLUGINS_MYSQL == 7
  959. // Right then, lets get coding...
  960. new
  961. query[110];
  962. mysql_format(YSI_g_sMySQL, query, "SELECT `uid`, `language`, `hash` FROM `y_users_register` WHERE `name` = '%e' LIMIT 0,1", name);
  963. mysql_function_query(YSI_g_sMySQL, query, true, "_Player_Preload", "ii", );
  964. #else
  965. new
  966. namelen = strlen(name),
  967. filename[] = USER_FILE_PATH "ind_X.YSI",
  968. File:fIndex;
  969. Player_GetIndexFile(filename, name[0]);
  970. fIndex = fopen(filename, io_readwrite);
  971. if (fIndex)
  972. {
  973. P:5("Player_RewritePreload: fIndex OK");
  974. new
  975. line[INDEX_DATA_LINE_LENGTH],
  976. len;
  977. while ((len = fread(fIndex, line)))
  978. {
  979. P:6("Player_RewritePreload: while");
  980. //new
  981. // len;
  982. //len = strlen(line);
  983. // Check if the line is the right length (could be one of three
  984. // lengths depending on newlines). Skip blanks.
  985. if (len < INDEX_DATA_LINE_LENGTH - 3)
  986. {
  987. continue;
  988. }
  989. P:6("Player_RewritePreload: Not len");
  990. // Check the name on the line.
  991. if (!strcmp(line[MAX_INDEX_LENGTH + 1], name, false, namelen) && line[MAX_INDEX_LENGTH + 1 + namelen] == ' ')
  992. {
  993. P:6("Player_RewritePreload: checked name");
  994. fseek(fIndex, -len, seek_current);
  995. //format(line, sizeof (line),
  996. if (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS][0] == '\0')
  997. {
  998. // Keep the old password.
  999. format(line, sizeof (line),
  1000. "%0" #MAX_INDEX_LENGTH "d %" #MAX_PLAYER_NAME "s %" #MAX_PASSWORD_LENGTH "." #MAX_PASSWORD_LENGTH "s %02s %04x%04x %04x%04x" INI_NEW_LINE,
  1001. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID],
  1002. name,
  1003. line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1],
  1004. Langs_GetCode(Langs_GetPlayerLanguage(playerid)),
  1005. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS] & 0xFFFF,
  1006. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] & 0xFFFF);
  1007. }
  1008. else
  1009. {
  1010. format(line, sizeof (line),
  1011. "%0" #MAX_INDEX_LENGTH "d %" #MAX_PLAYER_NAME "s %" #MAX_PASSWORD_LENGTH "s %02s %04x%04x %04x%04x" INI_NEW_LINE,
  1012. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID],
  1013. name,
  1014. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_PASS],
  1015. Langs_GetCode(Langs_GetPlayerLanguage(playerid)),
  1016. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_BITS] & 0xFFFF,
  1017. YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] >>> 16, YSI_g_sPreloadData[playerid][E_USER_PRELOAD_DATE] & 0xFFFF);
  1018. }
  1019. P:5("Player_RewritePreload: Writing: %s", line);
  1020. fwrite(fIndex, line);
  1021. fclose(fIndex);
  1022. return 1;
  1023. }
  1024. }
  1025. fclose(fIndex);
  1026. }
  1027. else if (fexist(filename))
  1028. {
  1029. P:E("Error reading index %c.", filename[0]);
  1030. return 0;
  1031. }
  1032. //ret[E_USER_PRELOAD_YID] = -1;
  1033. #endif
  1034. return 0;
  1035. }
  1036. /**--------------------------------------------------------------------------**\
  1037. <summary>Player_TryGroup</summary>
  1038. <param name="playerid">Player who is joining a group.</param>
  1039. <param name="string:other[]">A player name already in the group.</param>
  1040. <param name="string:password[]">The password of the group.</param>
  1041. <returns>
  1042. -
  1043. </returns>
  1044. <remarks>
  1045. Links a player with an existing player such that they share all stats.
  1046. </remarks>
  1047. \**--------------------------------------------------------------------------**/
  1048. global Player_TryGroup(playerid, string:other[], string:password[])
  1049. {
  1050. P:2("Player_TryGroup called");
  1051. if (Player_IsLoggedIn(playerid))
  1052. {
  1053. // They are already logged in.
  1054. Text_Send(playerid, $YSI_LOGIN_ALREADY);
  1055. return 1;
  1056. }
  1057. new
  1058. hash[MAX_PASSWORD_LENGTH + 1];
  1059. Player_HashPass(password, hash);
  1060. // Check if the user is not registered already.
  1061. switch (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID])
  1062. {
  1063. case -2:
  1064. {
  1065. Text_Send(playerid, $YSI_LOGIN_INDERR);
  1066. return 0;
  1067. }
  1068. case -1:
  1069. {
  1070. //Text_Send(playerid, $YSI_LOGIN_NOTF);
  1071. }
  1072. default:
  1073. {
  1074. Text_Send(playerid, $YSI_REG_TAKEN);
  1075. return 0;
  1076. }
  1077. }
  1078. // Check if the new data matches the old.
  1079. new
  1080. ret[E_USER_PRELOAD];
  1081. Player_Preload(other, ret);
  1082. switch (ret[E_USER_PRELOAD_YID])
  1083. {
  1084. case -2:
  1085. {
  1086. Text_Send(playerid, $YSI_LOGIN_INDERR);
  1087. }
  1088. case -1:
  1089. {
  1090. Text_Send(playerid, $YSI_LOGIN_NOTF);
  1091. }
  1092. default:
  1093. {
  1094. // Match the password.
  1095. if (!strcmp(ret[E_USER_PRELOAD_PASS], hash, false, MAX_PASSWORD_LENGTH) && ret[E_USER_PRELOAD_PASS][0])
  1096. {
  1097. new
  1098. name[MAX_PLAYER_NAME + 1];
  1099. GetPlayerName(playerid, name, sizeof (name));
  1100. new
  1101. filename[64] = USER_FILE_PATH "ind_X.YSI";
  1102. Player_GetIndexFile(filename, name[0]);
  1103. new
  1104. File:fIndex = fopen(filename, io_append);
  1105. if (!fIndex)
  1106. {
  1107. Text_Send(playerid, $YSI_ADDU_INDERR2);
  1108. return 0;
  1109. }
  1110. P:5("Player_TryGroup: Write index.");
  1111. new
  1112. uid = ret[E_USER_PRELOAD_YID],
  1113. line[INDEX_DATA_LINE_LENGTH];
  1114. // Use the loaded ID.
  1115. format(line, sizeof (line), "%0" #MAX_INDEX_LENGTH "d %" #MAX_PLAYER_NAME "s %" #MAX_PASSWORD_LENGTH "s %02s" INI_NEW_LINE, uid, name, hash, Langs_GetCode(ret[E_USER_PRELOAD_LANG]));
  1116. fwrite(fIndex, line);
  1117. fclose(fIndex);
  1118. format(filename, sizeof (filename), USER_FILE_PATH "%0" #MAX_INDEX_LENGTH "d.INI", uid);
  1119. new
  1120. INI:x = INI_Open(filename);
  1121. if (x == INI_NO_FILE)
  1122. {
  1123. Text_Send(playerid, $YSI_LOGIN_NOLOAD);
  1124. }
  1125. else
  1126. {
  1127. // Add this name to the list of known names.
  1128. INI_SetTag(x, "ysi_names");
  1129. INI_WriteString(x, name, "name");
  1130. INI_Close(x);
  1131. }
  1132. // Call in all scripts.
  1133. Langs_SetPlayerLanguage(playerid, ret[E_USER_PRELOAD_LANG]);
  1134. broadcastfunc Player_DoLogin(playerid, uid);
  1135. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  1136. return 1;
  1137. }
  1138. else
  1139. {
  1140. Text_Send(playerid, $YSI_LOGIN_WRONG);
  1141. }
  1142. }
  1143. }
  1144. return 0;
  1145. }
  1146. /**--------------------------------------------------------------------------**\
  1147. <summary>Player_ForceGroup</summary>
  1148. <param name="playerid">Player who is joining a group.</param>
  1149. <param name="string:other[]">A player name already in the group.</param>
  1150. <returns>
  1151. -
  1152. </returns>
  1153. <remarks>
  1154. Like "Player_TryGroup", but doesn't take a password and instead just uses
  1155. the password of the old player (hashed).
  1156. </remarks>
  1157. \**--------------------------------------------------------------------------**/
  1158. global Player_ForceGroup(playerid, string:other[])
  1159. {
  1160. P:2("Player_ForceGroup called");
  1161. if (Player_IsLoggedIn(playerid))
  1162. {
  1163. // They are already logged in.
  1164. Text_Send(playerid, $YSI_LOGIN_ALREADY);
  1165. return 1;
  1166. }
  1167. // Check if the user is not registered already.
  1168. switch (YSI_g_sPreloadData[playerid][E_USER_PRELOAD_YID])
  1169. {
  1170. case -2:
  1171. {
  1172. Text_Send(playerid, $YSI_LOGIN_INDERR);
  1173. return 0;
  1174. }
  1175. case -1:
  1176. {
  1177. //Text_Send(playerid, $YSI_LOGIN_NOTF);
  1178. }
  1179. default:
  1180. {
  1181. Text_Send(playerid, $YSI_REG_TAKEN);
  1182. return 0;
  1183. }
  1184. }
  1185. // Check if the new data matches the old.
  1186. new
  1187. ret[E_USER_PRELOAD];
  1188. Player_Preload(other, ret);
  1189. switch (ret[E_USER_PRELOAD_YID])
  1190. {
  1191. case -2:
  1192. {
  1193. Text_Send(playerid, $YSI_LOGIN_INDERR);
  1194. }
  1195. case -1:
  1196. {
  1197. Text_Send(playerid, $YSI_LOGIN_NOTF);
  1198. }
  1199. default:
  1200. {
  1201. new
  1202. name[MAX_PLAYER_NAME + 1];
  1203. GetPlayerName(playerid, name, sizeof (name));
  1204. new
  1205. filename[64] = USER_FILE_PATH "ind_X.YSI";
  1206. Player_GetIndexFile(filename, name[0]);
  1207. new
  1208. File:fIndex = fopen(filename, io_append);
  1209. if (!fIndex)
  1210. {
  1211. Text_Send(playerid, $YSI_ADDU_INDERR2);
  1212. return 0;
  1213. }
  1214. P:5("Player_TryGroup: Write index.");
  1215. new
  1216. uid = ret[E_USER_PRELOAD_YID],
  1217. line[INDEX_DATA_LINE_LENGTH];
  1218. // Use the loaded ID.
  1219. format(line, sizeof (line), "%0" #MAX_INDEX_LENGTH "d %" #MAX_PLAYER_NAME "s %" #MAX_PASSWORD_LENGTH "s %02s" INI_NEW_LINE, uid, name, ret[E_USER_PRELOAD_PASS], Langs_GetCode(ret[E_USER_PRELOAD_LANG]));
  1220. fwrite(fIndex, line);
  1221. fclose(fIndex);
  1222. format(filename, sizeof (filename), USER_FILE_PATH "%0" #MAX_INDEX_LENGTH "d.INI", uid);
  1223. new
  1224. INI:x = INI_Open(filename);
  1225. if (x == INI_NO_FILE)
  1226. {
  1227. Text_Send(playerid, $YSI_LOGIN_NOLOAD);
  1228. }
  1229. else
  1230. {
  1231. // Add this name to the list of known names.
  1232. INI_SetTag(x, "ysi_names");
  1233. INI_WriteString(x, name, "name");
  1234. INI_Close(x);
  1235. }
  1236. // Call in all scripts.
  1237. Langs_SetPlayerLanguage(playerid, ret[E_USER_PRELOAD_LANG]);
  1238. broadcastfunc Player_DoLogin(playerid, uid);
  1239. Text_Send(playerid, $YSI_LOGIN_LOGIN);
  1240. return 1;
  1241. }
  1242. }
  1243. return 0;
  1244. }
  1245. static stock Player_GetNewID()
  1246. {
  1247. new
  1248. File:fHnd = fopen(USER_FILE_PATH "index.YSI", io_readwrite),
  1249. num[MAX_INDEX_LENGTH + 9],
  1250. uid = -1;
  1251. if (fHnd)
  1252. {
  1253. fread(fHnd, num);
  1254. num[strfind(num, " ")] = '\0';
  1255. uid = strval(num) + 1;
  1256. valstr(num, uid);
  1257. fseek(fHnd, 0, seek_start);
  1258. fwrite(fHnd, num);
  1259. fwrite(fHnd, " ");
  1260. fclose(fHnd);
  1261. }
  1262. return uid;
  1263. }
  1264. static stock Player_CreateNewID()
  1265. {
  1266. new
  1267. File:fHnd = fopen(USER_FILE_PATH "index.YSI", io_write);
  1268. if (fHnd)
  1269. {
  1270. fwrite(fHnd, "-1 ");
  1271. fclose(fHnd);
  1272. return 1;
  1273. }
  1274. return 0;
  1275. }
  1276. /*
  1277. 88 88 88
  1278. 88 88 88
  1279. 88 88 88
  1280. 88 88 8b,dPPYba, ,adPPYb,d8 8b,dPPYba, ,adPPYYba, ,adPPYb,88 ,adPPYba, ,adPPYba,
  1281. 88 88 88P' "8a a8" `Y88 88P' "Y8 "" `Y8 a8" `Y88 a8P_____88 I8[ ""
  1282. 88 88 88 d8 8b 88 88 ,adPPPPP88 8b 88 8PP""""""" `"Y8ba,
  1283. Y8a. .a8P 88b, ,a8" "8a, ,d88 88 88, ,88 "8a, ,d88 "8b, ,aa aa ]8I
  1284. `"Y8888Y"' 88`YbbdP"' `"YbbdP"Y8 88 `"8bbdP"Y8 `"8bbdP"Y8 `"Ybbd8"' `"YbbdP"'
  1285. 88 aa, ,88
  1286. 88 "Y8bbdP"
  1287. */
  1288. static stock Users_DoUpgrade0()
  1289. {
  1290. // Only ever do this upgrade once.
  1291. switch (ftouch(USER_FILE_PATH "y_users_v2_1.YSI"))
  1292. {
  1293. case -1:
  1294. {
  1295. P:E("Could not upgrade user files.");
  1296. }
  1297. case 1:
  1298. {
  1299. #if !defined YSI_DO_USER_UPGRADE
  1300. P:E("y_users needs to upgrade user files. Please back up the old ones and recompile/rerun once with YSI_DO_USER_UPGRADE.");
  1301. fremove(USER_FILE_PATH "y_users_v2_1.YSI");
  1302. #else
  1303. // Do the upgrade to add languages to all files (could take a
  1304. // little while, but needs doing).
  1305. P:I("Please wait, upgrading user files.");
  1306. new
  1307. ch,
  1308. filename[] = USER_FILE_PATH "ind_X.YSI",
  1309. File:f,
  1310. File:g,
  1311. line[INDEX_DATA_LINE_LENGTH],
  1312. //Language:def = Langs_GetLanguageAt(0),
  1313. code[3];
  1314. strcpy(code, Langs_GetCode(Langs_GetLanguageAt(0)));
  1315. for (new i = -2; i != 26; ++i)
  1316. {
  1317. if (i == -2)
  1318. {
  1319. ch = '_';
  1320. }
  1321. else if (i == -1)
  1322. {
  1323. ch = '0';
  1324. }
  1325. else
  1326. {
  1327. ch = 'a' + i;
  1328. }
  1329. Player_GetIndexFile(filename, ch);
  1330. f = fopen(filename, io_read);
  1331. if (!f)
  1332. {
  1333. if (fexist(filename))
  1334. {
  1335. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1336. }
  1337. continue;
  1338. }
  1339. g = ftemp();
  1340. if (!g)
  1341. {
  1342. fclose(f);
  1343. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1344. continue;
  1345. }
  1346. while ((ch = fread(f, line)))
  1347. {
  1348. //ch = strlen(line);
  1349. if (ch > 3)
  1350. {
  1351. if (line[ch - 2] < ' ')
  1352. {
  1353. // "/r/n" or "/n/r".
  1354. // Copy the existing line ending.
  1355. line[ch + 1] = line[ch - 2];
  1356. line[ch + 2] = line[ch - 1];
  1357. line[ch - 2] = ' ';
  1358. line[ch - 1] = code[0];
  1359. line[ch ] = code[1];
  1360. line[ch + 3] = '\0';
  1361. //line[ch - 1] = '\0';
  1362. fwrite(g, line);
  1363. }
  1364. else
  1365. {
  1366. // "/n" or "/r".
  1367. // Copy the existing line ending.
  1368. line[ch + 2] = line[ch - 1];
  1369. line[ch - 1] = ' ';
  1370. line[ch ] = code[0];
  1371. line[ch + 1] = code[1];
  1372. line[ch + 2] = '\0';
  1373. //line[ch - 1] = '\0';
  1374. fwrite(g, line);
  1375. }
  1376. }
  1377. }
  1378. fseek(g);
  1379. fclose(f);
  1380. fremove(filename);
  1381. f = fopen(filename, io_write);
  1382. if (!f)
  1383. {
  1384. fclose(g);
  1385. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1386. continue;
  1387. }
  1388. while (fread(g, line))
  1389. {
  1390. fwrite(f, line);
  1391. }
  1392. fclose(f);
  1393. fclose(g);
  1394. }
  1395. f = fopen(USER_FILE_PATH "index.YSI", io_append);
  1396. if (f)
  1397. {
  1398. fwrite(f, " ");
  1399. fclose(f);
  1400. }
  1401. else
  1402. {
  1403. P:E("Upgrade index failed.");
  1404. }
  1405. P:I("Upgrade complete.");
  1406. #endif
  1407. }
  1408. }
  1409. }
  1410. static stock Users_DoUpgrade1()
  1411. {
  1412. // Only ever do this upgrade once.
  1413. switch (ftouch(USER_FILE_PATH "y_users_v2_2.YSI"))
  1414. {
  1415. // case 0: Already exists.
  1416. case -1:
  1417. {
  1418. P:E("Could not upgrade user files.");
  1419. }
  1420. case 1:
  1421. {
  1422. #if !defined YSI_DO_USER_UPGRADE
  1423. P:E("y_users needs to upgrade user files. Please back up the old ones and recompile/rerun once with YSI_DO_USER_UPGRADE.");
  1424. fremove(USER_FILE_PATH "y_users_v2_2.YSI");
  1425. #else
  1426. // Do the upgrade to add languages to all files (could take a
  1427. // little while, but needs doing).
  1428. P:I("Please wait, upgrading user files.");
  1429. new
  1430. ch,
  1431. hash[MAX_PASSWORD_LENGTH + MAX_INDEX_LENGTH + 1],
  1432. filename[] = USER_FILE_PATH "ind_X.YSI",
  1433. File:f,
  1434. File:g,
  1435. line[INDEX_DATA_LINE_LENGTH],
  1436. //Language:def = Langs_GetLanguageAt(0),
  1437. code[3];
  1438. strcpy(code, Langs_GetCode(Langs_GetLanguageAt(0)));
  1439. for (new i = -2; i != 26; ++i)
  1440. {
  1441. if (i == -2)
  1442. {
  1443. ch = '_';
  1444. }
  1445. else if (i == -1)
  1446. {
  1447. ch = '0';
  1448. }
  1449. else
  1450. {
  1451. ch = 'a' + i;
  1452. }
  1453. Player_GetIndexFile(filename, ch);
  1454. f = fopen(filename, io_read);
  1455. if (!f)
  1456. {
  1457. if (fexist(filename))
  1458. {
  1459. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1460. }
  1461. continue;
  1462. }
  1463. g = ftemp();
  1464. if (!g)
  1465. {
  1466. fclose(f);
  1467. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1468. continue;
  1469. }
  1470. while (fread(f, line))
  1471. {
  1472. ch = strlen(line);
  1473. if (ch > 3)
  1474. {
  1475. // Get the current hash.
  1476. strcpy(hash, line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1], MAX_PASSWORD_LENGTH + 1);
  1477. //hash[MAX_PASSWORD_LENGTH] = '\0';
  1478. // Append their ID (not QUITE their join time, but
  1479. // best we can do retrospectively).
  1480. //line[MAX_INDEX_LENGTH] = '\0';
  1481. strcat(hash, line, sizeof (hash));
  1482. //line[MAX_INDEX_LENGTH] = ' ';
  1483. //hash[MAX_PASSWORD_LENGTH + MAX_INDEX_LENGTH] = '\0';
  1484. //printf("HASH 1: %s", hash);
  1485. Player_HashPass(hash, hash);
  1486. //printf("HASH 2: %s", hash);
  1487. // Copy the correct line ending.
  1488. if (line[ch - 2] < ' ')
  1489. {
  1490. format(line, sizeof (line), "%.*s %s %.2s 00000000 %.8s%s", MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME, line, hash, line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1], line[0], line[ch - 2]);
  1491. //format(line[ch - 2], 21, " 00000000 %.*s%s", MAX_INDEX_LENGTH, line[0], line[ch - 2]);
  1492. }
  1493. else
  1494. {
  1495. format(line, sizeof (line), "%.*s %s %.2s 00000000 %.8s%s", MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME, line, hash, line[MAX_INDEX_LENGTH + 1 + MAX_PLAYER_NAME + 1 + MAX_PASSWORD_LENGTH + 1], line[0], line[ch - 1]);
  1496. //format(line[ch - 1], 21, " 00000000 %.*s%s", MAX_INDEX_LENGTH, line[0], line[ch - 1]);
  1497. }
  1498. fwrite(g, line);
  1499. }
  1500. }
  1501. fseek(g);
  1502. fclose(f);
  1503. fremove(filename);
  1504. f = fopen(filename, io_write);
  1505. if (!f)
  1506. {
  1507. fclose(g);
  1508. P:E("Upgrade %c failed.", filename[USER_FILE_LENGTH + 4]);
  1509. continue;
  1510. }
  1511. while (fread(g, line))
  1512. {
  1513. fwrite(f, line);
  1514. }
  1515. fclose(f);
  1516. fclose(g);
  1517. }
  1518. f = fopen(USER_FILE_PATH "index.YSI", io_append);
  1519. if (f)
  1520. {
  1521. fwrite(f, " ");
  1522. fclose(f);
  1523. }
  1524. else
  1525. {
  1526. P:E("Upgrade index failed.");
  1527. }
  1528. P:I("Upgrade complete.");
  1529. #endif
  1530. }
  1531. }
  1532. }