source: account.c @ 88d2208

Last change on this file since 88d2208 was 3b32017, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-08-19T22:21:07Z

Better handling of NULLs passed to set_eval_account(). Still confusing
though, set_reset() is broken for variables that can actually be NULL.

  • Property mode set to 100644
File size: 7.2 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 NULL;
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 = NULL;
92                        return g_strdup( set->def );
93                }
94        }
95        else if( value == NULL )
96        {
97                /* Noop, the other three can't be NULL. */
98        }
99        else if( strcmp( set->key, "username" ) == 0 )
100        {
101                g_free( acc->user );
102                acc->user = g_strdup( value );
103                return value;
104        }
105        else if( strcmp( set->key, "password" ) == 0 )
106        {
107                g_free( acc->pass );
108                acc->pass = g_strdup( value );
109                return NULL;    /* password shouldn't be visible in plaintext! */
110        }
111        else if( strcmp( set->key, "auto_connect" ) == 0 )
112        {
113                if( !is_bool( value ) )
114                        return NULL;
115               
116                acc->auto_connect = bool2int( value );
117                return value;
118        }
119       
120        return NULL;
121}
122
123account_t *account_get( irc_t *irc, char *id )
124{
125        account_t *a, *ret = NULL;
126        char *handle, *s;
127        int nr;
128       
129        /* This checks if the id string ends with (...) */
130        if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
131        {
132                struct prpl *proto;
133               
134                *s = *handle = 0;
135                handle ++;
136               
137                if( ( proto = find_protocol( id ) ) )
138                {
139                        for( a = irc->accounts; a; a = a->next )
140                                if( a->prpl == proto &&
141                                    a->prpl->handle_cmp( handle, a->user ) == 0 )
142                                        ret = a;
143                }
144               
145                /* Restore the string. */
146                handle --;
147                *handle = '(';
148                *s = ')';
149               
150                if( ret )
151                        return ret;
152        }
153       
154        if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
155        {
156                for( a = irc->accounts; a; a = a->next )
157                        if( ( nr-- ) == 0 )
158                                return( a );
159               
160                return( NULL );
161        }
162       
163        for( a = irc->accounts; a; a = a->next )
164        {
165                if( g_strcasecmp( id, a->prpl->name ) == 0 )
166                {
167                        if( !ret )
168                                ret = a;
169                        else
170                                return( NULL ); /* We don't want to match more than one... */
171                }
172                else if( strstr( a->user, id ) )
173                {
174                        if( !ret )
175                                ret = a;
176                        else
177                                return( NULL );
178                }
179        }
180       
181        return( ret );
182}
183
184void account_del( irc_t *irc, account_t *acc )
185{
186        account_t *a, *l = NULL;
187       
188        if( acc->ic )
189                /* Caller should have checked, accounts still in use can't be deleted. */
190                return;
191       
192        for( a = irc->accounts; a; a = (l=a)->next )
193                if( a == acc )
194                {
195                        if( l )
196                                l->next = a->next;
197                        else
198                                irc->accounts = a->next;
199                       
200                        while( a->set )
201                                set_del( &a->set, a->set->key );
202                       
203                        g_hash_table_destroy( a->nicks );
204                       
205                        g_free( a->user );
206                        g_free( a->pass );
207                        g_free( a->server );
208                        if( a->reconnect )      /* This prevents any reconnect still queued to happen */
209                                cancel_auto_reconnect( a );
210                        g_free( a );
211                       
212                        break;
213                }
214}
215
216void account_on( irc_t *irc, account_t *a )
217{
218        if( a->ic )
219        {
220                /* Trying to enable an already-enabled account */
221                return;
222        }
223       
224        cancel_auto_reconnect( a );
225       
226        a->reconnect = 0;
227        a->prpl->login( a );
228}
229
230void account_off( irc_t *irc, account_t *a )
231{
232        imc_logout( a->ic, FALSE );
233        a->ic = NULL;
234        if( a->reconnect )
235        {
236                /* Shouldn't happen */
237                cancel_auto_reconnect( a );
238        }
239}
240
241struct account_reconnect_delay
242{
243        int start;
244        char op;
245        int step;
246        int max;
247};
248
249int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
250{
251        memset( p, 0, sizeof( *p ) );
252        /* A whole day seems like a sane "maximum maximum". */
253        p->max = 86400;
254       
255        /* Format: /[0-9]+([*+][0-9]+(<[0-9+]))/ */
256        while( *value && isdigit( *value ) )
257                p->start = p->start * 10 + *value++ - '0';
258       
259        /* Sure, call me evil for implementing my own fscanf here, but it's
260           dead simple and I'm immediately at the next part to parse. */
261       
262        if( *value == 0 )
263                /* If the string ends now, the delay is constant. */
264                return 1;
265        else if( *value != '+' && *value != '*' )
266                /* Otherwise allow either a + or a * */
267                return 0;
268       
269        p->op = *value++;
270       
271        /* + or * the delay by this number every time. */
272        while( *value && isdigit( *value ) )
273                p->step = p->step * 10 + *value++ - '0';
274       
275        if( *value == 0 )
276                /* Use the default maximum (one day). */
277                return 1;
278        else if( *value != '<' )
279                return 0;
280       
281        p->max = 0;
282        value ++;
283        while( *value && isdigit( *value ) )
284                p->max = p->max * 10 + *value++ - '0';
285       
286        return p->max > 0;
287}
288
289char *set_eval_account_reconnect_delay( set_t *set, char *value )
290{
291        struct account_reconnect_delay p;
292       
293        return account_reconnect_delay_parse( value, &p ) ? value : NULL;
294}
295
296int account_reconnect_delay( account_t *a )
297{
298        char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
299        struct account_reconnect_delay p;
300       
301        if( account_reconnect_delay_parse( setting, &p ) )
302        {
303                if( a->auto_reconnect_delay == 0 )
304                        a->auto_reconnect_delay = p.start;
305                else if( p.op == '+' )
306                        a->auto_reconnect_delay += p.step;
307                else if( p.op == '*' )
308                        a->auto_reconnect_delay *= p.step;
309               
310                if( a->auto_reconnect_delay > p.max )
311                        a->auto_reconnect_delay = p.max;
312        }
313        else
314        {
315                a->auto_reconnect_delay = 0;
316        }
317       
318        return a->auto_reconnect_delay;
319}
Note: See TracBrowser for help on using the repository browser.