BUD.inc 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595
  1. // BUD v0.1.5 RC1 by Slice
  2. #include <a_samp>
  3. #include <a_http>
  4. // :D
  5. #define BUD:: BUD_
  6. #define opt. opt_
  7. #define private stock static
  8. #define global stock
  9. // :D!
  10. #define BUD_Notice(%0) (printf("BUD - Notice: " %0))
  11. #define BUD_Warning(%0) (printf("BUD - Warning: " %0))
  12. #define BUD_Error(%0) (printf("BUD - Error: " %0))
  13. // This is so the constants can be defined before inclusion.
  14. #if !defined BUD_USE_WHIRLPOOL
  15. #define BUD_USE_WHIRLPOOL (false)
  16. #endif
  17. #if !defined BUD_MAX_DATABASE_NAME
  18. #define BUD_MAX_DATABASE_NAME (16)
  19. #endif
  20. #if !defined BUD_MAX_COLUMNS
  21. #define BUD_MAX_COLUMNS (12)
  22. #endif
  23. #if !defined BUD_MAX_COLUMN_NAME
  24. #define BUD_MAX_COLUMN_NAME (16)
  25. #endif
  26. #if !defined BUD_CHECK_STRING_LENGTH
  27. #define BUD_CHECK_STRING_LENGTH (false)
  28. #endif
  29. #if !defined BUD_MAX_ENTRY_STRING
  30. #define BUD_MAX_ENTRY_STRING (64)
  31. #endif
  32. #if !defined BUD_MULTIGET_MAX_ENTRIES
  33. #define BUD_MULTIGET_MAX_ENTRIES (16)
  34. #endif
  35. #if !defined BUD_MULTISET_MAX_ENTRIES
  36. #define BUD_MULTISET_MAX_ENTRIES (16)
  37. #endif
  38. #if !defined BUD_MULTISET_MAX_STRING_SIZE
  39. #define BUD_MULTISET_MAX_STRING_SIZE (BUD::MAX_ENTRY_STRING)
  40. #endif
  41. #if !defined BUD_MULTISET_BUFFER_SIZE
  42. #define BUD_MULTISET_BUFFER_SIZE (2048)
  43. #endif
  44. #if !defined BUD_BUFFER_SIZE
  45. #define BUD_BUFFER_SIZE (3072)
  46. #endif
  47. #define DEFAULT_DATABASE_NAME "bud.db" // No need to change this; do it via the settings instead.
  48. #define BUD_VERSION_MINOR 0
  49. #define BUD_VERSION_MAJOR 1
  50. #define BUD_VERSION_BUILD 5
  51. #define INVALID_DB (DB:0)
  52. #define BUD_NO_RESULT (DBResult:0)
  53. #define BUD_INVALID_UID (-1)
  54. #define BUD_Results:%0<%1> %0[%1][2]
  55. #if !defined cellbytes
  56. #define __undef_celbytes
  57. #define cellbytes (cellbits / 8)
  58. #endif
  59. enum BUD::e_COLUMN_TYPES {
  60. BUD::TYPE_NUMBER,
  61. BUD::TYPE_FLOAT,
  62. BUD::TYPE_STRING
  63. };
  64. enum BUD::e_OPTIONS {
  65. opt.Database,
  66. opt.Asynchronous,
  67. opt.KeepAliveTime,
  68. opt.IntEntryDefault,
  69. opt.FloatEntryDefault,
  70. opt.DatabaseOpenTimeOut,
  71. opt.CheckForUpdates
  72. };
  73. enum BUD::e_SORT_ORDER {
  74. BUD::SORT_ASC,
  75. BUD::SORT_DESC,
  76. BUD::SORT_ASCENDING = 0,
  77. BUD::SORT_DESCENDING
  78. };
  79. // No need to change this either; use BUD::VerifyColumn(column[], type) instead.
  80. #define DEFAULT_COLUMNS "uid INTEGER PRIMARY KEY, name TEXT, passhash BLOB"
  81. private
  82. bool:g_bIsInitialized = false,
  83. g_szDatabaseName[BUD::MAX_DATABASE_NAME] = "bud.db",
  84. g_iColumnCount,
  85. g_szColumnName[BUD::MAX_COLUMNS][BUD::MAX_COLUMN_NAME],
  86. DB:g_dbKeptAlive = INVALID_DB,
  87. g_iKeepAlive = 2000,
  88. g_iKeepAliveTimer = -1,
  89. bool:g_bAsynchronous = true,
  90. g_iIntEntryDefault = 0,
  91. Float:g_fFloatEntryDefault = 0.0,
  92. g_iDatabaseOpenTimeOut = 3000,
  93. bool:g_bCheckForUpdates = true,
  94. g_szBuffer[BUD::BUFFER_SIZE]
  95. ;
  96. // Prevent it from causing issues if WP_Hash is defined before or after this.
  97. #if (BUD::USE_WHIRLPOOL)
  98. #if defined WP_Hash
  99. #define BUD_WhirlpoolHash WP_Hash
  100. #else
  101. native BUD::WhirlpoolHash(buffer[], len = sizeof(buffer), const str[]) = WP_Hash;
  102. #endif
  103. #endif
  104. // Close the database connection when it has been unused for g_iKeepAlive ms
  105. private bool:BUD::GetDB() {
  106. if (g_iKeepAliveTimer == -1) {
  107. new
  108. iStartTick = GetTickCount()
  109. ;
  110. do
  111. g_dbKeptAlive = db_open(g_szDatabaseName);
  112. while (g_dbKeptAlive == INVALID_DB && GetTickCount() - iStartTick < g_iDatabaseOpenTimeOut);
  113. if (g_dbKeptAlive == INVALID_DB) {
  114. BUD::Error("Unable to open the database \"%s\".", g_szDatabaseName);
  115. return false;
  116. } else {
  117. if (g_bAsynchronous)
  118. db_query(g_dbKeptAlive, "PRAGMA synchronous = 0");
  119. else
  120. db_query(g_dbKeptAlive, "PRAGMA synchronous = 3");
  121. }
  122. } else {
  123. KillTimer(g_iKeepAliveTimer);
  124. }
  125. g_iKeepAliveTimer = SetTimer("BUD_CloseDB", g_iKeepAlive, false);
  126. return true;
  127. }
  128. forward BUD::CloseDB();
  129. public BUD::CloseDB() {
  130. g_iKeepAliveTimer = -1;
  131. db_close(g_dbKeptAlive);
  132. g_dbKeptAlive = INVALID_DB;
  133. }
  134. global BUD::Setting(BUD::e_OPTIONS:iSetting, _:...) {
  135. switch (iSetting) {
  136. case opt.Database: {
  137. if (g_bIsInitialized) {
  138. BUD::Warning("opt.Database has to be set before BUD::Initialize() is called.");
  139. return;
  140. }
  141. __getstringarg(g_szDatabaseName, 1);
  142. }
  143. case opt.Asynchronous: {
  144. new
  145. bool:bNewSetting = getarg(1) ? true : false
  146. ;
  147. if (g_bAsynchronous != bNewSetting) {
  148. g_bAsynchronous = bNewSetting;
  149. if (g_dbKeptAlive != INVALID_DB) {
  150. if (g_bAsynchronous)
  151. db_query(g_dbKeptAlive, "PRAGMA synchronous = 0");
  152. else
  153. db_query(g_dbKeptAlive, "PRAGMA synchronous = 3");
  154. }
  155. }
  156. }
  157. case opt.KeepAliveTime: {
  158. g_iKeepAlive = max(0, getarg(1));
  159. }
  160. case opt.IntEntryDefault: {
  161. g_iIntEntryDefault = getarg(1);
  162. }
  163. case opt.FloatEntryDefault: {
  164. g_fFloatEntryDefault = getarg(1);
  165. }
  166. case opt.DatabaseOpenTimeOut: {
  167. g_iDatabaseOpenTimeOut = getarg(1);
  168. }
  169. case opt.CheckForUpdates: {
  170. if (g_bIsInitialized) {
  171. BUD::Warning("opt.CheckForUpdates has to be set before BUD::Initialize() is called.");
  172. return;
  173. }
  174. g_bCheckForUpdates = getarg(1) ? true : false;
  175. }
  176. default: {
  177. BUD::Warning("Unknown setting ID passed in BUD::Setting (%d).", _:iSetting);
  178. }
  179. }
  180. }
  181. #if !(BUD::USE_WHIRLPOOL)
  182. #if !defined MAX_PASSWORD_LENGTH
  183. #define MAX_PASSWORD_LENGTH (64)
  184. #define UNDEFINE_MAX_PASSWORD_LENGTH (true)
  185. #else
  186. #define UNDEFINE_MAX_PASSWORD_LENGTH (false)
  187. #endif
  188. stock BUD::chrfind(needle, haystack[], start = 0) { // Y_Less
  189. while (haystack[start]) if (haystack[start++] == needle) return start - 1;
  190. return -1;
  191. }
  192. stock BUD::JSCHash(const __pass[],__passhash[MAX_PASSWORD_LENGTH + 1]) { // By JSC (Y_Less's dad); ported by Y_Less
  193. static
  194. __charset[] = \"4YLi6pOX)Mudvbc_IFVB/8HZ\2r(fGjaN0oU9C1Wywnq*smKQRxJDhkAS|53EzglT7tPe",
  195. __css = 69;
  196. new
  197. __j = strlen(__pass);
  198. new
  199. __sum = __j,
  200. __tmp = 0,
  201. __i,
  202. __mod;
  203. for (__i = 0; __i < MAX_PASSWORD_LENGTH || __i < __j; __i++) {
  204. __mod = __i % MAX_PASSWORD_LENGTH;
  205. __tmp = (__i >= __j) ? __charset[(7 * __i) % __css] : __pass[__i];
  206. __sum = (__sum + BUD::chrfind(__tmp, __charset) + 1) % __css;
  207. __passhash[__mod] = __charset[(__sum + __passhash[__mod]) % __css];
  208. }
  209. __passhash[MAX_PASSWORD_LENGTH] = '\0';
  210. }
  211. #else
  212. #define UNDEFINE_MAX_PASSWORD_LENGTH (false)
  213. #endif
  214. global bool:BUD::Initialize() {
  215. if (g_bIsInitialized) {
  216. BUD::Notice("Initialization aborted; BUD is already initialized.");
  217. return true;
  218. }
  219. #if (BUD::USE_WHIRLPOOL)
  220. new szBuffer[129];
  221. BUD::WhirlpoolHash(szBuffer, _, "I like cookies.");
  222. if (strcmp(szBuffer, "516A210D9C04CFE36568BEDA5287977572CCC618126B188B02F0BCFB92EE5B7EBA9F3D6DE2DE8FC0BB4C9E6111B93CF6482CCCD5639A94F125CFF7B829275933"))
  223. BUD::Warning("Whirlpool isn't behaving as expected; this might cause problems with the authentication.");
  224. #endif
  225. if (!g_szDatabaseName[0]) {
  226. BUD::Warning("The database name was not specified; default will be applied (\"" DEFAULT_DATABASE_NAME "\").");
  227. g_szDatabaseName = DEFAULT_DATABASE_NAME;
  228. }
  229. if (!fexist(g_szDatabaseName)) {
  230. BUD::Notice("The database \"%s\" doesn't exist; it will be created.", g_szDatabaseName);
  231. if (!BUD::CreateDatabase())
  232. return false;
  233. }
  234. BUD::ReloadTableInfo();
  235. BUD::IntegrityCheck();
  236. if (g_bCheckForUpdates)
  237. BUD::CheckForUpdates();
  238. g_bIsInitialized = true;
  239. printf("BUD v" #BUD::VERSION_MAJOR "." #BUD::VERSION_MINOR "." #BUD::VERSION_BUILD " BETA loaded.");
  240. return true;
  241. }
  242. global bool:BUD::Exit() {
  243. if (g_iKeepAliveTimer != -1) {
  244. KillTimer(g_iKeepAliveTimer);
  245. BUD::CloseDB();
  246. }
  247. g_bIsInitialized = false;
  248. }
  249. private BUD::IntegrityCheck() {
  250. if (!BUD::GetDB())
  251. return;
  252. new
  253. DBResult:dbrResult
  254. ;
  255. dbrResult = db_query(g_dbKeptAlive, "PRAGMA integrity_check");
  256. if (dbrResult) {
  257. new
  258. iRow,
  259. szField[64]
  260. ;
  261. do {
  262. db_get_field(dbrResult, 0, szField, sizeof(szField) - 1);
  263. if (iRow == 0 && !strcmp("ok", szField))
  264. break;
  265. else
  266. BUD::Warning("Database integrity check says: %s", szField);
  267. iRow++;
  268. }
  269. while (db_next_row(dbrResult));
  270. db_free_result(dbrResult);
  271. }
  272. }
  273. private BUD::CreateDatabase() {
  274. if (!BUD::GetDB())
  275. return false;
  276. db_query(g_dbKeptAlive, "CREATE TABLE users (" DEFAULT_COLUMNS ")");
  277. return true;
  278. }
  279. private BUD::ReloadTableInfo() {
  280. new
  281. DBResult:dbrResult
  282. ;
  283. if (!BUD::GetDB())
  284. return;
  285. dbrResult = db_query(g_dbKeptAlive, "PRAGMA table_info('users')");
  286. g_iColumnCount = 0;
  287. if (dbrResult) {
  288. new
  289. szColumnName[BUD::MAX_COLUMN_NAME]
  290. ;
  291. do {
  292. if (g_iColumnCount + 1 >= BUD::MAX_COLUMNS) {
  293. BUD::Warning("There are more columns in the \"users\" table than BUD::MAX_COLUMNS. Increase the limit!");
  294. break;
  295. }
  296. db_get_field(dbrResult, 1, szColumnName, BUD::MAX_COLUMN_NAME - 1);
  297. memcpy(g_szColumnName[g_iColumnCount++], szColumnName, .numbytes = (BUD::MAX_COLUMN_NAME * (cellbits / 8)));
  298. }
  299. while (db_next_row(dbrResult));
  300. db_free_result(dbrResult);
  301. } else
  302. BUD::Warning("Failed to get the table info from \"%s\"; some columns could be missing.", g_szDatabaseName);
  303. }
  304. global BUD::VerifyColumn(const szColumnName[], BUD::e_COLUMN_TYPES:iType, { _,Float }:...) {
  305. #if (BUD::CHECK_STRING_LENGTH)
  306. if (strlen(szColumnName) >= BUD::MAX_COLUMN_NAME)
  307. return false;
  308. #endif
  309. if (!(BUD::e_COLUMN_TYPES:0 <= iType <= BUD::e_COLUMN_TYPES)) {
  310. BUD::Error("Invalid type given to BUD::VerifyColumn.");
  311. return;
  312. }
  313. if (!g_iColumnCount) {
  314. BUD::Notice("Because the table info wasn't retrieved, columns cannot be verified.");
  315. return;
  316. }
  317. new
  318. bool:bColumnCreated = false
  319. ;
  320. recheck:
  321. for (new i = 0; i < g_iColumnCount; i++) {
  322. if (!strcmp(g_szColumnName[i], szColumnName, true))
  323. return;
  324. }
  325. if (!bColumnCreated) {
  326. BUD::Notice("The column \"%s\" doesn't exist; attempting to create it.", szColumnName);
  327. if (!BUD::GetDB())
  328. return;
  329. switch (iType) {
  330. case BUD::TYPE_NUMBER: {
  331. new
  332. iDefaultValue
  333. ;
  334. if (numargs() != 3)
  335. iDefaultValue = 0;
  336. else
  337. iDefaultValue = getarg(2);
  338. format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` INTEGER DEFAULT(%d)", szColumnName, iDefaultValue);
  339. }
  340. case BUD::TYPE_FLOAT: {
  341. new
  342. Float:fDefaultValue
  343. ;
  344. if (numargs() != 3)
  345. fDefaultValue = 0.0;
  346. else
  347. fDefaultValue = Float:getarg(2);
  348. format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` REAL DEFAULT(%f)", szColumnName, fDefaultValue);
  349. }
  350. case BUD::TYPE_STRING: {
  351. new
  352. szDefaultValue[BUD::MAX_ENTRY_STRING * 2]
  353. ;
  354. if (numargs() == 3) {
  355. __getstringarg(szDefaultValue, 2);
  356. szDefaultValue[BUD::MAX_ENTRY_STRING - 1] = EOS;
  357. BUD::EscapeSqlString(szDefaultValue);
  358. }
  359. format(g_szBuffer, sizeof(g_szBuffer), "ALTER TABLE `users` ADD COLUMN `%s` TEXT DEFAULT('%s')", szColumnName, szDefaultValue);
  360. }
  361. default: {
  362. return;
  363. }
  364. }
  365. db_free_result(
  366. db_query(g_dbKeptAlive, g_szBuffer)
  367. );
  368. bColumnCreated = true;
  369. BUD::ReloadTableInfo();
  370. goto recheck;
  371. }
  372. BUD::Error("Failed to create the column \"%s\"; this could be because of an invalid column name.", szColumnName);
  373. }
  374. global bool:BUD::IsNameRegistered(const szName[]) {
  375. #if (BUD::CHECK_STRING_LENGTH)
  376. if (strlen(szName) >= MAX_PLAYER_NAME)
  377. return false;
  378. #endif
  379. if (!BUD::GetDB())
  380. return true; // Better return true here to prevent any very circumstantial hijacking.
  381. new
  382. DBResult:dbrResult,
  383. bool:bIsRegistered = false
  384. ;
  385. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid` FROM `users` WHERE `name` = '%s' COLLATE NOCASE", szName);
  386. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  387. if (dbrResult) {
  388. if (db_num_rows(dbrResult) >= 1)
  389. bIsRegistered = true;
  390. db_free_result(dbrResult);
  391. }
  392. return bIsRegistered;
  393. }
  394. global bool:BUD::RegisterName(const szName[], const szPassword[]) {
  395. #if (BUD::CHECK_STRING_LENGTH)
  396. if (strlen(szName) >= MAX_PLAYER_NAME)
  397. return false;
  398. #endif
  399. if (BUD::IsNameRegistered(szName))
  400. return false;
  401. new
  402. #if (BUD::USE_WHIRLPOOL)
  403. szPasshash[129],
  404. #else
  405. szPasshash[MAX_PASSWORD_LENGTH + 1],
  406. #endif
  407. DBResult:dbrResult
  408. ;
  409. #if (BUD::USE_WHIRLPOOL)
  410. g_szBuffer = "INSERT INTO users(`name`, `passhash`) VALUES('";
  411. #else
  412. g_szBuffer = "INSERT INTO users(`name`, `passhash`) VALUES('";
  413. #endif
  414. if (!BUD::GetDB())
  415. return false;
  416. #if (BUD::USE_WHIRLPOOL)
  417. BUD::WhirlpoolHash(szPasshash, _, szPassword);
  418. #else
  419. BUD::JSCHash(szPassword, szPasshash);
  420. #endif
  421. strcat(g_szBuffer, szName);
  422. #if (BUD::USE_WHIRLPOOL)
  423. strcat(g_szBuffer, "', x'");
  424. #else
  425. strcat(g_szBuffer, "', '");
  426. #endif
  427. strcat(g_szBuffer, szPasshash);
  428. strcat(g_szBuffer, "')");
  429. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  430. if (dbrResult)
  431. db_free_result(dbrResult);
  432. if (BUD::IsNameRegistered(szName))
  433. return true;
  434. return false;
  435. }
  436. global BUD::UnregisterName(const szName[]) {
  437. #if (BUD::CHECK_STRING_LENGTH)
  438. if (strlen(szName) >= MAX_PLAYER_NAME)
  439. return false;
  440. #endif
  441. if (!BUD::IsNameRegistered(szName))
  442. return false;
  443. if (!BUD::GetDB())
  444. return false;
  445. g_szBuffer = "DELETE FROM `users` WHERE `name`='";
  446. strcat(g_szBuffer, szName);
  447. strcat(g_szBuffer, "' COLLATE NOCASE");
  448. db_query(g_dbKeptAlive, g_szBuffer);
  449. if (BUD::IsNameRegistered(szName))
  450. return false;
  451. return true;
  452. }
  453. global bool:BUD::CheckAuth(const szName[], const szPassword[]) {
  454. #if (BUD::CHECK_STRING_LENGTH)
  455. if (strlen(szName) >= MAX_PLAYER_NAME)
  456. return false;
  457. #endif
  458. if (!BUD::GetDB())
  459. return false;
  460. new
  461. #if (BUD::USE_WHIRLPOOL)
  462. szPasshash[129],
  463. #else
  464. szPasshash[MAX_PASSWORD_LENGTH + 1],
  465. #endif
  466. DBResult:dbrResult,
  467. bool:bAuthenticated = false
  468. ;
  469. #if (BUD::USE_WHIRLPOOL)
  470. g_szBuffer = "SELECT `uid` FROM `users` WHERE `name`='";
  471. #else
  472. g_szBuffer = "SELECT `uid` FROM `users` WHERE `name`='";
  473. #endif
  474. #if (BUD::USE_WHIRLPOOL)
  475. BUD::WhirlpoolHash(szPasshash, _, szPassword);
  476. #else
  477. BUD::JSCHash(szPassword, szPasshash);
  478. #endif
  479. strcat(g_szBuffer, szName);
  480. #if (BUD::USE_WHIRLPOOL)
  481. strcat(g_szBuffer, "' AND `passhash`=x'");
  482. #else
  483. strcat(g_szBuffer, "' AND `passhash`='");
  484. #endif
  485. strcat(g_szBuffer, szPasshash);
  486. strcat(g_szBuffer, "' COLLATE NOCASE");
  487. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  488. if (dbrResult) {
  489. if (db_num_rows(dbrResult) == 1)
  490. bAuthenticated = true;
  491. db_free_result(dbrResult);
  492. }
  493. return bAuthenticated;
  494. }
  495. global BUD::GetNameUID(const szName[]) {
  496. #if (BUD::CHECK_STRING_LENGTH)
  497. if (strlen(szName) >= BUD::MAX_PLAYER_NAME)
  498. return BUD::INVALID_UID;
  499. #endif
  500. if (!BUD::GetDB())
  501. return BUD::INVALID_UID;
  502. new
  503. DBResult:dbrResult
  504. ;
  505. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid` FROM `users` WHERE `name`='%s' COLLATE NOCASE", szName);
  506. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  507. if (dbrResult) {
  508. new
  509. iUID = BUD::INVALID_UID
  510. ;
  511. if (db_num_rows(dbrResult) == 1) {
  512. db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
  513. iUID = strval(g_szBuffer);
  514. }
  515. db_free_result(dbrResult);
  516. return iUID;
  517. }
  518. return BUD::INVALID_UID;
  519. }
  520. global Float:BUD::GetFloatEntry(iUID, const szColumn[]) {
  521. #if (BUD::CHECK_STRING_LENGTH)
  522. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  523. return g_fFloatEntryDefault;
  524. #endif
  525. if (!BUD::GetDB())
  526. return g_fFloatEntryDefault;
  527. new
  528. DBResult:dbrResult
  529. ;
  530. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
  531. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  532. if (dbrResult) {
  533. if (db_num_rows(dbrResult) == 1)
  534. db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
  535. else
  536. g_szBuffer[0] = EOS;
  537. db_free_result(dbrResult);
  538. if (g_szBuffer[0])
  539. return floatstr(g_szBuffer);
  540. }
  541. return g_fFloatEntryDefault;
  542. }
  543. global BUD::GetIntEntry(iUID, const szColumn[]) {
  544. #if (BUD::CHECK_STRING_LENGTH)
  545. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  546. return g_iIntEntryDefault;
  547. #endif
  548. if (!BUD::GetDB())
  549. return g_iIntEntryDefault;
  550. new
  551. DBResult:dbrResult
  552. ;
  553. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
  554. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  555. if (dbrResult) {
  556. if (db_num_rows(dbrResult) == 1)
  557. db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
  558. else
  559. g_szBuffer[0] = EOS;
  560. db_free_result(dbrResult);
  561. if (g_szBuffer[0])
  562. return strval(g_szBuffer);
  563. }
  564. return g_iIntEntryDefault;
  565. }
  566. global BUD::GetStringEntry(iUID, const szColumn[], szOutput[], iSize = sizeof(szOutput)) {
  567. #if (BUD::CHECK_STRING_LENGTH)
  568. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME) {
  569. szOutput[0] = EOS;
  570. return;
  571. }
  572. #endif
  573. if (!BUD::GetDB()) {
  574. szOutput[0] = EOS;
  575. return;
  576. }
  577. new
  578. DBResult:dbrResult
  579. ;
  580. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `%s` FROM `users` WHERE `uid`='%d'", szColumn, iUID);
  581. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  582. if (dbrResult) {
  583. if (db_num_rows(dbrResult) == 1)
  584. db_get_field(dbrResult, 0, szOutput, iSize - 1);
  585. else
  586. szOutput[0] = EOS;
  587. db_free_result(dbrResult);
  588. }
  589. }
  590. global bool:BUD::MultiGet(iUID, const szTypeDefinitions[], { _, Float }:...) {
  591. new
  592. iEntries = numargs() - 2
  593. ;
  594. if (iEntries & 0b1) {
  595. BUD::Error("A parameter is missing in BUD::MultiGet; expecting a variable in the end.", numargs() - 2);
  596. return false;
  597. }
  598. iEntries /= 2;
  599. if (iEntries > BUD::MULTIGET_MAX_ENTRIES) {
  600. BUD::Error("Too many entires passed to BUD::MultiGet; entires: %d, limit: %d.", iEntries, BUD::MULTIGET_MAX_ENTRIES);
  601. return false;
  602. }
  603. new
  604. iNumTypeDefinitions,
  605. iTypeDefinitions[BUD::MULTIGET_MAX_ENTRIES char],
  606. iTypeLengths[BUD::MULTIGET_MAX_ENTRIES]
  607. ;
  608. for (new i = 0, l = strlen(szTypeDefinitions); i < l; i++) {
  609. switch (szTypeDefinitions[i]) {
  610. case 'i', 'd', 'f': {
  611. iTypeDefinitions{ iNumTypeDefinitions++ } = szTypeDefinitions[i];
  612. }
  613. case 's': {
  614. if (szTypeDefinitions[i + 1] == '[' && szTypeDefinitions[i + 2]) {
  615. ++i;
  616. new
  617. szLength[11],
  618. iEndingBracket = strfind(szTypeDefinitions, "]", .pos = i + 2)
  619. ;
  620. if (iEndingBracket != -1) {
  621. strmid(szLength, szTypeDefinitions, i + 1, iEndingBracket);
  622. iTypeLengths[iNumTypeDefinitions] = strval(szLength);
  623. if (iTypeLengths[iNumTypeDefinitions] <= 0) {
  624. BUD::Error("Invalid string length given in the type definitions for BUD::MultiGet: %d.", iTypeLengths[iNumTypeDefinitions]);
  625. return false;
  626. }
  627. iTypeDefinitions{ iNumTypeDefinitions++ } = 's';
  628. i = iEndingBracket;
  629. continue;
  630. }
  631. }
  632. BUD::Error("String size has to be passed in the type definitions for BUD::MultiGet; example: \"iffs[32]ii\".", iNumTypeDefinitions, iEntries);
  633. return false;
  634. }
  635. default: {
  636. BUD::Error("Unknown type definition passed to BUD::MultiGet; expected: i/s/f, given: %c.", szTypeDefinitions[i]);
  637. return false;
  638. }
  639. }
  640. }
  641. if (iEntries != iNumTypeDefinitions) {
  642. BUD::Error("The number of type definitions doesn't match the number of entries passed to BUD::MultiGet; typedefs: %d, entries: %d.", iNumTypeDefinitions, iEntries);
  643. return false;
  644. }
  645. if (!BUD::GetDB())
  646. return false;
  647. new
  648. szColumn[BUD::MAX_COLUMN_NAME],
  649. iColumnArg
  650. ;
  651. g_szBuffer = "SELECT `";
  652. for (new iEntry = 0; iEntry < iEntries; iEntry++) {
  653. iColumnArg = 2 + iEntry * 2;
  654. __getstringarg(szColumn, iColumnArg);
  655. #if (BUD::CHECK_STRING_LENGTH)
  656. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  657. return false;
  658. #endif
  659. strcat(g_szBuffer, szColumn);
  660. if (iEntry < iEntries - 1)
  661. strcat(g_szBuffer, "`,`");
  662. }
  663. strcat(g_szBuffer, "` FROM `users` WHERE `uid`=");
  664. new
  665. szUID[11],
  666. DBResult:dbrResult
  667. ;
  668. valstr(szUID, iUID);
  669. strcat(g_szBuffer, szUID);
  670. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  671. if (dbrResult) {
  672. new
  673. iRows = db_num_rows(dbrResult)
  674. ;
  675. if (iRows == 1) {
  676. new
  677. iFields = db_num_fields(dbrResult)
  678. ;
  679. if (iEntries != iFields)
  680. BUD::Warning("The number of entries requested doesn't match the given number; requested: %d, given: %d", iEntries, iFields);
  681. for (new iField = 0; iField < iFields; iField++) {
  682. if (iTypeDefinitions{ iField } == 's')
  683. db_get_field(dbrResult, iField, g_szBuffer, iTypeLengths[iField] - 1);
  684. else
  685. db_get_field(dbrResult, iField, g_szBuffer, sizeof(g_szBuffer) - 1);
  686. switch (iTypeDefinitions{ iField }) {
  687. case 'i', 'd': {
  688. setarg(2 + iField * 2 + 1, .value = strval(g_szBuffer));
  689. }
  690. case 'f': {
  691. setarg(2 + iField * 2 + 1, .value = _:floatstr(g_szBuffer));
  692. }
  693. case 's': {
  694. __setstringarg(2 + iField * 2 + 1, g_szBuffer);
  695. }
  696. }
  697. }
  698. } else if (iRows > 1) {
  699. BUD::Error("Multiple rows fetched from one UID; UID: %d, rows: %d", iUID, iRows);
  700. db_free_result(dbrResult);
  701. return false;
  702. }
  703. db_free_result(dbrResult);
  704. return true;
  705. }
  706. return false;
  707. }
  708. global bool:BUD::MultiSet(iUID, const szTypeDefinitions[], { _, Float }:...) {
  709. new
  710. iEntries = numargs() - 2
  711. ;
  712. if (iEntries & 0b1) {
  713. BUD::Error("A parameter is missing in BUD::MultiSet; expecting a variable/value in the end.", numargs() - 2);
  714. return false;
  715. }
  716. iEntries /= 2;
  717. if (iEntries > BUD::MULTISET_MAX_ENTRIES) {
  718. BUD::Error("Too many entires passed to BUD::MultiSet; entires: %d, limit: %d.", iEntries, BUD::MULTISET_MAX_ENTRIES);
  719. return false;
  720. }
  721. new
  722. iNumTypeDefinitions = strlen(szTypeDefinitions)
  723. ;
  724. if (iEntries != iNumTypeDefinitions) {
  725. BUD::Error("The number of type definitions doesn't match the number of entries passed to BUD::MultiSet; typedefs: %d, entries: %d.", iNumTypeDefinitions, iEntries);
  726. return false;
  727. }
  728. for (new i = 0; i < iNumTypeDefinitions; i++) {
  729. switch (szTypeDefinitions[i]) {
  730. case 'i', 'd', 'f', 's': { }
  731. default: {
  732. BUD::Error("Unknown type definition passed to BUD::MultiSet; expected: i/s/f, given: %c.", szTypeDefinitions[i]);
  733. return false;
  734. }
  735. }
  736. }
  737. if (!BUD::GetDB())
  738. return false;
  739. new
  740. szColumn[BUD::MAX_COLUMN_NAME],
  741. iColumnArg,
  742. szValue[BUD::MULTISET_MAX_STRING_SIZE * 2]
  743. ;
  744. g_szBuffer = "UPDATE `users` SET ";
  745. for (new iEntry = 0; iEntry < iEntries; iEntry++) {
  746. iColumnArg = 2 + iEntry * 2;
  747. __getstringarg(szColumn, iColumnArg);
  748. ++iColumnArg;
  749. #if (BUD::CHECK_STRING_LENGTH)
  750. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  751. return false;
  752. #endif
  753. strcat(g_szBuffer, "`");
  754. strcat(g_szBuffer, szColumn);
  755. strcat(g_szBuffer, "`=");
  756. switch (szTypeDefinitions[iEntry]) {
  757. case 'i', 'd': {
  758. valstr(szValue, getarg(iColumnArg));
  759. }
  760. case 'f': {
  761. format(szValue, sizeof(szValue), "%f", Float:getarg(iColumnArg));
  762. }
  763. case 's': {
  764. __getstringarg(szValue, iColumnArg, BUD::MULTISET_MAX_STRING_SIZE);
  765. szValue[BUD::MULTISET_MAX_STRING_SIZE - 1] = EOS;
  766. BUD::EscapeSqlString(szValue);
  767. strcat(g_szBuffer, "'");
  768. }
  769. }
  770. strcat(g_szBuffer, szValue);
  771. if (szTypeDefinitions[iEntry] == 's')
  772. strcat(g_szBuffer, "'");
  773. if (iEntry < iEntries - 1)
  774. strcat(g_szBuffer, ", ");
  775. }
  776. valstr(szValue, iUID);
  777. strcat(g_szBuffer, " WHERE `uid`=");
  778. strcat(g_szBuffer, szValue);
  779. db_query(g_dbKeptAlive, g_szBuffer);
  780. return true;
  781. }
  782. global bool:BUD::SetIntEntry(iUID, const szColumn[], iInput) {
  783. #if (BUD::CHECK_STRING_LENGTH)
  784. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  785. return false;
  786. #endif
  787. if (!BUD::GetDB())
  788. return false;
  789. format(g_szBuffer, sizeof(g_szBuffer), "UPDATE `users` SET `%s`=%d WHERE `uid`=%d", szColumn, iInput, iUID);
  790. db_query(g_dbKeptAlive, g_szBuffer);
  791. return true;
  792. }
  793. global bool:BUD::SetFloatEntry(iUID, const szColumn[], Float:fInput) {
  794. #if (BUD::CHECK_STRING_LENGTH)
  795. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME)
  796. return false;
  797. #endif
  798. if (!BUD::GetDB())
  799. return false;
  800. format(g_szBuffer, sizeof(g_szBuffer), "UPDATE `users` SET `%s`=%f WHERE `uid`=%d", szColumn, fInput, iUID);
  801. db_query(g_dbKeptAlive, g_szBuffer);
  802. return true;
  803. }
  804. global bool:BUD::SetStringEntry(iUID, const szColumn[], const szInput[], iSize = sizeof(szInput)) {
  805. #if (BUD::CHECK_STRING_LENGTH)
  806. if (strlen(szColumn) >= BUD::MAX_COLUMN_NAME || strlen(szInput) >= BUD::MAX_ENTRY_STRING)
  807. return false;
  808. #endif
  809. if (!BUD::GetDB())
  810. return false;
  811. new
  812. szUID[11]
  813. ;
  814. memcpy(g_szBuffer, szInput, .numbytes = (iSize * (cellbits / 8))+4);
  815. BUD::EscapeSqlString(g_szBuffer);
  816. valstr(szUID, iUID);
  817. strins(g_szBuffer, "UPDATE `users` SET `", 0);
  818. strins(g_szBuffer, szColumn, 20);
  819. strins(g_szBuffer, "`='", 20 + strlen(szColumn));
  820. strcat(g_szBuffer, "' WHERE `uid`=");
  821. strcat(g_szBuffer, szUID);
  822. db_query(g_dbKeptAlive, g_szBuffer);
  823. return true;
  824. }
  825. global BUD::EscapeSqlString(szString[], iEnclosingChar = '\'', iSize = sizeof(szString)) {
  826. new
  827. iLength = strlen(szString),
  828. szInsert[2]
  829. ;
  830. szInsert[0] = iEnclosingChar;
  831. for (new i = 0; i <= iLength; i++) {
  832. if (szString[i] == iEnclosingChar) {
  833. if (i > iLength - 1) {
  834. szString[i] = EOS;
  835. break;
  836. } else {
  837. if (iLength >= iSize - 1) {
  838. szString[iLength - 1] = EOS;
  839. --iLength;
  840. }
  841. strins(szString, szInsert, i, iSize);
  842. ++iLength;
  843. ++i;
  844. }
  845. }
  846. }
  847. }
  848. global DBResult:BUD::RunQuery(szQuery[], bool:bStoreResult) {
  849. if (!BUD::GetDB()) {
  850. BUD::Error("No DB in BUD::RunQuery.");
  851. return BUD::NO_RESULT;
  852. }
  853. new
  854. DBResult:dbrResult = db_query(g_dbKeptAlive, szQuery)
  855. ;
  856. if (dbrResult) {
  857. if (bStoreResult) {
  858. SetTimerEx("BUD_FreeResult", 0, false, "i", _:dbrResult);
  859. return dbrResult;
  860. } else
  861. db_free_result(dbrResult);
  862. }
  863. return BUD::NO_RESULT;
  864. }
  865. forward BUD::FreeResult(DBResult:dbrResult);
  866. public BUD::FreeResult(DBResult:dbrResult) {
  867. db_free_result(dbrResult);
  868. }
  869. global BUD::GetSortedData(brResults[][], const szColumnName[], BUD::e_SORT_ORDER:iSortOrder = BUD::SORT_DESC, const szConditions[] = "", iResults = sizeof(brResults)) {
  870. if (!BUD::GetDB())
  871. return -1;
  872. new
  873. DBResult:dbrResult,
  874. iReturn = -1
  875. ;
  876. format(g_szBuffer, sizeof(g_szBuffer), "SELECT `uid`, `%s` FROM `users` %s ORDER BY `%s` %s LIMIT %d", szColumnName, szConditions, szColumnName, (BUD::SORT_ASC == iSortOrder) ? ("ASC") : ("DESC"), iResults);
  877. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  878. if (dbrResult) {
  879. if (db_num_rows(dbrResult) > 0) {
  880. new
  881. iIndex
  882. ;
  883. do {
  884. db_get_field(dbrResult, 0, g_szBuffer, sizeof(g_szBuffer) - 1);
  885. brResults[iIndex][0] = strval(g_szBuffer);
  886. db_get_field(dbrResult, 1, g_szBuffer, sizeof(g_szBuffer) - 1);
  887. brResults[iIndex][1] = strval(g_szBuffer);
  888. ++iIndex;
  889. }
  890. while (db_next_row(dbrResult) && iIndex < iResults);
  891. iReturn = iIndex;
  892. }
  893. db_free_result(dbrResult);
  894. }
  895. return iReturn;
  896. }
  897. global bool:BUD::GetNamesForSortedData(brResults[][], iResults, szaNames[][], iMaxName = sizeof(szaNames[])) {
  898. if (!BUD::GetDB())
  899. return false;
  900. new
  901. szUID[11],
  902. iUID,
  903. i,
  904. DBResult:dbrResult
  905. ;
  906. g_szBuffer = "SELECT `uid`, `name` FROM `users` WHERE `uid` IN (";
  907. for (i = 0; i < iResults; i++) {
  908. valstr(szUID, brResults[i][0]);
  909. strcat(g_szBuffer, szUID);
  910. if (i + 1 < iResults)
  911. strcat(g_szBuffer, ",");
  912. }
  913. strcat(g_szBuffer, ")");
  914. dbrResult = db_query(g_dbKeptAlive, g_szBuffer);
  915. if (dbrResult) {
  916. if (db_num_rows(dbrResult) > 0) {
  917. new
  918. iIndex,
  919. bool:bFound
  920. ;
  921. do {
  922. db_get_field(dbrResult, 0, szUID, sizeof(szUID) - 1);
  923. iUID = strval(szUID);
  924. bFound = false;
  925. for (i = 0; i < iResults; i++) {
  926. if (brResults[i][0] == iUID) {
  927. db_get_field(dbrResult, 1, szaNames[i], iMaxName - 1);
  928. bFound = true;
  929. break;
  930. }
  931. }
  932. if (!bFound) {
  933. new
  934. szName[MAX_PLAYER_NAME + 1]
  935. ;
  936. db_get_field(dbrResult, 1, szName, sizeof(szName) - 1);
  937. BUD::Warning("Unable to find the place for %s (%d) in BUD::GetNamesForSortedData.", szName, iUID);
  938. szaNames[i][0] = 0;
  939. strcat(szaNames[i], "UNKNOWN", iMaxName);
  940. }
  941. ++iIndex;
  942. }
  943. while (db_next_row(dbrResult) && iIndex < iResults);
  944. }
  945. db_free_result(dbrResult);
  946. return true;
  947. }
  948. return false;
  949. }
  950. forward BUD::funcinc();
  951. public BUD::funcinc() {
  952. new szNothing[1];
  953. strcat(szNothing, "");
  954. format(szNothing, 0, "");
  955. printf("");
  956. }
  957. global DBResult:BUD::RunQueryEx(const szQuery[], bool:bStoreResult = false, {Float, _}:...) {
  958. if (!BUD::GetDB()) {
  959. BUD::Error("No DB in BUD::RunQuery.");
  960. return BUD::NO_RESULT;
  961. }
  962. const
  963. STATIC_ARGS = 2
  964. ;
  965. new
  966. iPos = -1,
  967. iArg = STATIC_ARGS,
  968. iIndex = 0,
  969. iArgumentAddress,
  970. iArguments, // Number of arguments
  971. aiArguments[128] // Argument addresses
  972. ;
  973. static
  974. axArguments[128], // "x" as in any tag. Contains single cell arguments.
  975. s_szStringBuffer[10240 + 1] // The last cell is used to see if the buffer ran out of space; hence the + 1.
  976. ;
  977. s_szStringBuffer[0] = 0;
  978. while (-1 != (iPos = strfind(szQuery, "%", _, iPos))) {
  979. if (szQuery[++iPos] == '%')
  980. continue;
  981. while (szQuery[iPos]) {
  982. switch (szQuery[iPos]) {
  983. case 'a' .. 'z', 'A' .. 'Z':
  984. break;
  985. case ' ', '*', '.', '!', '-', '?', '0' .. '9': {
  986. iPos++;
  987. continue;
  988. }
  989. }
  990. }
  991. switch (szQuery[iPos]) {
  992. case '\0': {
  993. break;
  994. }
  995. case 's': {
  996. iIndex += strlen(s_szStringBuffer[iIndex]);
  997. if (iIndex)
  998. iIndex++;
  999. if (iIndex >= sizeof(s_szStringBuffer) - 1) {
  1000. BUD::Error("The string buffer in BUD::RunQueryEx is out of space. You must increase the size of it.");
  1001. return BUD::NO_RESULT;
  1002. }
  1003. __getstringarg(s_szStringBuffer[iIndex], iArg, sizeof(s_szStringBuffer) - iIndex);
  1004. if (s_szStringBuffer[sizeof(s_szStringBuffer) - 2]) {
  1005. BUD::Error("The string buffer in BUD::RunQueryEx ran out of space. You must increase the size of it.");
  1006. return BUD::NO_RESULT;
  1007. }
  1008. BUD::EscapeSqlString(s_szStringBuffer[iIndex], _, sizeof(s_szStringBuffer) - iIndex);
  1009. #emit CONST.pri s_szStringBuffer
  1010. #emit STOR.S.pri iArgumentAddress
  1011. iArgumentAddress += iIndex * 4;
  1012. aiArguments[iArguments++] = iArgumentAddress;
  1013. }
  1014. default: {
  1015. axArguments[iArg] = getarg(iArg);
  1016. #emit CONST.pri axArguments
  1017. #emit STOR.S.pri iArgumentAddress
  1018. iArgumentAddress += iArg * 4;
  1019. aiArguments[iArguments++] = iArgumentAddress;
  1020. }
  1021. }
  1022. iArg++;
  1023. if (iArg >= sizeof(axArguments) - 1) {
  1024. BUD::Error("Argument limit exceeded in BUD::RunQueryEx.");
  1025. return BUD::NO_RESULT;
  1026. }
  1027. }
  1028. new
  1029. iArgCount = (3 + iArguments) * 4,
  1030. i = iArguments,
  1031. iSize = sizeof(s_szStringBuffer)
  1032. ;
  1033. while (--i >= 0) {
  1034. iArg = aiArguments[i];
  1035. #emit PUSH.S iArg
  1036. }
  1037. #emit PUSH.S szQuery
  1038. #emit PUSH.S iSize
  1039. #emit CONST.pri s_szStringBuffer
  1040. #emit PUSH.pri
  1041. #emit PUSH.S iArgCount
  1042. #emit SYSREQ.C format
  1043. iArgCount += 4;
  1044. #emit LCTRL 4
  1045. #emit LOAD.S.alt iArgCount
  1046. #emit ADD
  1047. #emit SCTRL 4
  1048. new
  1049. DBResult:dbrResult = db_query(g_dbKeptAlive, s_szStringBuffer)
  1050. ;
  1051. if (dbrResult) {
  1052. if (bStoreResult) {
  1053. SetTimerEx("BUD_FreeResult", 0, false, "i", _:dbrResult);
  1054. return dbrResult;
  1055. } else
  1056. db_free_result(dbrResult);
  1057. }
  1058. return BUD::NO_RESULT;
  1059. }
  1060. // Inspired by Y_Less!
  1061. private BUD::CheckForUpdates() {
  1062. HTTP(0xFA7E, HTTP_GET, "spelsajten.net/bud_version.php?version=0x" #BUD_VERSION_MINOR #BUD_VERSION_MAJOR #BUD_VERSION_BUILD, "", "BUD_HTTPResponse");
  1063. }
  1064. forward BUD::HTTPResponse(iIndex, iResponseCode, szData[]);
  1065. public BUD::HTTPResponse(iIndex, iResponseCode, szData[]) {
  1066. if (iResponseCode == 200) {
  1067. switch (szData[0]) {
  1068. case '0': return; // Up-to-date
  1069. case '1': BUD::Notice("There is a new update available.");
  1070. case '2': BUD::Warning("There is a new version out; upgrading is strongly recommended.");
  1071. case '3': { // New version available; upgrading has to be done.
  1072. new
  1073. iTick = GetTickCount()
  1074. ;
  1075. BUD::Error("This version is outdated; you have to upgrade your script because of security reasons.");
  1076. SetGameModeText("LOOK AT THE SERVER LOG");
  1077. while (GetTickCount() - iTick < 3000) {}
  1078. SendRconCommand("exit");
  1079. }
  1080. }
  1081. } else {
  1082. if (iResponseCode < 100)
  1083. BUD::Notice("Unable to check for updates; internal error code %d.", iResponseCode);
  1084. else
  1085. BUD::Notice("Unable to check for updates; HTTP error code %d.", iResponseCode);
  1086. }
  1087. }
  1088. // Y_Less
  1089. private __getstringarg(dest[], arg, len = sizeof (dest))
  1090. {
  1091. // Get the address of the previous function's stack. First get the index of
  1092. // the argument required.
  1093. #emit LOAD.S.pri arg
  1094. // Then convert that number to bytes from cells.
  1095. #emit SMUL.C 4
  1096. // Get the previous function's frame. Stored in variable 0 (in the current
  1097. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  1098. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  1099. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  1100. // count (in C pointer speak).
  1101. #emit LOAD.S.alt 0
  1102. // Add the frame pointer to the argument offset in bytes.
  1103. #emit ADD
  1104. // Add 12 to skip over the function header.
  1105. #emit ADD.C 12
  1106. // Load the address stored in the specified address.
  1107. #emit LOAD.I
  1108. // Push the length for "strcat".
  1109. #emit PUSH.S len
  1110. // Push the address we just determined was the source.
  1111. #emit PUSH.pri
  1112. // Load the address of the destination.
  1113. #emit LOAD.S.alt dest
  1114. // Blank the first cell so "strcat" behaves like "strcpy".
  1115. #emit CONST.pri 0
  1116. // Store the loaded number 0 to the loaded address.
  1117. #emit STOR.I
  1118. // Push the loaded address.
  1119. #emit PUSH.alt
  1120. // Push the number of parameters passed (in bytes) to the function.
  1121. #emit PUSH.C 12
  1122. // Call the function.
  1123. #emit SYSREQ.C strcat
  1124. // Restore the stack to its level before we called this native.
  1125. #emit STACK 16
  1126. }
  1127. // Modification of above
  1128. stock __setstringarg(iArg, const szValue[], iLength = sizeof(szValue)) {
  1129. new
  1130. iAddress
  1131. ;
  1132. // Get the address of the previous function's stack. First get the index of
  1133. // the argument required.
  1134. #emit LOAD.S.pri iArg
  1135. // Then convert that number to bytes from cells.
  1136. #emit SMUL.C 4
  1137. // Get the previous function's frame.
  1138. #emit LOAD.S.alt 0
  1139. // Add the frame pointer to the argument offset in bytes.
  1140. #emit ADD
  1141. // Add 12 to skip over the function header.
  1142. #emit ADD.C 12
  1143. // Load the address stored in the specified address.
  1144. #emit LOAD.I
  1145. #emit STOR.S.PRI iAddress
  1146. // Push the length (last argument first)
  1147. #emit PUSH.S iLength
  1148. // Push the new value (source) szValue
  1149. #emit PUSH.S szValue
  1150. // Blank out the first cell of the argument
  1151. #emit CONST.pri 0
  1152. #emit SREF.S.pri iAddress
  1153. // Push the destination
  1154. #emit PUSH.S iAddress
  1155. // Push the number of parameters passed (in bytes) to the function.
  1156. #emit PUSH.C 12
  1157. // Call the function.
  1158. #emit SYSREQ.C strcat
  1159. // Restore the stack to its level before we called this native.
  1160. #emit STACK 16
  1161. }
  1162. #if (BUD::USE_WHIRLPOOL && UNDEFINE_MAX_PASSWORD_LENGTH)
  1163. #undef MAX_PASSWORD_LENGTH
  1164. #endif
  1165. #undef UNDEFINE_MAX_PASSWORD_LENGTH
  1166. #undef INVALID_DB
  1167. #undef DEFAULT_COLUMNS
  1168. #undef DEFAULT_DATABASE_NAME
  1169. #undef BUD_Notice
  1170. #undef BUD_Warning
  1171. #undef BUD_Error
  1172. #undef private
  1173. #undef global
  1174. #if defined __undef_celbytes
  1175. #undef __undef_celbytes
  1176. #undef cellbytes
  1177. #endif