source: account.c @ 7125cb3

Last change on this file since 7125cb3 was 7125cb3, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-08-24T18:01:05Z

Added SET_INVALID, which set evaluators should now return instead of NULL
when the given value is not accepted. This to allow certain variables
actually be set to NULL (server, for example). This should fully close
#444.

  • Property mode set to 100644
File size: 7.3 KB
Line 
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
30account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
31{
32        account_t *a;
33        set_t *s;
34       
35        if( irc->accounts )
36        {
37                for( a = irc->accounts; a->next; a = a->next );
38                a = a->next = g_new0( account_t, 1 );
39        }
40        else
41        {
42                irc->accounts = a = g_new0 ( account_t, 1 );
43        }
44       
45        a->prpl = prpl;
46        a->user = g_strdup( user );
47        a->pass = g_strdup( pass );
48        a->auto_connect = 1;
49        a->irc = irc;
50       
51        s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
52        s->flags |= ACC_SET_NOSAVE;
53       
54        s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
55       
56        s = set_add( &a->set, "password", NULL, set_eval_account, a );
57        s->flags |= ACC_SET_NOSAVE;
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       
63        a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
64       
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. */
67        if( prpl->init )
68                prpl->init( a );
69       
70        return( a );
71}
72
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. */
78        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
79                return SET_INVALID;
80       
81        if( strcmp( set->key, "server" ) == 0 )
82        {
83                g_free( acc->server );
84                if( value && *value )
85                {
86                        acc->server = g_strdup( value );
87                        return value;
88                }
89                else
90                {
91                        acc->server = g_strdup( set->def );
92                        return g_strdup( set->def );
93                }
94        }
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        {
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                }
115        }
116        else if( strcmp( set->key, "auto_connect" ) == 0 )
117        {
118                if( !is_bool( value ) )
119                        return SET_INVALID;
120               
121                acc->auto_connect = bool2int( value );
122                return value;
123        }
124       
125        return SET_INVALID;
126}
127
128account_t *account_get( irc_t *irc, char *id )
129{
130        account_t *a, *ret = NULL;
131        char *handle, *s;
132        int nr;
133       
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 &&
146                                    a->prpl->handle_cmp( handle, a->user ) == 0 )
147                                        ret = a;
148                }
149               
150                /* Restore the string. */
151                handle --;
152                *handle = '(';
153                *s = ')';
154               
155                if( ret )
156                        return ret;
157        }
158       
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        {
170                if( g_strcasecmp( id, a->prpl->name ) == 0 )
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;
192       
193        if( acc->ic )
194                /* Caller should have checked, accounts still in use can't be deleted. */
195                return;
196       
197        for( a = irc->accounts; a; a = (l=a)->next )
198                if( a == acc )
199                {
200                        if( l )
201                                l->next = a->next;
202                        else
203                                irc->accounts = a->next;
204                       
205                        while( a->set )
206                                set_del( &a->set, a->set->key );
207                       
208                        g_hash_table_destroy( a->nicks );
209                       
210                        g_free( a->user );
211                        g_free( a->pass );
212                        g_free( a->server );
213                        if( a->reconnect )      /* This prevents any reconnect still queued to happen */
214                                cancel_auto_reconnect( a );
215                        g_free( a );
216                       
217                        break;
218                }
219}
220
221void account_on( irc_t *irc, account_t *a )
222{
223        if( a->ic )
224        {
225                /* Trying to enable an already-enabled account */
226                return;
227        }
228       
229        cancel_auto_reconnect( a );
230       
231        a->reconnect = 0;
232        a->prpl->login( a );
233}
234
235void account_off( irc_t *irc, account_t *a )
236{
237        imc_logout( a->ic, FALSE );
238        a->ic = NULL;
239        if( a->reconnect )
240        {
241                /* Shouldn't happen */
242                cancel_auto_reconnect( a );
243        }
244}
245
246struct account_reconnect_delay
247{
248        int start;
249        char op;
250        int step;
251        int max;
252};
253
254int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
255{
256        memset( p, 0, sizeof( *p ) );
257        /* A whole day seems like a sane "maximum maximum". */
258        p->max = 86400;
259       
260        /* Format: /[0-9]+([*+][0-9]+(<[0-9+]))/ */
261        while( *value && isdigit( *value ) )
262                p->start = p->start * 10 + *value++ - '0';
263       
264        /* Sure, call me evil for implementing my own fscanf here, but it's
265           dead simple and I immediately know where to continue parsing. */
266       
267        if( *value == 0 )
268                /* If the string ends now, the delay is constant. */
269                return 1;
270        else if( *value != '+' && *value != '*' )
271                /* Otherwise allow either a + or a * */
272                return 0;
273       
274        p->op = *value++;
275       
276        /* + or * the delay by this number every time. */
277        while( *value && isdigit( *value ) )
278                p->step = p->step * 10 + *value++ - '0';
279       
280        if( *value == 0 )
281                /* Use the default maximum (one day). */
282                return 1;
283        else if( *value != '<' )
284                return 0;
285       
286        p->max = 0;
287        value ++;
288        while( *value && isdigit( *value ) )
289                p->max = p->max * 10 + *value++ - '0';
290       
291        return p->max > 0;
292}
293
294char *set_eval_account_reconnect_delay( set_t *set, char *value )
295{
296        struct account_reconnect_delay p;
297       
298        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
299}
300
301int account_reconnect_delay( account_t *a )
302{
303        char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
304        struct account_reconnect_delay p;
305       
306        if( account_reconnect_delay_parse( setting, &p ) )
307        {
308                if( a->auto_reconnect_delay == 0 )
309                        a->auto_reconnect_delay = p.start;
310                else if( p.op == '+' )
311                        a->auto_reconnect_delay += p.step;
312                else if( p.op == '*' )
313                        a->auto_reconnect_delay *= p.step;
314               
315                if( a->auto_reconnect_delay > p.max )
316                        a->auto_reconnect_delay = p.max;
317        }
318        else
319        {
320                a->auto_reconnect_delay = 0;
321        }
322       
323        return a->auto_reconnect_delay;
324}
Note: See TracBrowser for help on using the repository browser.