source: protocols/account.c @ badd148

Last change on this file since badd148 was badd148, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-12T23:22:53Z

Reformat nicks whenever fullname/nick/group changes (but at least for now
still only for offline users).

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