/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/account.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/account.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 1998,1999,2000,2001 Ross Combs (rocombs@cs.nmsu.edu)
3 * Copyright (C) 2000,2001 Marco Ziech (mmz@gmx.net)
4 * Copyright (C) 2002,2003,2004 Mihai RUSU (dizzy@rdsnet.ro)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20 #define ACCOUNT_INTERNAL_ACCESS
21 #include "common/setup_before.h"
22 #include <stdio.h>
23 #ifdef HAVE_STDDEF_H
24 # include <stddef.h>
25 #else
26 # ifndef NULL
27 # define NULL ((void *)0)
28 # endif
29 #endif
30 #ifdef STDC_HEADERS
31 # include <stdlib.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 # include <string.h>
35 #else
36 # ifdef HAVE_STRINGS_H
37 # include <strings.h>
38 # endif
39 #endif
40 #include "compat/strchr.h"
41 #include "compat/strdup.h"
42 #include "compat/strcasecmp.h"
43 #include "compat/strncasecmp.h"
44 #include <ctype.h>
45 #ifdef HAVE_LIMITS_H
46 # include <limits.h>
47 #endif
48 #include "compat/char_bit.h"
49 #ifdef TIME_WITH_SYS_TIME
50 # include <sys/time.h>
51 # include <time.h>
52 #else
53 # ifdef HAVE_SYS_TIME_H
54 # include <sys/time.h>
55 # else
56 # include <time.h>
57 # endif
58 #endif
59 #include <errno.h>
60 #include "compat/strerror.h"
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
63 #endif
64 #include "compat/pdir.h"
65 #include "common/list.h"
66 #include "common/elist.h"
67 #include "common/eventlog.h"
68 #include "prefs.h"
69 #include "common/util.h"
70 #include "common/field_sizes.h"
71 #include "common/bnethash.h"
72 #include "common/introtate.h"
73 #include "account.h"
74 #include "account_wrap.h"
75 #include "common/hashtable.h"
76 #include "storage.h"
77 #include "connection.h"
78 #include "watch.h"
79 #include "friends.h"
80 #include "team.h"
81 #include "common/tag.h"
82 #include "ladder.h"
83 #include "clan.h"
84 #include "server.h"
85 #include "common/flags.h"
86 #include "common/xalloc.h"
87 #ifdef HAVE_ASSERT_H
88 # include <assert.h>
89 #endif
90 #include "common/setup_after.h"
91
92 static t_hashtable * accountlist_head=NULL;
93 static t_hashtable * accountlist_uid_head=NULL;
94
95 static t_account * default_acct=NULL;
96 unsigned int maxuserid=0;
97 static DECLARE_ELIST_INIT(dirtylist);
98 static DECLARE_ELIST_INIT(loadedlist);
99
100 /* This is to force the creation of all accounts when we initially load the accountlist. */
101 static int force_account_add=0;
102
103 static int doing_loadattrs=0;
104
105 static unsigned int account_hash(char const * username);
106 static int account_insert_attr(t_account * account, char const * key, char const * val);
107 static t_account * account_load(t_storage_info *);
108 static int account_load_attrs(t_account * account);
109 static void account_unload_attrs(t_account * account);
110 static int account_load_friends(t_account * account);
111 static int account_unload_friends(t_account * account);
112 static void account_destroy(t_account * account);
113 static t_account * accountlist_add_account(t_account * account);
114
115 static unsigned int account_hash(char const *username)
116 {
117 register unsigned int h;
118 register unsigned int len = strlen(username);
119
120 for (h = 5381; len > 0; --len, ++username) {
121 h += h << 5;
122 if (isupper((int) *username) == 0)
123 h ^= *username;
124 else
125 h ^= tolower((int) *username);
126 }
127 return h;
128 }
129
130 static inline void account_set_accessed(t_account *acc)
131 {
132 FLAG_SET(&acc->flags,ACCOUNT_FLAG_ACCESSED);
133 acc->lastaccess = now;
134 }
135
136 static inline void account_clear_accessed(t_account *acc)
137 {
138 FLAG_CLEAR(&acc->flags,ACCOUNT_FLAG_ACCESSED);
139 }
140
141 static inline void account_set_dirty(t_account *acc)
142 {
143 if (FLAG_ISSET(acc->flags,ACCOUNT_FLAG_DIRTY)) return;
144
145 acc->dirtytime = now;
146 FLAG_SET(&acc->flags,ACCOUNT_FLAG_DIRTY);
147 elist_add_tail(&dirtylist, &acc->dirtylist);
148 }
149
150 static inline void account_clear_dirty(t_account *acc)
151 {
152 if (!FLAG_ISSET(acc->flags,ACCOUNT_FLAG_DIRTY)) return;
153
154 FLAG_CLEAR(&acc->flags,ACCOUNT_FLAG_DIRTY);
155 elist_del(&acc->dirtylist);
156 }
157
158 static inline void account_set_loaded(t_account *acc)
159 {
160 if (FLAG_ISSET(acc->flags,ACCOUNT_FLAG_LOADED)) return;
161 FLAG_SET(&acc->flags,ACCOUNT_FLAG_LOADED);
162
163 if (acc == default_acct) return; /* don't add default_acct to loadedlist */
164 elist_add_tail(&loadedlist, &acc->loadedlist);
165 }
166
167 static inline void account_clear_loaded(t_account *acc)
168 {
169 if (!FLAG_ISSET(acc->flags,ACCOUNT_FLAG_LOADED)) return;
170
171 /* clear this because they are not valid if account is unloaded */
172 account_clear_dirty(acc);
173 account_clear_accessed(acc);
174
175 FLAG_CLEAR(&acc->flags,ACCOUNT_FLAG_LOADED);
176 if (acc == default_acct) return; /* default_acct is not in loadedlist */
177 elist_del(&acc->loadedlist);
178 }
179
180 static t_account * account_create(char const * username, char const * passhash1)
181 {
182 t_account * account;
183
184 if (username && !passhash1) {
185 eventlog(eventlog_level_error,__FUNCTION__,"got NULL passhash1");
186 return NULL;
187 }
188
189 if (username && account_check_name(username)) {
190 eventlog(eventlog_level_error,__FUNCTION__,"got invalid chars in username");
191 return NULL;
192 }
193
194 account = xmalloc(sizeof(t_account));
195
196 account->name = NULL;
197 account->storage = NULL;
198 account->clanmember = NULL;
199 account->attrs = NULL;
200 account->friends = NULL;
201 account->teams = NULL;
202 account->conn = NULL;
203 FLAG_ZERO(&account->flags);
204 account->lastaccess = 0;
205 account->dirtytime = 0;
206 elist_init(&account->dirtylist);
207 elist_init(&account->loadedlist);
208
209 account->namehash = 0; /* hash it later before inserting */
210 account->uid = 0; /* hash it later before inserting */
211
212 if (username) /* actually making a new account */
213 {
214 account->storage = storage->create_account(username);
215 if(!account->storage) {
216 eventlog(eventlog_level_error,__FUNCTION__,"failed to add user to storage");
217 goto err;
218 }
219 account_set_loaded(account);
220
221 account->name = xstrdup(username);
222
223 if (account_set_strattr(account,"BNET\\acct\\username",username)<0)
224 {
225 eventlog(eventlog_level_error,__FUNCTION__,"could not set username");
226 goto err;
227 }
228 if (account_set_numattr(account,"BNET\\acct\\userid",maxuserid+1)<0)
229 {
230 eventlog(eventlog_level_error,__FUNCTION__,"could not set userid");
231 goto err;
232 }
233 if (account_set_strattr(account,"BNET\\acct\\passhash1",passhash1)<0)
234 {
235 eventlog(eventlog_level_error,__FUNCTION__,"could not set passhash1");
236 goto err;
237 }
238
239 }
240
241 return account;
242
243 err:
244 account_destroy(account);
245 return NULL;
246 }
247
248
249 static void account_unload_attrs(t_account * account)
250 {
251 t_attribute const * attr;
252 t_attribute const * temp;
253
254 assert(account);
255
256 for (attr=account->attrs; attr; attr=temp)
257 {
258 if (attr->key)
259 xfree((void *)attr->key); /* avoid warning */
260 if (attr->val)
261 xfree((void *)attr->val); /* avoid warning */
262 temp = attr->next;
263 xfree((void *)attr); /* avoid warning */
264 }
265 account->attrs = NULL;
266 account_clear_loaded(account);
267 }
268
269 static void account_destroy(t_account * account)
270 {
271 if (!account)
272 {
273 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
274 return;
275 }
276 friendlist_close(account->friends);
277 teams_destroy(account->teams);
278 account_unload_attrs(account);
279 if (account->name)
280 xfree(account->name);
281 if (account->storage)
282 storage->free_info(account->storage);
283
284 xfree(account);
285 }
286
287
288 extern unsigned int account_get_uid(t_account const * account)
289 {
290 if (!account)
291 {
292 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
293 return -1;
294 }
295 return account->uid;
296 }
297
298
299 extern int account_match(t_account * account, char const * username)
300 {
301 unsigned int userid=0;
302 unsigned int namehash;
303 char const * tname;
304
305 if (!account)
306 {
307 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
308 return -1;
309 }
310 if (!username)
311 {
312 eventlog(eventlog_level_error,__FUNCTION__,"got NULL username");
313 return -1;
314 }
315
316 if (username[0]=='#')
317 if (str_to_uint(&username[1],&userid)<0)
318 userid = 0;
319
320 if (userid)
321 {
322 if (account->uid==userid)
323 return 1;
324 }
325 else
326 {
327 namehash = account_hash(username);
328 if (account->namehash==namehash &&
329 (tname = account_get_name(account)))
330 {
331 if (strcasecmp(tname,username)==0)
332 return 1;
333 }
334 }
335
336 return 0;
337 }
338
339
340 extern int account_save(t_account * account, unsigned flags)
341 {
342 assert(account);
343
344 if (!FLAG_ISSET(account->flags,ACCOUNT_FLAG_LOADED))
345 return 0;
346
347 if (!FLAG_ISSET(account->flags,ACCOUNT_FLAG_DIRTY))
348 return 0;
349
350 if (!FLAG_ISSET(flags,FS_FORCE) && now - account->dirtytime < prefs_get_user_sync_timer())
351 return 0;
352
353 if (!account->storage) {
354 eventlog(eventlog_level_error, __FUNCTION__, "account "UID_FORMAT" has NULL filename",account->uid);
355 return -1;
356 }
357
358 storage->write_attrs(account->storage, account->attrs);
359 account_clear_dirty(account);
360
361 return 1;
362 }
363
364
365 extern int account_flush(t_account * account, unsigned flags)
366 {
367 assert(account);
368
369 if (!FLAG_ISSET(account->flags,ACCOUNT_FLAG_LOADED))
370 return 0;
371
372 if (FLAG_ISSET(flags,FS_FORCE) && FLAG_ISSET(account->flags,ACCOUNT_FLAG_DIRTY))
373 if (account_save(account,FS_FORCE) < 0) return -1;
374
375 if (!FLAG_ISSET(flags,FS_FORCE) &&
376 FLAG_ISSET(account->flags,ACCOUNT_FLAG_ACCESSED) &&
377 now - account->lastaccess < prefs_get_user_flush_timer())
378 return 0;
379
380 account_unload_friends(account);
381 account_unload_attrs(account);
382
383 return 1;
384 }
385
386
387 static int account_insert_attr(t_account * account, char const * key, char const * val)
388 {
389 t_attribute * nattr;
390 char * nkey;
391 char * nval;
392
393 nattr = xmalloc(sizeof(t_attribute));
394
395 nkey = (char *)storage->escape_key(key);
396 if (nkey == key) nkey = xstrdup(key);
397 nval = xstrdup(val);
398 nattr->key = nkey;
399 nattr->val = nval;
400 nattr->dirty = 1;
401
402 nattr->next = account->attrs;
403
404 account->attrs = nattr;
405
406 account_set_dirty(account);
407
408 return 0;
409 }
410
411 extern char const * account_get_strattr_real(t_account * account, char const * key, char const * fn, unsigned int ln)
412 {
413 char const * newkey = key, *newkey2;
414 t_attribute * curr, *last, *last2;
415
416 if (!account)
417 {
418 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account (from %s:%u)",fn,ln);
419 return NULL;
420 }
421 if (!key)
422 {
423 eventlog(eventlog_level_error,__FUNCTION__,"got NULL key (from %s:%u)",fn,ln);
424 return NULL;
425 }
426
427 if (!FLAG_ISSET(account->flags,ACCOUNT_FLAG_LOADED))
428 {
429 if (account_load_attrs(account)<0)
430 {
431 eventlog(eventlog_level_error,__FUNCTION__,"could not load attributes");
432 return NULL;
433 }
434 }
435
436 account_set_accessed(account);
437
438 if (strncasecmp(key,"DynKey",6)==0)
439 {
440 char * temp;
441
442 /* Recent Starcraft clients seems to query DynKey\*\1\rank instead of
443 * Record\*\1\rank. So replace Dynkey with Record for key lookup.
444 */
445 temp = xstrdup(key);
446 strncpy(temp,"Record",6);
447 newkey = temp;
448 }
449 else if (strncmp(key,"Star",4)==0)
450 {
451 char * temp;
452
453 /* Starcraft clients query Star instead of STAR on logon screen.
454 */
455 temp = xstrdup(key);
456 strncpy(temp,"STAR",6);
457 newkey = temp;
458 }
459
460 if (newkey != key) {
461 newkey2 = storage->escape_key(newkey);
462 if (newkey2 != newkey) {
463 xfree((void*)newkey);
464 newkey = newkey2;
465 }
466 } else newkey = storage->escape_key(key);
467
468 last = NULL;
469 last2 = NULL;
470 if (account->attrs)
471 for (curr=account->attrs; curr; curr=curr->next) {
472 if (strcasecmp(curr->key,newkey)==0)
473 {
474 if (newkey!=key)
475 xfree((void *)newkey); /* avoid warning */
476 /* DIZZY: found a match, lets promote it so it would be found faster next time */
477 if (last) {
478 if (last2) {
479 last2->next = curr;
480 } else {
481 account->attrs = curr;
482 }
483
484 last->next = curr->next;
485 curr->next = last;
486
487 }
488 return curr->val;
489 }
490 last2 = last;
491 last = curr;
492 }
493
494 if ((curr = (t_attribute *)storage->read_attr(account->storage, newkey)) != NULL) {
495 curr->next = account->attrs;
496 account->attrs = curr;
497 if (newkey!=key) xfree((void *)newkey); /* avoid warning */
498 return curr->val;
499 }
500
501 if (newkey!=key) xfree((void *)newkey); /* avoid warning */
502
503 if (account==default_acct) /* don't recurse infinitely */
504 return NULL;
505
506 return account_get_strattr(default_acct,key); /* FIXME: this is sorta dangerous because this pointer can go away if we re-read the config files... verify that nobody caches non-username, userid strings */
507 }
508
509 extern int account_set_strattr(t_account * account, char const * key, char const * val)
510 {
511 t_attribute * curr;
512 const char *newkey;
513
514 if (!account)
515 {
516 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
517 return -1;
518 }
519 if (!key)
520 {
521 eventlog(eventlog_level_error,__FUNCTION__,"got NULL key");
522 return -1;
523 }
524
525 if (!FLAG_ISSET(account->flags,ACCOUNT_FLAG_LOADED))
526 {
527 if (account_load_attrs(account)<0)
528 {
529 eventlog(eventlog_level_error,__FUNCTION__,"could not load attributes");
530 return -1;
531 }
532 }
533 curr = account->attrs;
534 if (!curr) /* if no keys in attr list then we need to insert it */
535 {
536 if (val) return account_insert_attr(account,key,val);
537 return 0;
538 }
539
540 newkey = storage->escape_key(key);
541 if (strcasecmp(curr->key,newkey)==0) /* if key is already the first in the attr list */
542 {
543 if (val)
544 {
545 char * temp;
546
547 temp = xstrdup(val);
548
549 if (strcmp(curr->val,temp)!=0)
550 account_set_dirty(account);
551 xfree((void *)curr->val); /* avoid warning */
552 curr->val = temp;
553 curr->dirty = 1;
554 }
555 else
556 {
557 t_attribute * temp;
558
559 temp = curr->next;
560
561 account_set_dirty(account);
562 xfree((void *)curr->key); /* avoid warning */
563 xfree((void *)curr->val); /* avoid warning */
564 xfree((void *)curr); /* avoid warning */
565
566 account->attrs = temp;
567 }
568
569 if (key != newkey) xfree((void*)newkey);
570 return 0;
571 }
572
573 for (; curr->next; curr=curr->next)
574 if (strcasecmp(curr->next->key,newkey)==0)
575 break;
576
577 if (curr->next) /* if key is already in the attr list */
578 {
579 if (val)
580 {
581 char * temp;
582
583 temp = xstrdup(val);
584
585 if (strcmp(curr->next->val,temp)!=0)
586 {
587 account_set_dirty(account);
588 curr->next->dirty = 1;
589 }
590 xfree((void *)curr->next->val); /* avoid warning */
591 curr->next->val = temp;
592 }
593 else
594 {
595 t_attribute * temp;
596
597 temp = curr->next->next;
598
599 account_set_dirty(account);
600 xfree((void *)curr->next->key); /* avoid warning */
601 xfree((void *)curr->next->val); /* avoid warning */
602 xfree(curr->next);
603
604 curr->next = temp;
605 }
606
607 if (key != newkey) xfree((void*)newkey);
608 return 0;
609 }
610
611 if (key != newkey) xfree((void*)newkey);
612
613 if (val) return account_insert_attr(account,key,val);
614
615 return 0;
616 }
617
618 static int _cb_load_attr(const char *key, const char *val, void *data)
619 {
620 t_account *account = (t_account *)data;
621
622 return account_set_strattr(account, key, val);
623 }
624
625 static int account_load_attrs(t_account * account)
626 {
627 if (!account) {
628 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
629 return -1;
630 }
631
632 if (!account->storage) {
633 eventlog(eventlog_level_error,__FUNCTION__,"account has NULL filename");
634 return -1;
635 }
636
637
638 if (FLAG_ISSET(account->flags,ACCOUNT_FLAG_LOADED)) /* already done */
639 return 0;
640 if (FLAG_ISSET(account->flags,ACCOUNT_FLAG_DIRTY)) /* if not loaded, how dirty? */
641 {
642 eventlog(eventlog_level_error,__FUNCTION__,"can not load modified account");
643 return -1;
644 }
645
646 account_set_loaded(account); /* set now so set_strattr works */
647 doing_loadattrs = 1;
648 if (storage->read_attrs(account->storage, _cb_load_attr, account)) {
649 eventlog(eventlog_level_error, __FUNCTION__, "got error loading attributes");
650 return -1;
651 }
652 doing_loadattrs = 0;
653
654 account_clear_dirty(account);
655
656 return 0;
657 }
658
659 extern void accounts_get_attr(const char * attribute)
660 {
661 /* FIXME: do it */
662 }
663
664 static t_account * account_load(t_storage_info *storage)
665 {
666 t_account * account;
667
668 if (!(account = account_create(NULL,NULL)))
669 {
670 eventlog(eventlog_level_error,__FUNCTION__,"could not load account");
671 return NULL;
672 }
673
674 account->storage = storage;
675
676 return account;
677 }
678
679 extern int accountlist_load_default(void)
680 {
681 if (default_acct)
682 account_destroy(default_acct);
683
684 if (!(default_acct = account_load(storage->get_defacct())))
685 {
686 eventlog(eventlog_level_error,__FUNCTION__,"could not load default account template");
687 return -1;
688 }
689
690 if (account_load_attrs(default_acct)<0)
691 {
692 eventlog(eventlog_level_error,__FUNCTION__,"could not load default account template attributes");
693 return -1;
694 }
695
696 eventlog(eventlog_level_debug,__FUNCTION__,"loaded default account template");
697
698 return 0;
699 }
700
701 static t_account * account_load_new(char const * name, unsigned uid)
702 {
703 t_account *account;
704 t_storage_info *info;
705
706 if (name && account_check_name(name)) return NULL;
707
708 force_account_add = 1; /* disable the protection */
709 info = storage->read_account(name,uid);
710 if (!info) return NULL;
711
712 if (!(account = account_load(info)))
713 {
714 eventlog(eventlog_level_error, __FUNCTION__,"could not load account from storage");
715 storage->free_info(info);
716 return NULL;
717 }
718
719 if (!accountlist_add_account(account))
720 {
721 eventlog(eventlog_level_error, __FUNCTION__,"could not add account to list");
722 account_destroy(account);
723 return NULL;
724 }
725
726 force_account_add = 0;
727
728 return account;
729 }
730
731 static int _cb_read_accounts2(t_storage_info *info, void *data)
732 {
733 unsigned int *count = (unsigned int *)data;
734 t_account *account;
735
736 if (!(account = account_load(info)))
737 {
738 eventlog(eventlog_level_error, __FUNCTION__,"could not load account from storage");
739 storage->free_info(info);
740 return -1;
741 }
742
743 if (!accountlist_add_account(account))
744 {
745 eventlog(eventlog_level_error, __FUNCTION__,"could not add account to list");
746 account_destroy(account);
747 return -1;
748 }
749
750 /* might as well free up the memory since we probably won't need it */
751 account_flush(account,FS_FORCE); /* force unload */
752
753 (*count)++;
754
755 return 0;
756 }
757
758 extern int accountlist_load_all(int flag)
759 {
760 unsigned int count;
761 int starttime = time(NULL);
762 static int loaded = 0; /* all accounts already loaded ? */
763 int res;
764
765 if (loaded) return 0;
766
767 count = 0;
768 res = 0;
769
770 force_account_add = 1; /* disable the protection */
771 switch(storage->read_accounts(flag,_cb_read_accounts2, &count))
772 {
773 case -1:
774 eventlog(eventlog_level_error, __FUNCTION__,"got error reading users");
775 res = -1;
776 break;
777 case 0:
778 loaded = 1;
779 eventlog(eventlog_level_info, __FUNCTION__, "loaded %u user accounts in %ld seconds",count,time(NULL) - starttime);
780 break;
781 default:
782 break;
783 }
784 force_account_add = 0; /* enable the protection */
785
786 return res;
787 }
788
789 extern int accountlist_create(void)
790 {
791 eventlog(eventlog_level_info, __FUNCTION__, "started creating accountlist");
792
793 if (!(accountlist_head = hashtable_create(prefs_get_hashtable_size())))
794 {
795 eventlog(eventlog_level_error, __FUNCTION__, "could not create accountlist_head");
796 return -1;
797 }
798
799 if (!(accountlist_uid_head = hashtable_create(prefs_get_hashtable_size())))
800 {
801 eventlog(eventlog_level_error, __FUNCTION__, "could not create accountlist_uid_head");
802 return -1;
803 }
804
805 /* load accounts without force, indexed storage types wont be loading */
806 accountlist_load_all(ST_NONE);
807 maxuserid = storage->read_maxuserid();
808
809 return 0;
810 }
811
812
813 extern int accountlist_destroy(void)
814 {
815 t_entry * curr;
816 t_account * account;
817
818 HASHTABLE_TRAVERSE(accountlist_head,curr)
819 {
820 if (!(account = entry_get_data(curr)))
821 eventlog(eventlog_level_error,__FUNCTION__,"found NULL account in list");
822 else
823 {
824 if (account_flush(account, FS_FORCE)<0)
825 eventlog(eventlog_level_error,__FUNCTION__,"could not save account");
826
827 account_destroy(account);
828 }
829 hashtable_remove_entry(accountlist_head,curr);
830 }
831
832 HASHTABLE_TRAVERSE(accountlist_uid_head,curr)
833 {
834 hashtable_remove_entry(accountlist_head,curr);
835 }
836
837 if (hashtable_destroy(accountlist_head)<0)
838 return -1;
839 accountlist_head = NULL;
840 if (hashtable_destroy(accountlist_uid_head)<0)
841 return -1;
842 accountlist_uid_head = NULL;
843 return 0;
844 }
845
846
847 extern t_hashtable * accountlist(void)
848 {
849 return accountlist_head;
850 }
851
852 extern t_hashtable * accountlist_uid(void)
853 {
854 return accountlist_uid_head;
855 }
856
857
858 extern void accountlist_unload_default(void)
859 {
860 account_destroy(default_acct);
861 }
862
863
864 extern unsigned int accountlist_get_length(void)
865 {
866 return hashtable_get_length(accountlist_head);
867 }
868
869
870 extern int accountlist_save(unsigned flags)
871 {
872 static t_elist *curr = &dirtylist;
873 static t_elist *next = NULL;
874 t_account * account;
875 unsigned int scount;
876 unsigned int tcount;
877
878 scount = tcount = 0;
879 if (curr == &dirtylist || FLAG_ISSET(flags,FS_ALL)) {
880 curr = dirtylist.next;
881 next = curr->next;
882 }
883
884 /* elist_for_each_safe splitted into separate startup for userstep function */
885 for (; curr != &dirtylist; curr = next, next = curr->next)
886 {
887 if (!FLAG_ISSET(flags,FS_ALL) && tcount >= prefs_get_user_step()) break;
888 account = elist_entry(curr,t_account,dirtylist);
889 switch (account_save(account,flags))
890 {
891 case -1:
892 eventlog(eventlog_level_error, __FUNCTION__,"could not save account");
893 break;
894 case 1:
895 scount++;
896 break;
897 case 0:
898 default:
899 break;
900 }
901 tcount++;
902 }
903
904 if (scount>0)
905 eventlog(eventlog_level_debug, __FUNCTION__,"saved %u of %u user accounts",scount,tcount);
906
907 if (!FLAG_ISSET(flags,FS_ALL) && curr != &dirtylist) return 1;
908
909 return 0;
910 }
911
912 extern int accountlist_flush(unsigned flags)
913 {
914 static t_elist *curr = &loadedlist;
915 static t_elist *next = NULL;
916 t_account * account;
917 unsigned int fcount;
918 unsigned int tcount;
919
920 fcount = tcount = 0;
921 if (curr == &loadedlist || FLAG_ISSET(flags,FS_ALL)) {
922 curr = loadedlist.next;
923 next = curr->next;
924 }
925
926 /* elist_for_each_safe splitted into separate startup for userstep function */
927 for (; curr != &loadedlist; curr = next, next = curr->next)
928 {
929 if (!FLAG_ISSET(flags,FS_ALL) && tcount >= prefs_get_user_step()) break;
930 account = elist_entry(curr,t_account,loadedlist);
931 switch (account_flush(account,flags))
932 {
933 case -1:
934 eventlog(eventlog_level_error, __FUNCTION__,"could not flush account");
935 break;
936 case 1:
937 fcount++;
938 break;
939 case 0:
940 default:
941 break;
942 }
943 tcount++;
944 }
945
946 if (fcount>0)
947 eventlog(eventlog_level_debug, __FUNCTION__,"flushed %u of %u user accounts",fcount,tcount);
948
949 if (!FLAG_ISSET(flags,FS_ALL) && curr != &loadedlist) return 1;
950
951 return 0;
952 }
953
954 extern t_account * accountlist_find_account(char const * username)
955 {
956 unsigned int userid=0;
957 t_entry * curr;
958 t_account * account;
959
960 if (!username)
961 {
962 eventlog(eventlog_level_error,__FUNCTION__,"got NULL username");
963 return NULL;
964 }
965
966 if (username[0]=='#') {
967 if (str_to_uint(&username[1],&userid)<0)
968 userid = 0;
969 } else if (!(prefs_get_savebyname()))
970 if (str_to_uint(username,&userid)<0)
971 userid = 0;
972
973 /* all accounts in list must be hashed already, no need to check */
974
975 if (userid) {
976 account=accountlist_find_account_by_uid(userid);
977 if (account) return account;
978 }
979
980 if ((!(userid)) || (userid && ((username[0]=='#') || (isdigit((int)username[0])))))
981 {
982 unsigned int namehash;
983 char const * tname;
984
985 namehash = account_hash(username);
986 HASHTABLE_TRAVERSE_MATCHING(accountlist_head,curr,namehash)
987 {
988 account = entry_get_data(curr);
989 if ((tname = account_get_name(account)))
990 {
991 if (strcasecmp(tname,username)==0)
992 {
993 hashtable_entry_release(curr);
994 return account;
995 }
996 }
997 }
998 }
999
1000 return account_load_new(username,0);
1001 }
1002
1003
1004 extern t_account * accountlist_find_account_by_uid(unsigned int uid)
1005 {
1006 t_entry * curr;
1007 t_account * account;
1008
1009 if (uid) {
1010 HASHTABLE_TRAVERSE_MATCHING(accountlist_uid_head,curr,uid)
1011 {
1012 account = entry_get_data(curr);
1013 if (account->uid==uid) {
1014 hashtable_entry_release(curr);
1015 return account;
1016 }
1017 }
1018 }
1019 return account_load_new(NULL,uid);
1020 }
1021
1022
1023 extern int accountlist_allow_add(void)
1024 {
1025 if (force_account_add)
1026 return 1; /* the permission was forced */
1027
1028 if (prefs_get_max_accounts()==0)
1029 return 1; /* allow infinite accounts */
1030
1031 if (prefs_get_max_accounts()<=hashtable_get_length(accountlist_head))
1032 return 0; /* maximum account limit reached */
1033
1034 return 1; /* otherwise let them proceed */
1035 }
1036
1037 static t_account * accountlist_add_account(t_account * account)
1038 {
1039 unsigned int uid;
1040 char const * username;
1041
1042 if (!account) {
1043 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1044 return NULL;
1045 }
1046
1047 username = account_get_name(account);
1048 uid = account_get_numattr(account,"BNET\\acct\\userid");
1049
1050 if (!username || strlen(username)<1) {
1051 eventlog(eventlog_level_error,__FUNCTION__,"got bad account (empty username)");
1052 return NULL;
1053 }
1054 if (uid<1) {
1055 eventlog(eventlog_level_error,__FUNCTION__,"got bad account (bad uid), fix it!");
1056 uid = maxuserid + 1;
1057 }
1058
1059 /* check whether the account limit was reached */
1060 if (!accountlist_allow_add()) {
1061 eventlog(eventlog_level_warn,__FUNCTION__,"account limit reached (current is %u, storing %u)",prefs_get_max_accounts(),hashtable_get_length(accountlist_head));
1062 return NULL;
1063 }
1064
1065 /* delayed hash, do it before inserting account into the list */
1066 account->namehash = account_hash(username);
1067 account->uid = uid;
1068
1069 /* mini version of accountlist_find_account(username) || accountlist_find_account(uid) */
1070 {
1071 t_entry * curr;
1072 t_account * curraccount;
1073 char const * tname;
1074
1075 if(uid <= maxuserid)
1076 HASHTABLE_TRAVERSE_MATCHING(accountlist_uid_head,curr,uid)
1077 {
1078 curraccount = entry_get_data(curr);
1079 if (curraccount->uid==uid)
1080 {
1081 eventlog(eventlog_level_debug,__FUNCTION__,"user \"%s\":"UID_FORMAT" already has an account (\"%s\":"UID_FORMAT")",username,uid,account_get_name(curraccount),curraccount->uid);
1082 hashtable_entry_release(curr);
1083 return NULL;
1084 }
1085 }
1086
1087 HASHTABLE_TRAVERSE_MATCHING(accountlist_head,curr,account->namehash)
1088 {
1089 curraccount = entry_get_data(curr);
1090 if ((tname = account_get_name(curraccount)))
1091 {
1092 if (strcasecmp(tname,username)==0)
1093 {
1094 eventlog(eventlog_level_debug,__FUNCTION__,"user \"%s\":"UID_FORMAT" already has an account (\"%s\":"UID_FORMAT")",username,uid,tname,curraccount->uid);
1095 hashtable_entry_release(curr);
1096 return NULL;
1097 }
1098 }
1099 }
1100 }
1101
1102 if (hashtable_insert_data(accountlist_head,account,account->namehash)<0) {
1103 eventlog(eventlog_level_error,__FUNCTION__,"could not add account to list");
1104 return NULL;
1105 }
1106
1107 if (hashtable_insert_data(accountlist_uid_head,account,uid)<0) {
1108 eventlog(eventlog_level_error,__FUNCTION__,"could not add account to list");
1109 return NULL;
1110 }
1111
1112 /* hashtable_stats(accountlist_head); */
1113
1114 if (uid>maxuserid)
1115 maxuserid = uid;
1116
1117 return account;
1118 }
1119
1120 extern t_account * accountlist_create_account(const char *username, const char *passhash1)
1121 {
1122 t_account *res;
1123
1124 assert(username != NULL);
1125 assert(passhash1 != NULL);
1126
1127 res = account_create(username,passhash1);
1128 if (!res) return NULL; /* eventlog reported ealier */
1129
1130 if (!accountlist_add_account(res)) {
1131 account_destroy(res);
1132 return NULL; /* eventlog reported earlier */
1133 }
1134
1135 account_save(res,FS_FORCE); /* sync new account to storage */
1136
1137 return res;
1138 }
1139
1140 extern char const * account_get_first_key(t_account * account)
1141 {
1142 if (!account) {
1143 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1144 return NULL;
1145 }
1146 if (!account->attrs) {
1147 return NULL;
1148 }
1149 return account->attrs->key;
1150 }
1151
1152 extern char const * account_get_next_key(t_account * account, char const * key)
1153 {
1154 t_attribute * attr;
1155
1156 if (!account) {
1157 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1158 return NULL;
1159 }
1160 attr = account->attrs;
1161 while (attr) {
1162 if (strcmp(attr->key,key)==0) {
1163 if (attr->next) {
1164 return attr->next->key;
1165 } else {
1166 return NULL;
1167 }
1168 }
1169 attr = attr->next;
1170 }
1171
1172 return NULL;
1173 }
1174
1175
1176 extern int account_check_name(char const * name)
1177 {
1178 unsigned int i;
1179 char ch;
1180
1181 if (!name) {
1182 eventlog(eventlog_level_error, __FUNCTION__,"got NULL name");
1183 return -1;
1184 }
1185
1186 for (i=0; i<strlen(name); i++)
1187 {
1188 /* These are the Battle.net rules but they are too strict.
1189 * We want to allow any characters that wouldn't cause
1190 * problems so this should test for what is _not_ allowed
1191 * instead of what is.
1192 */
1193 ch = name[i];
1194 /* hardcoded safety checks */
1195 if (ch == '/' || ch == '\\') return -1;
1196 if (isalnum((int)ch)) continue;
1197 if (strchr(prefs_get_account_allowed_symbols(),ch)) continue;
1198 return -1;
1199 }
1200 if (i<USER_NAME_MIN || i>=USER_NAME_MAX)
1201 return -1;
1202 return 0;
1203 }
1204
1205 extern char const * account_get_name_real(t_account * account, char const * fn, unsigned int ln)
1206 {
1207 char const * temp;
1208
1209 if (!account)
1210 {
1211 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account (from %s:%u)",fn,ln);
1212 return NULL; /* FIXME: places assume this can't fail */
1213 }
1214
1215 if (account->name) /* we have a cached username so return it */
1216 return account->name;
1217
1218 /* we dont have a cached username so lets get it from attributes */
1219 if (!(temp = account_get_strattr(account,"BNET\\acct\\username")))
1220 eventlog(eventlog_level_error,__FUNCTION__,"account has no username");
1221 else
1222 account->name = xstrdup(temp);
1223 return account->name;
1224 }
1225
1226
1227 extern int account_check_mutual( t_account * account, int myuserid)
1228 {
1229 if (account == NULL) {
1230 eventlog(eventlog_level_error, __FUNCTION__, "got NULL account");
1231 return -1;
1232 }
1233
1234 if(!myuserid) {
1235 eventlog(eventlog_level_error,__FUNCTION__,"got NULL userid");
1236 return -1;
1237 }
1238
1239 if(account->friends!=NULL)
1240 {
1241 t_friend * fr;
1242 if((fr=friendlist_find_uid(account->friends, myuserid))!=NULL)
1243 {
1244 friend_set_mutual(fr, 1);
1245 return 0;
1246 }
1247 }
1248 else
1249 {
1250 int i;
1251 int n = account_get_friendcount(account);
1252 int friend;
1253 for(i=0; i<n; i++)
1254 {
1255 friend = account_get_friend(account,i);
1256 if(!friend) {
1257 eventlog(eventlog_level_error,__FUNCTION__,"got NULL friend");
1258 continue;
1259 }
1260
1261 if(myuserid==friend)
1262 return 0;
1263 }
1264 }
1265
1266 // If friend isnt in list return -1 to tell func NO
1267 return -1;
1268 }
1269
1270 extern t_list * account_get_friends(t_account * account)
1271 {
1272 if (!account)
1273 {
1274 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1275 return NULL;
1276 }
1277
1278 if(!FLAG_ISSET(account->flags,ACCOUNT_FLAG_FLOADED))
1279 if(account_load_friends(account)<0)
1280 {
1281 eventlog(eventlog_level_error,__FUNCTION__,"could not load friend list");
1282 return NULL;
1283 }
1284
1285 return account->friends;
1286 }
1287
1288 static int account_load_friends(t_account * account)
1289 {
1290 int i;
1291 int n;
1292 int friend;
1293 t_account * acc;
1294 t_friend * fr;
1295
1296 int newlist=0;
1297 if (!account)
1298 {
1299 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1300 return -1;
1301 }
1302
1303 if(FLAG_ISSET(account->flags,ACCOUNT_FLAG_FLOADED))
1304 return 0;
1305
1306 if(account->friends==NULL)
1307 {
1308 account->friends=list_create();
1309 newlist=1;
1310 }
1311
1312 n = account_get_friendcount(account);
1313 for(i=0; i<n; i++)
1314 {
1315 friend = account_get_friend(account,i);
1316 if(!friend) {
1317 account_remove_friend(account, i);
1318 continue;
1319 }
1320 fr=NULL;
1321 if(newlist || (fr=friendlist_find_uid(account->friends, friend))==NULL)
1322 {
1323 if((acc = accountlist_find_account_by_uid(friend))==NULL)
1324 {
1325 if(account_remove_friend(account, i) == 0)
1326 {
1327 i--;
1328 n--;
1329 }
1330 continue;
1331 }
1332 if(account_check_mutual(acc, account_get_uid(account))==0)
1333 friendlist_add_account(account->friends, acc, 1);
1334 else
1335 friendlist_add_account(account->friends, acc, 0);
1336 }
1337 else {
1338 if((acc=friend_get_account(fr))==NULL)
1339 {
1340 account_remove_friend(account, i);
1341 continue;
1342 }
1343 if(account_check_mutual(acc, account_get_uid(account))==0)
1344 friend_set_mutual(fr, 1);
1345 else
1346 friend_set_mutual(fr, 0);
1347 }
1348 }
1349 if(!newlist)
1350 friendlist_purge(account->friends);
1351 FLAG_SET(&account->flags,ACCOUNT_FLAG_FLOADED);
1352 return 0;
1353 }
1354
1355 static int account_unload_friends(t_account * account)
1356 {
1357 if(friendlist_unload(account->friends)<0)
1358 return -1;
1359 FLAG_CLEAR(&account->flags,ACCOUNT_FLAG_FLOADED);
1360 return 0;
1361 }
1362
1363 extern int account_set_clanmember(t_account * account, t_clanmember * clanmember)
1364 {
1365 if(account==NULL)
1366 {
1367 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1368 return -1;
1369 }
1370
1371 account->clanmember = clanmember;
1372 return 0;
1373 }
1374
1375 extern t_clanmember * account_get_clanmember(t_account * account)
1376 {
1377 t_clanmember * member;
1378
1379 if(account==NULL)
1380 {
1381 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1382 return NULL;
1383 }
1384
1385 if ((member = account->clanmember)&&(clanmember_get_clan(member))&&(clan_get_created(clanmember_get_clan(member)) > 0))
1386 return member;
1387 else
1388 return NULL;
1389 }
1390
1391 extern t_clanmember * account_get_clanmember_forced(t_account * account)
1392 {
1393 if(account==NULL)
1394 {
1395 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1396 return NULL;
1397 }
1398
1399 return account->clanmember;
1400 }
1401
1402 extern t_clan * account_get_clan(t_account * account)
1403 {
1404 if(account==NULL)
1405 {
1406 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1407 return NULL;
1408 }
1409
1410 if(account->clanmember && (clanmember_get_clan(account->clanmember) != NULL) && (clan_get_created(clanmember_get_clan(account->clanmember)) > 0))
1411 return clanmember_get_clan(account->clanmember);
1412 else
1413 return NULL;
1414 }
1415
1416 extern t_clan * account_get_creating_clan(t_account * account)
1417 {
1418 if(account==NULL)
1419 {
1420 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1421 return NULL;
1422 }
1423
1424 if(account->clanmember && (clanmember_get_clan(account->clanmember) != NULL) && (clan_get_created(clanmember_get_clan(account->clanmember)) <= 0))
1425 return clanmember_get_clan(account->clanmember);
1426 else
1427 return NULL;
1428 }
1429
1430 int account_set_conn(t_account * account, t_connection * conn)
1431 {
1432 if (!(account))
1433 {
1434 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1435 return -1;
1436 }
1437
1438 account->conn = conn;
1439
1440 return 0;
1441 }
1442
1443 t_connection * account_get_conn(t_account * account)
1444 {
1445 if (!(account))
1446 {
1447 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1448 return NULL;
1449 }
1450
1451 return account->conn;
1452 }
1453
1454 void account_add_team(t_account * account,t_team * team)
1455 {
1456 assert(account);
1457 assert(team);
1458
1459 if (!(account->teams))
1460 account->teams = list_create();
1461
1462 list_append_data(account->teams,team);
1463 }
1464
1465 t_team * account_find_team_by_accounts(t_account * account, t_account **accounts, t_clienttag clienttag)
1466 {
1467 if ((account->teams))
1468 return _list_find_team_by_accounts(accounts,clienttag,account->teams);
1469 else
1470 return NULL;
1471 }
1472
1473 t_team * account_find_team_by_teamid(t_account * account, unsigned int teamid)
1474 {
1475 if ((account->teams))
1476 return _list_find_team_by_teamid(teamid,account->teams);
1477 else
1478 return NULL;
1479 }
1480
1481 t_list * account_get_teams(t_account * account)
1482 {
1483 assert(account);
1484
1485 return account->teams;
1486 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1