source: account.c @ 4524f66

Last change on this file since 4524f66 was f86a3d5, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-09-01T10:21:01Z

Fixed ugly looping bug in chatroom list cleanup code.

  • Property mode set to 100644
File size: 7.4 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Account management functions                                         */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "account.h"
29
[7b23afd]30account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
[b7d3cc34]31{
32        account_t *a;
[5100caa]33        set_t *s;
[b7d3cc34]34       
35        if( irc->accounts )
36        {
37                for( a = irc->accounts; a->next; a = a->next );
[a312b6b]38                a = a->next = g_new0( account_t, 1 );
[b7d3cc34]39        }
40        else
41        {
42                irc->accounts = a = g_new0 ( account_t, 1 );
43        }
44       
[7b23afd]45        a->prpl = prpl;
[b7d3cc34]46        a->user = g_strdup( user );
47        a->pass = g_strdup( pass );
[2b14eef]48        a->auto_connect = 1;
[b7d3cc34]49        a->irc = irc;
50       
[96863f6]51        s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
[5100caa]52        s->flags |= ACC_SET_NOSAVE;
53       
[04026d4]54        s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
[00a5270]55       
[5100caa]56        s = set_add( &a->set, "password", NULL, set_eval_account, a );
[f3579fd]57        s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
[5100caa]58       
59        s = set_add( &a->set, "username", NULL, set_eval_account, a );
60        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
61        set_setstr( &a->set, "username", user );
62       
[5b52a48]63        a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
64       
[96863f6]65        /* This function adds some more settings (and might want to do more
66           things that have to be done now, although I can't think of anything. */
[0da65d5]67        if( prpl->init )
68                prpl->init( a );
[96863f6]69       
[b7d3cc34]70        return( a );
71}
72
[5100caa]73char *set_eval_account( set_t *set, char *value )
74{
75        account_t *acc = set->data;
76       
77        /* Double-check: We refuse to edit on-line accounts. */
[0da65d5]78        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
[7125cb3]79                return SET_INVALID;
[5100caa]80       
[3b32017]81        if( strcmp( set->key, "server" ) == 0 )
[5100caa]82        {
83                g_free( acc->server );
[3b32017]84                if( value && *value )
[30ce1ce]85                {
[5100caa]86                        acc->server = g_strdup( value );
[30ce1ce]87                        return value;
88                }
[5100caa]89                else
[30ce1ce]90                {
[7125cb3]91                        acc->server = g_strdup( set->def );
[30ce1ce]92                        return g_strdup( set->def );
93                }
[5100caa]94        }
[3b32017]95        else if( strcmp( set->key, "username" ) == 0 )
96        {
97                g_free( acc->user );
98                acc->user = g_strdup( value );
99                return value;
100        }
101        else if( strcmp( set->key, "password" ) == 0 )
102        {
[7125cb3]103                if( value )
104                {
105                        g_free( acc->pass );
106                        acc->pass = g_strdup( value );
107                        return NULL;    /* password shouldn't be visible in plaintext! */
108                }
109                else
110                {
111                        /* NULL can (should) be stored in the set_t
112                           variable, but is otherwise not correct. */
113                        return SET_INVALID;
114                }
[3b32017]115        }
[5100caa]116        else if( strcmp( set->key, "auto_connect" ) == 0 )
117        {
118                if( !is_bool( value ) )
[7125cb3]119                        return SET_INVALID;
[5100caa]120               
121                acc->auto_connect = bool2int( value );
122                return value;
123        }
124       
[7125cb3]125        return SET_INVALID;
[5100caa]126}
127
[b7d3cc34]128account_t *account_get( irc_t *irc, char *id )
129{
130        account_t *a, *ret = NULL;
[85616c3]131        char *handle, *s;
[b7d3cc34]132        int nr;
133       
[85616c3]134        /* This checks if the id string ends with (...) */
135        if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
136        {
137                struct prpl *proto;
138               
139                *s = *handle = 0;
140                handle ++;
141               
142                if( ( proto = find_protocol( id ) ) )
143                {
144                        for( a = irc->accounts; a; a = a->next )
145                                if( a->prpl == proto &&
[5b52a48]146                                    a->prpl->handle_cmp( handle, a->user ) == 0 )
[85616c3]147                                        ret = a;
148                }
149               
150                /* Restore the string. */
151                handle --;
152                *handle = '(';
153                *s = ')';
154               
155                if( ret )
156                        return ret;
157        }
158       
[b7d3cc34]159        if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
160        {
161                for( a = irc->accounts; a; a = a->next )
162                        if( ( nr-- ) == 0 )
163                                return( a );
164               
165                return( NULL );
166        }
167       
168        for( a = irc->accounts; a; a = a->next )
169        {
[7b23afd]170                if( g_strcasecmp( id, a->prpl->name ) == 0 )
[b7d3cc34]171                {
172                        if( !ret )
173                                ret = a;
174                        else
175                                return( NULL ); /* We don't want to match more than one... */
176                }
177                else if( strstr( a->user, id ) )
178                {
179                        if( !ret )
180                                ret = a;
181                        else
182                                return( NULL );
183                }
184        }
185       
186        return( ret );
187}
188
189void account_del( irc_t *irc, account_t *acc )
190{
191        account_t *a, *l = NULL;
[d995c9b]192        struct chat *c, *nc;
[b7d3cc34]193       
[fa75134]194        if( acc->ic )
195                /* Caller should have checked, accounts still in use can't be deleted. */
196                return;
197       
[b7d3cc34]198        for( a = irc->accounts; a; a = (l=a)->next )
199                if( a == acc )
200                {
201                        if( l )
202                                l->next = a->next;
203                        else
204                                irc->accounts = a->next;
205                       
[d995c9b]206                        for( c = irc->chatrooms; c; c = nc )
[f86a3d5]207                        {
208                                nc = c->next;
[d995c9b]209                                if( acc == c->acc )
210                                        chat_del( irc, c );
[f86a3d5]211                        }
[d995c9b]212                       
[5100caa]213                        while( a->set )
214                                set_del( &a->set, a->set->key );
215                       
[5b52a48]216                        g_hash_table_destroy( a->nicks );
217                       
[b7d3cc34]218                        g_free( a->user );
219                        g_free( a->pass );
[fa75134]220                        g_free( a->server );
[b7d3cc34]221                        if( a->reconnect )      /* This prevents any reconnect still queued to happen */
222                                cancel_auto_reconnect( a );
223                        g_free( a );
224                       
225                        break;
226                }
227}
228
229void account_on( irc_t *irc, account_t *a )
230{
[0da65d5]231        if( a->ic )
[b7d3cc34]232        {
233                /* Trying to enable an already-enabled account */
234                return;
235        }
236       
237        cancel_auto_reconnect( a );
238       
239        a->reconnect = 0;
[0a3c243]240        a->prpl->login( a );
[b7d3cc34]241}
242
243void account_off( irc_t *irc, account_t *a )
244{
[b0eaa5b]245        imc_logout( a->ic, FALSE );
[0da65d5]246        a->ic = NULL;
[b7d3cc34]247        if( a->reconnect )
248        {
249                /* Shouldn't happen */
250                cancel_auto_reconnect( a );
251        }
252}
[280e655]253
[4230221]254struct account_reconnect_delay
[280e655]255{
256        int start;
257        char op;
258        int step;
[4230221]259        int max;
260};
261
262int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
263{
264        memset( p, 0, sizeof( *p ) );
265        /* A whole day seems like a sane "maximum maximum". */
266        p->max = 86400;
[280e655]267       
[4230221]268        /* Format: /[0-9]+([*+][0-9]+(<[0-9+]))/ */
269        while( *value && isdigit( *value ) )
270                p->start = p->start * 10 + *value++ - '0';
271       
272        /* Sure, call me evil for implementing my own fscanf here, but it's
[7125cb3]273           dead simple and I immediately know where to continue parsing. */
[4230221]274       
275        if( *value == 0 )
276                /* If the string ends now, the delay is constant. */
277                return 1;
278        else if( *value != '+' && *value != '*' )
279                /* Otherwise allow either a + or a * */
280                return 0;
281       
282        p->op = *value++;
283       
284        /* + or * the delay by this number every time. */
285        while( *value && isdigit( *value ) )
286                p->step = p->step * 10 + *value++ - '0';
287       
288        if( *value == 0 )
289                /* Use the default maximum (one day). */
290                return 1;
291        else if( *value != '<' )
292                return 0;
293       
294        p->max = 0;
295        value ++;
296        while( *value && isdigit( *value ) )
297                p->max = p->max * 10 + *value++ - '0';
298       
299        return p->max > 0;
300}
301
302char *set_eval_account_reconnect_delay( set_t *set, char *value )
303{
304        struct account_reconnect_delay p;
305       
[7125cb3]306        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
[280e655]307}
308
309int account_reconnect_delay( account_t *a )
310{
311        char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
[4230221]312        struct account_reconnect_delay p;
[280e655]313       
[4230221]314        if( account_reconnect_delay_parse( setting, &p ) )
[280e655]315        {
316                if( a->auto_reconnect_delay == 0 )
[4230221]317                        a->auto_reconnect_delay = p.start;
318                else if( p.op == '+' )
319                        a->auto_reconnect_delay += p.step;
320                else if( p.op == '*' )
321                        a->auto_reconnect_delay *= p.step;
322               
323                if( a->auto_reconnect_delay > p.max )
324                        a->auto_reconnect_delay = p.max;
[280e655]325        }
[4230221]326        else
[280e655]327        {
[4230221]328                a->auto_reconnect_delay = 0;
[280e655]329        }
330       
[4230221]331        return a->auto_reconnect_delay;
[280e655]332}
Note: See TracBrowser for help on using the repository browser.