source: protocols/account.c @ a7dbf45

Last change on this file since a7dbf45 was e135cd09, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-24T15:58:27Z

Use the account tag in a few places and store it in the XML file as an
attribute, not as a setting (since all accounts have it anyway).

  • Property mode set to 100644
File size: 9.7 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[58adb7e]4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
[b7d3cc34]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
[06b39f2]30static char *set_eval_nick_source( set_t *set, char *value );
31
[81e04e1]32account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass )
[b7d3cc34]33{
34        account_t *a;
[5100caa]35        set_t *s;
[40e6dac]36        char tag[strlen(prpl->name)+10];
[b7d3cc34]37       
[81e04e1]38        if( bee->accounts )
[b7d3cc34]39        {
[81e04e1]40                for( a = bee->accounts; a->next; a = a->next );
[a312b6b]41                a = a->next = g_new0( account_t, 1 );
[b7d3cc34]42        }
43        else
44        {
[81e04e1]45                bee->accounts = a = g_new0 ( account_t, 1 );
[b7d3cc34]46        }
47       
[7b23afd]48        a->prpl = prpl;
[b7d3cc34]49        a->user = g_strdup( user );
50        a->pass = g_strdup( pass );
[2b14eef]51        a->auto_connect = 1;
[81e04e1]52        a->bee = bee;
[b7d3cc34]53       
[96863f6]54        s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
[5100caa]55        s->flags |= ACC_SET_NOSAVE;
56       
[04026d4]57        s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
[00a5270]58       
[2e0eaac]59        s = set_add( &a->set, "nick_format", NULL, NULL, a );
[badd148]60        s->flags |= SET_NULL_OK;
[2e0eaac]61       
[06b39f2]62        s = set_add( &a->set, "nick_source", "handle", set_eval_nick_source, a );
63        s->flags |= ACC_SET_NOSAVE; /* Just for bw compatibility! */
[286b28e]64       
[5100caa]65        s = set_add( &a->set, "password", NULL, set_eval_account, a );
[f3579fd]66        s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
[5100caa]67       
[40e6dac]68        s = set_add( &a->set, "tag", NULL, set_eval_account, a );
[e135cd09]69        s->flags |= ACC_SET_NOSAVE;
[40e6dac]70       
[5100caa]71        s = set_add( &a->set, "username", NULL, set_eval_account, a );
72        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
73        set_setstr( &a->set, "username", user );
74       
[40e6dac]75        if( account_by_tag( bee, prpl->name ) )
76        {
77                int i;
78
79                for( i = 2; i < 10000; i ++ )
80                {
81                        sprintf( tag, "%s%d", prpl->name, i );
82                        if( !account_by_tag( bee, tag ) )
83                                break;
84                }
85        }
86        else
87        {
88                strcpy( tag, prpl->name );
89        }
90        set_setstr( &a->set, "tag", tag );
91       
[5b52a48]92        a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
93       
[96863f6]94        /* This function adds some more settings (and might want to do more
95           things that have to be done now, although I can't think of anything. */
[0da65d5]96        if( prpl->init )
97                prpl->init( a );
[96863f6]98       
[58adb7e]99        s = set_add( &a->set, "away", NULL, set_eval_account, a );
100        s->flags |= SET_NULL_OK;
101       
102        if( a->flags & ACC_FLAG_STATUS_MESSAGE )
103        {
104                s = set_add( &a->set, "status", NULL, set_eval_account, a );
105                s->flags |= SET_NULL_OK;
106        }
107       
108        return a;
[b7d3cc34]109}
110
[5100caa]111char *set_eval_account( set_t *set, char *value )
112{
113        account_t *acc = set->data;
114       
115        /* Double-check: We refuse to edit on-line accounts. */
[0da65d5]116        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
[7125cb3]117                return SET_INVALID;
[5100caa]118       
[3b32017]119        if( strcmp( set->key, "server" ) == 0 )
[5100caa]120        {
121                g_free( acc->server );
[3b32017]122                if( value && *value )
[30ce1ce]123                {
[5100caa]124                        acc->server = g_strdup( value );
[30ce1ce]125                        return value;
126                }
[5100caa]127                else
[30ce1ce]128                {
[7125cb3]129                        acc->server = g_strdup( set->def );
[30ce1ce]130                        return g_strdup( set->def );
131                }
[5100caa]132        }
[3b32017]133        else if( strcmp( set->key, "username" ) == 0 )
134        {
135                g_free( acc->user );
136                acc->user = g_strdup( value );
137                return value;
138        }
139        else if( strcmp( set->key, "password" ) == 0 )
140        {
[7125cb3]141                if( value )
142                {
143                        g_free( acc->pass );
144                        acc->pass = g_strdup( value );
145                        return NULL;    /* password shouldn't be visible in plaintext! */
146                }
147                else
148                {
149                        /* NULL can (should) be stored in the set_t
150                           variable, but is otherwise not correct. */
151                        return SET_INVALID;
152                }
[3b32017]153        }
[40e6dac]154        else if( strcmp( set->key, "tag" ) == 0 )
155        {
156                account_t *oa;
157               
158                /* Enforce uniqueness. */
159                if( ( oa = account_by_tag( acc->bee, value ) ) && oa != acc )
160                        return SET_INVALID;
161               
162                g_free( acc->tag );
163                acc->tag = g_strdup( value );
164                return value;
165        }
[5100caa]166        else if( strcmp( set->key, "auto_connect" ) == 0 )
167        {
168                if( !is_bool( value ) )
[7125cb3]169                        return SET_INVALID;
[5100caa]170               
171                acc->auto_connect = bool2int( value );
172                return value;
173        }
[58adb7e]174        else if( strcmp( set->key, "away" ) == 0 ||
175                 strcmp( set->key, "status" ) == 0 )
176        {
177                if( acc->ic && acc->ic->flags & OPT_LOGGED_IN )
178                {
179                        /* If we're currently on-line, set the var now already
180                           (bit of a hack) and send an update. */
181                        g_free( set->value );
182                        set->value = g_strdup( value );
183                       
184                        imc_away_send_update( acc->ic );
185                }
186               
187                return value;
188        }
[5100caa]189       
[7125cb3]190        return SET_INVALID;
[5100caa]191}
192
[06b39f2]193/* For bw compatibility, have this write-only setting. */
194static char *set_eval_nick_source( set_t *set, char *value )
195{
196        account_t *a = set->data;
197       
198        if( strcmp( value, "full_name" ) == 0 )
199                set_setstr( &a->set, "nick_format", "%full_name" );
200        else if( strcmp( value, "first_name" ) == 0 )
201                set_setstr( &a->set, "nick_format", "%first_name" );
202        else
203                set_setstr( &a->set, "nick_format", "%-@nick" );
204       
205        return value;
206}
207
[40e6dac]208account_t *account_get( bee_t *bee, const char *id )
[b7d3cc34]209{
210        account_t *a, *ret = NULL;
[85616c3]211        char *handle, *s;
[b7d3cc34]212        int nr;
213       
[40e6dac]214        /* Tags get priority above anything else. */
215        if( ( a = account_by_tag( bee, id ) ) )
216                return a;
217       
[85616c3]218        /* This checks if the id string ends with (...) */
219        if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 )
220        {
221                struct prpl *proto;
222               
223                *s = *handle = 0;
224                handle ++;
225               
226                if( ( proto = find_protocol( id ) ) )
227                {
[81e04e1]228                        for( a = bee->accounts; a; a = a->next )
[85616c3]229                                if( a->prpl == proto &&
[5b52a48]230                                    a->prpl->handle_cmp( handle, a->user ) == 0 )
[85616c3]231                                        ret = a;
232                }
233               
234                /* Restore the string. */
235                handle --;
236                *handle = '(';
237                *s = ')';
238               
239                if( ret )
240                        return ret;
241        }
242       
[b7d3cc34]243        if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
244        {
[81e04e1]245                for( a = bee->accounts; a; a = a->next )
[b7d3cc34]246                        if( ( nr-- ) == 0 )
247                                return( a );
248               
249                return( NULL );
250        }
251       
[81e04e1]252        for( a = bee->accounts; a; a = a->next )
[b7d3cc34]253        {
[7b23afd]254                if( g_strcasecmp( id, a->prpl->name ) == 0 )
[b7d3cc34]255                {
256                        if( !ret )
257                                ret = a;
258                        else
259                                return( NULL ); /* We don't want to match more than one... */
260                }
261                else if( strstr( a->user, id ) )
262                {
263                        if( !ret )
264                                ret = a;
265                        else
266                                return( NULL );
267                }
268        }
269       
270        return( ret );
271}
272
[40e6dac]273account_t *account_by_tag( bee_t *bee, const char *tag )
274{
275        account_t *a;
276       
277        for( a = bee->accounts; a; a = a->next )
278                if( a->tag && g_strcasecmp( tag, a->tag ) == 0 )
279                        return a;
280       
281        return NULL;
282}
283
[81e04e1]284void account_del( bee_t *bee, account_t *acc )
[b7d3cc34]285{
286        account_t *a, *l = NULL;
287       
[fa75134]288        if( acc->ic )
289                /* Caller should have checked, accounts still in use can't be deleted. */
290                return;
291       
[81e04e1]292        for( a = bee->accounts; a; a = (l=a)->next )
[b7d3cc34]293                if( a == acc )
294                {
295                        if( l )
296                                l->next = a->next;
297                        else
[81e04e1]298                                bee->accounts = a->next;
[b7d3cc34]299                       
[81e04e1]300                        /** FIXME
301                        for( c = bee->chatrooms; c; c = nc )
[f86a3d5]302                        {
303                                nc = c->next;
[d995c9b]304                                if( acc == c->acc )
[81e04e1]305                                        chat_del( bee, c );
[f86a3d5]306                        }
[81e04e1]307                        */
[d995c9b]308                       
[5100caa]309                        while( a->set )
310                                set_del( &a->set, a->set->key );
311                       
[5b52a48]312                        g_hash_table_destroy( a->nicks );
313                       
[40e6dac]314                        g_free( a->tag );
[b7d3cc34]315                        g_free( a->user );
316                        g_free( a->pass );
[fa75134]317                        g_free( a->server );
[b7d3cc34]318                        if( a->reconnect )      /* This prevents any reconnect still queued to happen */
319                                cancel_auto_reconnect( a );
320                        g_free( a );
321                       
322                        break;
323                }
324}
325
[81e04e1]326void account_on( bee_t *bee, account_t *a )
[b7d3cc34]327{
[0da65d5]328        if( a->ic )
[b7d3cc34]329        {
330                /* Trying to enable an already-enabled account */
331                return;
332        }
333       
334        cancel_auto_reconnect( a );
335       
336        a->reconnect = 0;
[0a3c243]337        a->prpl->login( a );
[b7d3cc34]338}
339
[81e04e1]340void account_off( bee_t *bee, account_t *a )
[b7d3cc34]341{
[b0eaa5b]342        imc_logout( a->ic, FALSE );
[0da65d5]343        a->ic = NULL;
[b7d3cc34]344        if( a->reconnect )
345        {
346                /* Shouldn't happen */
347                cancel_auto_reconnect( a );
348        }
349}
[280e655]350
[4230221]351struct account_reconnect_delay
[280e655]352{
353        int start;
354        char op;
355        int step;
[4230221]356        int max;
357};
358
359int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p )
360{
361        memset( p, 0, sizeof( *p ) );
362        /* A whole day seems like a sane "maximum maximum". */
363        p->max = 86400;
[280e655]364       
[58adb7e]365        /* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */
[4230221]366        while( *value && isdigit( *value ) )
367                p->start = p->start * 10 + *value++ - '0';
368       
369        /* Sure, call me evil for implementing my own fscanf here, but it's
[7125cb3]370           dead simple and I immediately know where to continue parsing. */
[4230221]371       
372        if( *value == 0 )
373                /* If the string ends now, the delay is constant. */
374                return 1;
375        else if( *value != '+' && *value != '*' )
376                /* Otherwise allow either a + or a * */
377                return 0;
378       
379        p->op = *value++;
380       
381        /* + or * the delay by this number every time. */
382        while( *value && isdigit( *value ) )
383                p->step = p->step * 10 + *value++ - '0';
384       
385        if( *value == 0 )
386                /* Use the default maximum (one day). */
387                return 1;
388        else if( *value != '<' )
389                return 0;
390       
391        p->max = 0;
392        value ++;
393        while( *value && isdigit( *value ) )
394                p->max = p->max * 10 + *value++ - '0';
395       
396        return p->max > 0;
397}
398
399char *set_eval_account_reconnect_delay( set_t *set, char *value )
400{
401        struct account_reconnect_delay p;
402       
[7125cb3]403        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
[280e655]404}
405
406int account_reconnect_delay( account_t *a )
407{
[81e04e1]408        char *setting = set_getstr( &a->bee->set, "auto_reconnect_delay" );
[4230221]409        struct account_reconnect_delay p;
[280e655]410       
[4230221]411        if( account_reconnect_delay_parse( setting, &p ) )
[280e655]412        {
413                if( a->auto_reconnect_delay == 0 )
[4230221]414                        a->auto_reconnect_delay = p.start;
415                else if( p.op == '+' )
416                        a->auto_reconnect_delay += p.step;
417                else if( p.op == '*' )
418                        a->auto_reconnect_delay *= p.step;
419               
420                if( a->auto_reconnect_delay > p.max )
421                        a->auto_reconnect_delay = p.max;
[280e655]422        }
[4230221]423        else
[280e655]424        {
[4230221]425                a->auto_reconnect_delay = 0;
[280e655]426        }
427       
[4230221]428        return a->auto_reconnect_delay;
[280e655]429}
Note: See TracBrowser for help on using the repository browser.