source: protocols/account.c @ 2e0eaac

Last change on this file since 2e0eaac was 2e0eaac, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-11T23:14:49Z

First version of the nick_format setting.

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