source: protocols/account.c @ 5a61bf59

Last change on this file since 5a61bf59 was 06b39f2, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-13T00:17:37Z

Automatically convert nick_source settings to their nick_convert equivalent.

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