source: protocols/nogaim.c @ 11e7828

Last change on this file since 11e7828 was 11e7828, checked in by dequis <dx@…>, at 2015-01-26T02:43:35Z

Fix whatsapp local contact lists

Had to move the code that adds contacts to imcb_connected to avoid
dereferencing a null im_connection.

Turns out this kind of local contact lists only applies to renamed
contacts, though. It doesn't deal with libpurple's blist.xml at all
(it could, there are APIs for it since 2.6.0)

  • Property mode set to 100644
File size: 17.9 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[0e788f5]4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
[b7d3cc34]5  \********************************************************************/
6
7/*
8 * nogaim
9 *
10 * Gaim without gaim - for BitlBee
11 *
12 * This file contains functions called by the Gaim IM-modules. It's written
13 * from scratch for BitlBee and doesn't contain any code from Gaim anymore
14 * (except for the function names).
15 */
16
17/*
18  This program is free software; you can redistribute it and/or modify
19  it under the terms of the GNU General Public License as published by
20  the Free Software Foundation; either version 2 of the License, or
21  (at your option) any later version.
22
23  This program is distributed in the hope that it will be useful,
24  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  GNU General Public License for more details.
27
28  You should have received a copy of the GNU General Public License with
29  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
[6f10697]30  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
31  Fifth Floor, Boston, MA  02110-1301  USA
[b7d3cc34]32*/
33
34#define BITLBEE_CORE
35#include <ctype.h>
36
[4cf80bb]37#include "nogaim.h"
38
[b7d3cc34]39GSList *connections;
40
[65e2ce1]41#ifdef WITH_PLUGINS
[7b23afd]42gboolean load_plugin(char *path)
43{
44        void (*init_function) (void);
45       
46        GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
47
48        if(!mod) {
[8ad90fb]49                log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error());
[7b23afd]50                return FALSE;
51        }
52
53        if(!g_module_symbol(mod,"init_plugin",(gpointer *) &init_function)) {
54                log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
55                return FALSE;
56        }
57
58        init_function();
59
60        return TRUE;
61}
[b7d3cc34]62
[65e2ce1]63void load_plugins(void)
64{
65        GDir *dir;
66        GError *error = NULL;
67
[4bfca70]68        dir = g_dir_open(global.conf->plugindir, 0, &error);
[65e2ce1]69
70        if (dir) {
71                const gchar *entry;
72                char *path;
73
74                while ((entry = g_dir_read_name(dir))) {
[4bfca70]75                        path = g_build_filename(global.conf->plugindir, entry, NULL);
[65e2ce1]76                        if(!path) {
77                                log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
78                                continue;
79                        }
80
81                        load_plugin(path);
82
83                        g_free(path);
84                }
85
86                g_dir_close(dir);
87        }
88}
89#endif
[b7d3cc34]90
[7b23afd]91GList *protocols = NULL;
92 
93void register_protocol (struct prpl *p)
94{
[90cd6c4]95        int i;
96        gboolean refused = global.conf->protocols != NULL;
97 
98        for (i = 0; global.conf->protocols && global.conf->protocols[i]; i++)
99        {
100                if (g_strcasecmp(p->name, global.conf->protocols[i]) == 0)
101                        refused = FALSE;
102        }
103
104        if (refused)
105                log_message(LOGLVL_WARNING, "Protocol %s disabled\n", p->name);
106        else
107                protocols = g_list_append(protocols, p);
[7b23afd]108}
109
110struct prpl *find_protocol(const char *name)
111{
112        GList *gl;
[e248c7f]113       
114        for( gl = protocols; gl; gl = gl->next )
[7b23afd]115        {
116                struct prpl *proto = gl->data;
[e248c7f]117               
118                if( g_strcasecmp( proto->name, name ) == 0 )
[7b23afd]119                        return proto;
120        }
[e248c7f]121       
[7b23afd]122        return NULL;
123}
124
[b7d3cc34]125void nogaim_init()
126{
[0da65d5]127        extern void msn_initmodule();
128        extern void oscar_initmodule();
129        extern void byahoo_initmodule();
130        extern void jabber_initmodule();
[1b221e0]131        extern void twitter_initmodule();
[796da03]132        extern void purple_initmodule();
[7b23afd]133
[b7d3cc34]134#ifdef WITH_MSN
[0da65d5]135        msn_initmodule();
[b7d3cc34]136#endif
137
138#ifdef WITH_OSCAR
[0da65d5]139        oscar_initmodule();
[b7d3cc34]140#endif
141       
142#ifdef WITH_YAHOO
[0da65d5]143        byahoo_initmodule();
[b7d3cc34]144#endif
145       
146#ifdef WITH_JABBER
[0da65d5]147        jabber_initmodule();
[b7d3cc34]148#endif
[7b23afd]149
[1b221e0]150#ifdef WITH_TWITTER
151        twitter_initmodule();
152#endif
153
[796da03]154#ifdef WITH_PURPLE
155        purple_initmodule();
156#endif
[7b23afd]157
[65e2ce1]158#ifdef WITH_PLUGINS
159        load_plugins();
[b7d3cc34]160#endif
161}
162
163GSList *get_connections() { return connections; }
164
[84b045d]165struct im_connection *imcb_new( account_t *acc )
[b7d3cc34]166{
[0da65d5]167        struct im_connection *ic;
[b7d3cc34]168       
[0da65d5]169        ic = g_new0( struct im_connection, 1 );
[b7d3cc34]170       
[81e04e1]171        ic->bee = acc->bee;
[0da65d5]172        ic->acc = acc;
173        acc->ic = ic;
[b7d3cc34]174       
[0da65d5]175        connections = g_slist_append( connections, ic );
[b7d3cc34]176       
[0da65d5]177        return( ic );
[b7d3cc34]178}
179
[aef4828]180void imc_free( struct im_connection *ic )
[b7d3cc34]181{
182        account_t *a;
183       
184        /* Destroy the pointer to this connection from the account list */
[81e04e1]185        for( a = ic->bee->accounts; a; a = a->next )
[0da65d5]186                if( a->ic == ic )
[b7d3cc34]187                {
[0da65d5]188                        a->ic = NULL;
[b7d3cc34]189                        break;
190                }
191       
[0da65d5]192        connections = g_slist_remove( connections, ic );
193        g_free( ic );
[b7d3cc34]194}
195
[aef4828]196static void serv_got_crap( struct im_connection *ic, char *format, ... )
[b7d3cc34]197{
198        va_list params;
[e27661d]199        char *text;
[dfde8e0]200        account_t *a;
[b7d3cc34]201       
202        va_start( params, format );
[e27661d]203        text = g_strdup_vprintf( format, params );
[b7d3cc34]204        va_end( params );
205
[81e04e1]206        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
207            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
[e27661d]208                strip_html( text );
[b7d3cc34]209       
[dfde8e0]210        /* Try to find a different connection on the same protocol. */
[81e04e1]211        for( a = ic->bee->accounts; a; a = a->next )
[0da65d5]212                if( a->prpl == ic->acc->prpl && a->ic != ic )
[dfde8e0]213                        break;
214       
[e27661d]215        /* If we found one, include the screenname in the message. */
[dfde8e0]216        if( a )
[81e04e1]217                /* FIXME(wilmer): ui_log callback or so */
[17f057d]218                irc_rootmsg( ic->bee->ui_data, "%s - %s", ic->acc->tag, text );
[dfde8e0]219        else
[e67e513]220                irc_rootmsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
[7b07dc6]221       
[e27661d]222        g_free( text );
[b7d3cc34]223}
224
[84b045d]225void imcb_log( struct im_connection *ic, char *format, ... )
[aef4828]226{
227        va_list params;
228        char *text;
229       
230        va_start( params, format );
231        text = g_strdup_vprintf( format, params );
232        va_end( params );
233       
234        if( ic->flags & OPT_LOGGED_IN )
235                serv_got_crap( ic, "%s", text );
236        else
237                serv_got_crap( ic, "Logging in: %s", text );
238       
239        g_free( text );
240}
241
[84b045d]242void imcb_error( struct im_connection *ic, char *format, ... )
[aef4828]243{
244        va_list params;
245        char *text;
246       
247        va_start( params, format );
248        text = g_strdup_vprintf( format, params );
249        va_end( params );
250       
251        if( ic->flags & OPT_LOGGED_IN )
252                serv_got_crap( ic, "Error: %s", text );
253        else
[02bb9db]254                serv_got_crap( ic, "Login error: %s", text );
[aef4828]255       
256        g_free( text );
257}
258
[ba9edaa]259static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
[b7d3cc34]260{
[0da65d5]261        struct im_connection *ic = d;
[b7d3cc34]262       
[e132b60]263        if( ( ic->flags & OPT_PONGS ) && !( ic->flags & OPT_PONGED ) )
264        {
265                /* This protocol is expected to ack keepalives and hasn't
266                   since the last time we were here. */
267                imcb_error( ic, "Connection timeout" );
268                imc_logout( ic, TRUE );
269                return FALSE;
270        }
271        ic->flags &= ~OPT_PONGED;
272       
[0da65d5]273        if( ic->acc->prpl->keepalive )
274                ic->acc->prpl->keepalive( ic );
[b7d3cc34]275       
276        return TRUE;
277}
278
[e132b60]279void start_keepalives( struct im_connection *ic, int interval )
280{
281        b_event_remove( ic->keepalive );
282        ic->keepalive = b_timeout_add( interval, send_keepalive, ic );
283       
284        /* Connecting successfully counts as a first successful pong. */
285        if( ic->flags & OPT_PONGS )
286                ic->flags |= OPT_PONGED;
287}
288
[84b045d]289void imcb_connected( struct im_connection *ic )
[b7d3cc34]290{
291        /* MSN servers sometimes redirect you to a different server and do
[84c1a0a]292           the whole login sequence again, so these "late" calls to this
[b7d3cc34]293           function should be handled correctly. (IOW, ignored) */
[0da65d5]294        if( ic->flags & OPT_LOGGED_IN )
[b7d3cc34]295                return;
[11e7828]296
297        if( ic->acc->flags & ACC_FLAG_LOCAL )
298        {
299                GHashTableIter nicks;
300                gpointer k, v;
301                g_hash_table_iter_init( &nicks, ic->acc->nicks );
302                while( g_hash_table_iter_next( &nicks, &k, &v ) )
303                {
304                        ic->acc->prpl->add_buddy( ic, (char*) k, NULL );
305                }
306        }
[b7d3cc34]307       
[84b045d]308        imcb_log( ic, "Logged in" );
[b7d3cc34]309       
[0da65d5]310        ic->flags |= OPT_LOGGED_IN;
[aef2077]311        start_keepalives( ic, 60000 );
[b7d3cc34]312       
[58adb7e]313        /* Necessary to send initial presence status, even if we're not away. */
314        imc_away_send_update( ic );
[280e655]315       
316        /* Apparently we're connected successfully, so reset the
317           exponential backoff timer. */
318        ic->acc->auto_reconnect_delay = 0;
[3611717]319       
[5c7b45c]320        if( ic->bee->ui->imc_connected )
321                ic->bee->ui->imc_connected( ic );
[b7d3cc34]322}
323
[ba9edaa]324gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
[b7d3cc34]325{
326        account_t *a = data;
327       
328        a->reconnect = 0;
[81e04e1]329        account_on( a->bee, a );
[b7d3cc34]330       
331        return( FALSE );        /* Only have to run the timeout once */
332}
333
334void cancel_auto_reconnect( account_t *a )
335{
[c98be00]336        b_event_remove( a->reconnect );
[b7d3cc34]337        a->reconnect = 0;
338}
339
[c2fb3809]340void imc_logout( struct im_connection *ic, int allow_reconnect )
[b7d3cc34]341{
[81e04e1]342        bee_t *bee = ic->bee;
[b7d3cc34]343        account_t *a;
[81e04e1]344        GSList *l;
[4230221]345        int delay;
[b7d3cc34]346       
[8d74291]347        /* Nested calls might happen sometimes, this is probably the best
348           place to catch them. */
[0da65d5]349        if( ic->flags & OPT_LOGGING_OUT )
[8d74291]350                return;
[66f783f]351        else
[0da65d5]352                ic->flags |= OPT_LOGGING_OUT;
[8d74291]353       
[5c7b45c]354        if( ic->bee->ui->imc_disconnected )
355                ic->bee->ui->imc_disconnected( ic );
356       
[84b045d]357        imcb_log( ic, "Signing off.." );
[fb62f81f]358       
[0dd6570]359        /* TBH I don't remember anymore why I didn't just use ic->acc... */
360        for( a = bee->accounts; a; a = a->next )
361                if( a->ic == ic )
362                        break;
363       
364        if( a && !allow_reconnect && !( ic->flags & OPT_LOGGED_IN ) &&
365            set_getbool( &a->set, "oauth" ) )
366        {
367                /* If this account supports OAuth, we're not logged in yet and
368                   not allowed to retry, assume there were auth issues. Give a
369                   helpful message on what might be necessary to fix this. */
370                imcb_log( ic, "If you're having problems logging in, try re-requesting "
371                          "an OAuth token: account %s set password \"\"", a->tag );
372        }
373       
[eabc9d2]374        for( l = bee->users; l; )
[b7d3cc34]375        {
[81e04e1]376                bee_user_t *bu = l->data;
[eabc9d2]377                GSList *next = l->next;
[81e04e1]378               
379                if( bu->ic == ic )
[eabc9d2]380                        bee_user_free( bee, bu );
381               
382                l = next;
[b7d3cc34]383        }
384       
[be7a180]385        b_event_remove( ic->keepalive );
386        ic->keepalive = 0;
387        ic->acc->prpl->logout( ic );
388        b_event_remove( ic->inpa );
389       
390        g_free( ic->away );
391        ic->away = NULL;
392       
[3663bb3]393        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
[b7d3cc34]394       
395        if( !a )
396        {
397                /* Uhm... This is very sick. */
398        }
[81e04e1]399        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
[4230221]400                 set_getbool( &a->set, "auto_reconnect" ) &&
401                 ( delay = account_reconnect_delay( a ) ) > 0 )
[b7d3cc34]402        {
[84b045d]403                imcb_log( ic, "Reconnecting in %d seconds..", delay );
[c98be00]404                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
[b7d3cc34]405        }
406       
[aef4828]407        imc_free( ic );
[b7d3cc34]408}
409
[9143aeb]410void imcb_ask( struct im_connection *ic, char *msg, void *data,
411               query_callback doit, query_callback dont )
[b7d3cc34]412{
[1e52e1f]413        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, g_free, data );
[b7d3cc34]414}
415
[d0527c1]416void imcb_ask_with_free( struct im_connection *ic, char *msg, void *data,
417                         query_callback doit, query_callback dont, query_callback myfree )
418{
419        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, myfree, data );
420}
421
[c6ca3ee]422void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
[b7d3cc34]423{
[81e04e1]424        bee_user_t *bu;
425        bee_t *bee = ic->bee;
[8b61469]426        bee_group_t *oldg;
[b7d3cc34]427       
[4e608d6]428        if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
[ad404ab]429                bu = bee_user_new( bee, ic, handle, 0 );
[b7d3cc34]430       
[8b61469]431        oldg = bu->group;
[7aadd71]432        bu->group = bee_group_by_name( bee, group, TRUE );
[7e83e8e4]433       
[8b61469]434        if( bee->ui->user_group && bu->group != oldg )
[7e83e8e4]435                bee->ui->user_group( bee, bu );
[b7d3cc34]436}
437
[1d39159]438void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
[b7d3cc34]439{
[1d39159]440        bee_t *bee = ic->bee;
441        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
[b7d3cc34]442       
[1d39159]443        if( !bu || !fullname ) return;
[b7d3cc34]444       
[17a6ee9]445        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
[b7d3cc34]446        {
[1d39159]447                g_free( bu->fullname );
448                bu->fullname = g_strdup( fullname );
[b7d3cc34]449               
[1d39159]450                if( bee->ui->user_fullname )
451                        bee->ui->user_fullname( bee, bu );
[b7d3cc34]452        }
453}
454
[c6ca3ee]455void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
[998b103]456{
[eabc9d2]457        bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
[998b103]458}
459
[d06eabf]460/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
461   modules to suggest a nickname for a handle. */
[fb00989]462void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
[d06eabf]463{
[6ef9065]464        bee_t *bee = ic->bee;
465        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
[d06eabf]466       
[6ef9065]467        if( !bu || !nick ) return;
468       
[69b896b]469        g_free( bu->nick );
470        bu->nick = g_strdup( nick );
471       
[6ef9065]472        if( bee->ui->user_nick_hint )
473                bee->ui->user_nick_hint( bee, bu, nick );
[d06eabf]474}
[b7d3cc34]475
476
[fa295e36]477struct imcb_ask_cb_data
[7bf0f5f0]478{
[0da65d5]479        struct im_connection *ic;
[7bf0f5f0]480        char *handle;
481};
482
[fa295e36]483static void imcb_ask_auth_cb_no( void *data )
[7bf0f5f0]484{
[fa295e36]485        struct imcb_ask_cb_data *cbd = data;
486       
487        cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
488       
489        g_free( cbd->handle );
490        g_free( cbd );
491}
492
493static void imcb_ask_auth_cb_yes( void *data )
494{
495        struct imcb_ask_cb_data *cbd = data;
496       
497        cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
498       
499        g_free( cbd->handle );
500        g_free( cbd );
501}
502
503void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
504{
505        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
506        char *s, *realname_ = NULL;
507       
508        if( realname != NULL )
509                realname_ = g_strdup_printf( " (%s)", realname );
510       
511        s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
[daae10f]512                             handle, realname_ ? realname_ : "" );
[fa295e36]513       
514        g_free( realname_ );
515       
516        data->ic = ic;
517        data->handle = g_strdup( handle );
[e00da63]518        query_add( (irc_t *) ic->bee->ui_data, ic, s,
[1e52e1f]519                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data );
[fa295e36]520}
521
522
523static void imcb_ask_add_cb_no( void *data )
524{
525        g_free( ((struct imcb_ask_cb_data*)data)->handle );
[7bf0f5f0]526        g_free( data );
527}
528
[fa295e36]529static void imcb_ask_add_cb_yes( void *data )
[7bf0f5f0]530{
[fa295e36]531        struct imcb_ask_cb_data *cbd = data;
[7bf0f5f0]532       
[fa295e36]533        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
[9143aeb]534       
[daae10f]535        imcb_ask_add_cb_no( data );
[7bf0f5f0]536}
537
[fa295e36]538void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
[b7d3cc34]539{
[fa295e36]540        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
[7bf0f5f0]541        char *s;
542       
543        /* TODO: Make a setting for this! */
[e00da63]544        if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
[7bf0f5f0]545                return;
546       
547        s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle );
548       
[0da65d5]549        data->ic = ic;
[7bf0f5f0]550        data->handle = g_strdup( handle );
[e00da63]551        query_add( (irc_t *) ic->bee->ui_data, ic, s,
[1e52e1f]552                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data );
[b7d3cc34]553}
554
[81e04e1]555struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
556{
557        return bee_user_by_handle( ic->bee, ic, handle );
[b7d3cc34]558}
559
[226fce1]560/* The plan is to not allow straight calls to prpl functions anymore, but do
561   them all from some wrappers. We'll start to define some down here: */
562
[84b045d]563int imc_chat_msg( struct groupchat *c, char *msg, int flags )
[b7d3cc34]564{
[e27661d]565        char *buf = NULL;
[b7d3cc34]566       
[6bbb939]567        if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
[e27661d]568        {
569                buf = escape_html( msg );
[b7d3cc34]570                msg = buf;
571        }
572       
[f6c963b]573        c->ic->acc->prpl->chat_msg( c, msg, flags );
[e27661d]574        g_free( buf );
575       
[0da65d5]576        return 1;
[b7d3cc34]577}
[226fce1]578
[34fbbf9]579static char *imc_away_state_find( GList *gcm, char *away, char **message );
[226fce1]580
[58adb7e]581int imc_away_send_update( struct im_connection *ic )
[226fce1]582{
[3e1ef92c]583        char *away, *msg = NULL;
[226fce1]584       
[91cec2f]585        if( ic->acc->prpl->away_states == NULL ||
586            ic->acc->prpl->set_away == NULL )
587                return 0;
588       
[58adb7e]589        away = set_getstr( &ic->acc->set, "away" ) ?
[81e04e1]590             : set_getstr( &ic->bee->set, "away" );
[34fbbf9]591        if( away && *away )
[226fce1]592        {
[34fbbf9]593                GList *m = ic->acc->prpl->away_states( ic );
[58adb7e]594                msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL;
595                away = imc_away_state_find( m, away, &msg ) ? : m->data;
596        }
597        else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE )
598        {
599                away = NULL;
600                msg = set_getstr( &ic->acc->set, "status" ) ?
[81e04e1]601                    : set_getstr( &ic->bee->set, "status" );
[226fce1]602        }
603       
[58adb7e]604        ic->acc->prpl->set_away( ic, away, msg );
[226fce1]605       
[34fbbf9]606        return 1;
[226fce1]607}
608
[84b045d]609static char *imc_away_alias_list[8][5] =
[226fce1]610{
611        { "Away from computer", "Away", "Extended away", NULL },
612        { "NA", "N/A", "Not available", NULL },
613        { "Busy", "Do not disturb", "DND", "Occupied", NULL },
614        { "Be right back", "BRB", NULL },
615        { "On the phone", "Phone", "On phone", NULL },
616        { "Out to lunch", "Lunch", "Food", NULL },
617        { "Invisible", "Hidden" },
618        { NULL }
619};
620
[34fbbf9]621static char *imc_away_state_find( GList *gcm, char *away, char **message )
[226fce1]622{
623        GList *m;
624        int i, j;
625       
[34fbbf9]626        for( m = gcm; m; m = m->next )
627                if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
628                {
629                        /* At least the Yahoo! module works better if message
630                           contains no data unless it adds something to what
631                           we have in state already. */
632                        if( strlen( m->data ) == strlen( away ) )
633                                *message = NULL;
634                       
635                        return m->data;
636                }
637       
[84b045d]638        for( i = 0; *imc_away_alias_list[i]; i ++ )
[226fce1]639        {
[34fbbf9]640                int keep_message;
641               
[84b045d]642                for( j = 0; imc_away_alias_list[i][j]; j ++ )
643                        if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )
[34fbbf9]644                        {
645                                keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );
[226fce1]646                                break;
[34fbbf9]647                        }
[226fce1]648               
[84b045d]649                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
[226fce1]650                        continue;                       /* is not what we want. Next!    */
651               
652                /* Now find an entry in this row which exists in gcm */
[84b045d]653                for( j = 0; imc_away_alias_list[i][j]; j ++ )
[226fce1]654                {
[34fbbf9]655                        for( m = gcm; m; m = m->next )
[84b045d]656                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
[34fbbf9]657                                {
658                                        if( !keep_message )
659                                                *message = NULL;
660                                       
661                                        return imc_away_alias_list[i][j];
662                                }
[226fce1]663                }
[34fbbf9]664               
665                /* No need to look further, apparently this state doesn't
666                   have any good alias for this protocol. */
667                break;
[226fce1]668        }
669       
[34fbbf9]670        return NULL;
[226fce1]671}
[da3b536]672
[84b045d]673void imc_add_allow( struct im_connection *ic, char *handle )
[da3b536]674{
[0da65d5]675        if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]676        {
[0da65d5]677                ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );
[da3b536]678        }
679       
[0da65d5]680        ic->acc->prpl->add_permit( ic, handle );
[da3b536]681}
682
[84b045d]683void imc_rem_allow( struct im_connection *ic, char *handle )
[da3b536]684{
685        GSList *l;
686       
[0da65d5]687        if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]688        {
689                g_free( l->data );
[0da65d5]690                ic->permit = g_slist_delete_link( ic->permit, l );
[da3b536]691        }
692       
[0da65d5]693        ic->acc->prpl->rem_permit( ic, handle );
[da3b536]694}
695
[84b045d]696void imc_add_block( struct im_connection *ic, char *handle )
[da3b536]697{
[0da65d5]698        if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]699        {
[0da65d5]700                ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );
[da3b536]701        }
702       
[0da65d5]703        ic->acc->prpl->add_deny( ic, handle );
[da3b536]704}
705
[84b045d]706void imc_rem_block( struct im_connection *ic, char *handle )
[da3b536]707{
708        GSList *l;
709       
[0da65d5]710        if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]711        {
712                g_free( l->data );
[0da65d5]713                ic->deny = g_slist_delete_link( ic->deny, l );
[da3b536]714        }
715       
[0da65d5]716        ic->acc->prpl->rem_deny( ic, handle );
[da3b536]717}
[85023c6]718
719void imcb_clean_handle( struct im_connection *ic, char *handle )
720{
721        /* Accepts a handle and does whatever is necessary to make it
722           BitlBee-friendly. Currently this means removing everything
723           outside 33-127 (ASCII printable excl spaces), @ (only one
724           is allowed) and ! and : */
725        char out[strlen(handle)+1];
726        int s, d;
727       
728        s = d = 0;
729        while( handle[s] )
730        {
731                if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' &&
732                    ( handle[s] & 0x80 ) == 0 )
733                {
734                        if( handle[s] == '@' )
735                        {
736                                /* See if we got an @ already? */
737                                out[d] = 0;
738                                if( strchr( out, '@' ) )
739                                        continue;
740                        }
741                       
742                        out[d++] = handle[s];
743                }
744                s ++;
745        }
746        out[d] = handle[s];
747       
748        strcpy( handle, out );
749}
Note: See TracBrowser for help on using the repository browser.