source: account.c @ ccba980

Last change on this file since ccba980 was b75acf6, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-22T21:55:23Z

Don't include chat.h from bitlbee.h. make install-dev doesn't install
chat.h and it shouldn't ... but things broke because bitlbee.h includes
it. Fixes #534.

  • Property mode set to 100644
File size: 7.5 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#include "chat.h"
30
31account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
32{
33        account_t *a;
34        set_t *s;
35       
36        if( irc->accounts )
37        {
38                for( a = irc->accounts; a->next; a = a->next );
39                a = a->next = g_new0( account_t, 1 );
40        }
41        else
42        {
43                irc->accounts = a = g_new0 ( account_t, 1 );
44        }
45       
46        a->prpl = prpl;
47        a->user = g_strdup( user );
48        a->pass = g_strdup( pass );
49        a->auto_connect = 1;
50        a->irc = irc;
51       
52        s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
53        s->flags |= ACC_SET_NOSAVE;
54       
55        s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
56       
57        s = set_add( &a->set, "password", NULL, set_eval_account, a );
58        s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
59       
60        s = set_add( &a->set, "username", NULL, set_eval_account, a );
61        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
62        set_setstr( &a->set, "username", user );
63       
64        a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
65       
66        /* This function adds some more settings (and might want to do more
67           things that have to be done now, although I can't think of anything. */
68        if( prpl->init )
69                prpl->init( a );
70       
71        return( a );
72}
73
74char *set_eval_account( set_t *set, char *value )
75{
76        account_t *acc = set->data;
77       
78        /* Double-check: We refuse to edit on-line accounts. */
79        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
80                return SET_INVALID;
81       
82        if( strcmp( set->key, "server" ) == 0 )
83        {
84                g_free( acc->server );
85                if( value && *value )
86                {
87                        acc->server = g_strdup( value );
88                        return value;
89                }
90                else
91                {
92                        acc->server = g_strdup( set->def );
93                        return g_strdup( set->def );
94                }
95        }
96        else if( strcmp( set->key, "username" ) == 0 )
97        {
98                g_free( acc->user );
99                acc->user = g_strdup( value );
100                return value;
101        }
102        else if( strcmp( set->key, "password" ) == 0 )
103        {
104                if( value )
105                {
106                        g_free( acc->pass );
107                        acc->pass = g_strdup( value );
108                        return NULL;    /* password shouldn't be visible in plaintext! */
109                }
110                else
111                {
112                        /* NULL can (should) be stored in the set_t
113                           variable, but is otherwise not correct. */
114                        return SET_INVALID;
115                }
116        }
117        else if( strcmp( set->key, "auto_connect" ) == 0 )
118        {
119                if( !is_bool( value ) )
120                        return SET_INVALID;
121               
122                acc->auto_connect = bool2int( value );
123                return value;
124        }
125       
126        return SET_INVALID;
127}
128
129account_t *account_get( irc_t *irc, char *id )
130{
131        account_t *a, *ret = NULL;
132        char *handle, *s;
133        int nr;
134       
135        /* This checks if the id string ends with (...) */
136        if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
137        {
138                struct prpl *proto;
139               
140                *s = *handle = 0;
141                handle ++;
142               
143                if( ( proto = find_protocol( id ) ) )
144                {
145                        for( a = irc->accounts; a; a = a->next )
146                                if( a->prpl == proto &&
147                                    a->prpl->handle_cmp( handle, a->user ) == 0 )
148                                        ret = a;
149                }
150               
151                /* Restore the string. */
152                handle --;
153                *handle = '(';
154                *s = ')';
155               
156                if( ret )
157                        return ret;
158        }
159       
160        if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
161        {
162                for( a = irc->accounts; a; a = a->next )
163                        if( ( nr-- ) == 0 )
164                                return( a );
165               
166                return( NULL );
167        }
168       
169        for( a = irc->accounts; a; a = a->next )
170        {
171                if( g_strcasecmp( id, a->prpl->name ) == 0 )
172                {
173                        if( !ret )
174                                ret = a;
175                        else
176                                return( NULL ); /* We don't want to match more than one... */
177                }
178                else if( strstr( a->user, id ) )
179                {
180                        if( !ret )
181                                ret = a;
182                        else
183                                return( NULL );
184                }
185        }
186       
187        return( ret );
188}
189
190void account_del( irc_t *irc, account_t *acc )
191{
192        account_t *a, *l = NULL;
193        struct chat *c, *nc;
194       
195        if( acc->ic )
196                /* Caller should have checked, accounts still in use can't be deleted. */
197                return;
198       
199        for( a = irc->accounts; a; a = (l=a)->next )
200                if( a == acc )
201                {
202                        if( l )
203                                l->next = a->next;
204                        else
205                                irc->accounts = a->next;
206                       
207                        for( c = irc->chatrooms; c; c = nc )
208                        {
209                                nc = c->next;
210                                if( acc == c->acc )
211                                        chat_del( irc, c );
212                        }
213                       
214                        while( a->set )
215                                set_del( &a->set, a->set->key );
216                       
217                        g_hash_table_destroy( a->nicks );
218                       
219                        g_free( a->user );
220                        g_free( a->pass );
221                        g_free( a->server );
222                        if( a->reconnect )      /* This prevents any reconnect still queued to happen */
223                                cancel_auto_reconnect( a );
224                        g_free( a );
225                       
226                        break;
227                }
228}
229
230void account_on( irc_t *irc, account_t *a )
231{
232        if( a->ic )
233        {
234                /* Trying to enable an already-enabled account */
235                return;
236        }
237       
238        cancel_auto_reconnect( a );
239       
240        a->reconnect = 0;
241        a->prpl->login( a );
242}
243
244void account_off( irc_t *irc, account_t *a )
245{
246        imc_logout( a->ic, FALSE );
247        a->ic = NULL;
248        if( a->reconnect )
249        {
250                /* Shouldn't happen */
251                cancel_auto_reconnect( a );
252        }
253}
254
255struct account_reconnect_delay
256{
257        int start;
258        char op;
259        int step;
260        int max;
261};
262
263int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
264{
265        memset( p, 0, sizeof( *p ) );
266        /* A whole day seems like a sane "maximum maximum". */
267        p->max = 86400;
268       
269        /* Format: /[0-9]+([*+][0-9]+(<[0-9+]))/ */
270        while( *value && isdigit( *value ) )
271                p->start = p->start * 10 + *value++ - '0';
272       
273        /* Sure, call me evil for implementing my own fscanf here, but it's
274           dead simple and I immediately know where to continue parsing. */
275       
276        if( *value == 0 )
277                /* If the string ends now, the delay is constant. */
278                return 1;
279        else if( *value != '+' && *value != '*' )
280                /* Otherwise allow either a + or a * */
281                return 0;
282       
283        p->op = *value++;
284       
285        /* + or * the delay by this number every time. */
286        while( *value && isdigit( *value ) )
287                p->step = p->step * 10 + *value++ - '0';
288       
289        if( *value == 0 )
290                /* Use the default maximum (one day). */
291                return 1;
292        else if( *value != '<' )
293                return 0;
294       
295        p->max = 0;
296        value ++;
297        while( *value && isdigit( *value ) )
298                p->max = p->max * 10 + *value++ - '0';
299       
300        return p->max > 0;
301}
302
303char *set_eval_account_reconnect_delay( set_t *set, char *value )
304{
305        struct account_reconnect_delay p;
306       
307        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
308}
309
310int account_reconnect_delay( account_t *a )
311{
312        char *setting = set_getstr( &a->irc->set, "auto_reconnect_delay" );
313        struct account_reconnect_delay p;
314       
315        if( account_reconnect_delay_parse( setting, &p ) )
316        {
317                if( a->auto_reconnect_delay == 0 )
318                        a->auto_reconnect_delay = p.start;
319                else if( p.op == '+' )
320                        a->auto_reconnect_delay += p.step;
321                else if( p.op == '*' )
322                        a->auto_reconnect_delay *= p.step;
323               
324                if( a->auto_reconnect_delay > p.max )
325                        a->auto_reconnect_delay = p.max;
326        }
327        else
328        {
329                a->auto_reconnect_delay = 0;
330        }
331       
332        return a->auto_reconnect_delay;
333}
Note: See TracBrowser for help on using the repository browser.