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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide 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 sysadm 1.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