source: protocols/nogaim.c @ 48b75f1

Last change on this file since 48b75f1 was 0e788f5, checked in by Wilmer van der Gaast <wilmer@…>, at 2013-02-21T19:15:59Z

I'm still bored on a long flight. Wrote a script to automatically update
my copyright mentions since some were getting pretty stale. Left files not
touched since before 2012 alone so that this change doesn't touch almost
EVERY source file.

  • Property mode set to 100644
File size: 17.6 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;
30  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
31  Suite 330, Boston, MA  02111-1307  USA
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;
296       
[84b045d]297        imcb_log( ic, "Logged in" );
[b7d3cc34]298       
[0da65d5]299        ic->flags |= OPT_LOGGED_IN;
[aef2077]300        start_keepalives( ic, 60000 );
[b7d3cc34]301       
[58adb7e]302        /* Necessary to send initial presence status, even if we're not away. */
303        imc_away_send_update( ic );
[280e655]304       
305        /* Apparently we're connected successfully, so reset the
306           exponential backoff timer. */
307        ic->acc->auto_reconnect_delay = 0;
[3611717]308       
[5c7b45c]309        if( ic->bee->ui->imc_connected )
310                ic->bee->ui->imc_connected( ic );
[b7d3cc34]311}
312
[ba9edaa]313gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
[b7d3cc34]314{
315        account_t *a = data;
316       
317        a->reconnect = 0;
[81e04e1]318        account_on( a->bee, a );
[b7d3cc34]319       
320        return( FALSE );        /* Only have to run the timeout once */
321}
322
323void cancel_auto_reconnect( account_t *a )
324{
[c98be00]325        b_event_remove( a->reconnect );
[b7d3cc34]326        a->reconnect = 0;
327}
328
[c2fb3809]329void imc_logout( struct im_connection *ic, int allow_reconnect )
[b7d3cc34]330{
[81e04e1]331        bee_t *bee = ic->bee;
[b7d3cc34]332        account_t *a;
[81e04e1]333        GSList *l;
[4230221]334        int delay;
[b7d3cc34]335       
[8d74291]336        /* Nested calls might happen sometimes, this is probably the best
337           place to catch them. */
[0da65d5]338        if( ic->flags & OPT_LOGGING_OUT )
[8d74291]339                return;
[66f783f]340        else
[0da65d5]341                ic->flags |= OPT_LOGGING_OUT;
[8d74291]342       
[5c7b45c]343        if( ic->bee->ui->imc_disconnected )
344                ic->bee->ui->imc_disconnected( ic );
345       
[84b045d]346        imcb_log( ic, "Signing off.." );
[fb62f81f]347       
[0dd6570]348        /* TBH I don't remember anymore why I didn't just use ic->acc... */
349        for( a = bee->accounts; a; a = a->next )
350                if( a->ic == ic )
351                        break;
352       
353        if( a && !allow_reconnect && !( ic->flags & OPT_LOGGED_IN ) &&
354            set_getbool( &a->set, "oauth" ) )
355        {
356                /* If this account supports OAuth, we're not logged in yet and
357                   not allowed to retry, assume there were auth issues. Give a
358                   helpful message on what might be necessary to fix this. */
359                imcb_log( ic, "If you're having problems logging in, try re-requesting "
360                          "an OAuth token: account %s set password \"\"", a->tag );
361        }
362       
[eabc9d2]363        for( l = bee->users; l; )
[b7d3cc34]364        {
[81e04e1]365                bee_user_t *bu = l->data;
[eabc9d2]366                GSList *next = l->next;
[81e04e1]367               
368                if( bu->ic == ic )
[eabc9d2]369                        bee_user_free( bee, bu );
370               
371                l = next;
[b7d3cc34]372        }
373       
[be7a180]374        b_event_remove( ic->keepalive );
375        ic->keepalive = 0;
376        ic->acc->prpl->logout( ic );
377        b_event_remove( ic->inpa );
378       
379        g_free( ic->away );
380        ic->away = NULL;
381       
[3663bb3]382        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
[b7d3cc34]383       
384        if( !a )
385        {
386                /* Uhm... This is very sick. */
387        }
[81e04e1]388        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
[4230221]389                 set_getbool( &a->set, "auto_reconnect" ) &&
390                 ( delay = account_reconnect_delay( a ) ) > 0 )
[b7d3cc34]391        {
[84b045d]392                imcb_log( ic, "Reconnecting in %d seconds..", delay );
[c98be00]393                a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a );
[b7d3cc34]394        }
395       
[aef4828]396        imc_free( ic );
[b7d3cc34]397}
398
[9143aeb]399void imcb_ask( struct im_connection *ic, char *msg, void *data,
400               query_callback doit, query_callback dont )
[b7d3cc34]401{
[1e52e1f]402        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, g_free, data );
[b7d3cc34]403}
404
[d0527c1]405void imcb_ask_with_free( struct im_connection *ic, char *msg, void *data,
406                         query_callback doit, query_callback dont, query_callback myfree )
407{
408        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, myfree, data );
409}
410
[c6ca3ee]411void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
[b7d3cc34]412{
[81e04e1]413        bee_user_t *bu;
414        bee_t *bee = ic->bee;
[8b61469]415        bee_group_t *oldg;
[b7d3cc34]416       
[4e608d6]417        if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
[ad404ab]418                bu = bee_user_new( bee, ic, handle, 0 );
[b7d3cc34]419       
[8b61469]420        oldg = bu->group;
[7aadd71]421        bu->group = bee_group_by_name( bee, group, TRUE );
[7e83e8e4]422       
[8b61469]423        if( bee->ui->user_group && bu->group != oldg )
[7e83e8e4]424                bee->ui->user_group( bee, bu );
[b7d3cc34]425}
426
[1d39159]427void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
[b7d3cc34]428{
[1d39159]429        bee_t *bee = ic->bee;
430        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
[b7d3cc34]431       
[1d39159]432        if( !bu || !fullname ) return;
[b7d3cc34]433       
[17a6ee9]434        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
[b7d3cc34]435        {
[1d39159]436                g_free( bu->fullname );
437                bu->fullname = g_strdup( fullname );
[b7d3cc34]438               
[1d39159]439                if( bee->ui->user_fullname )
440                        bee->ui->user_fullname( bee, bu );
[b7d3cc34]441        }
442}
443
[c6ca3ee]444void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
[998b103]445{
[eabc9d2]446        bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
[998b103]447}
448
[d06eabf]449/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
450   modules to suggest a nickname for a handle. */
[fb00989]451void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
[d06eabf]452{
[6ef9065]453        bee_t *bee = ic->bee;
454        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
[d06eabf]455       
[6ef9065]456        if( !bu || !nick ) return;
457       
[69b896b]458        g_free( bu->nick );
459        bu->nick = g_strdup( nick );
460       
[6ef9065]461        if( bee->ui->user_nick_hint )
462                bee->ui->user_nick_hint( bee, bu, nick );
[d06eabf]463}
[b7d3cc34]464
465
[fa295e36]466struct imcb_ask_cb_data
[7bf0f5f0]467{
[0da65d5]468        struct im_connection *ic;
[7bf0f5f0]469        char *handle;
470};
471
[fa295e36]472static void imcb_ask_auth_cb_no( void *data )
[7bf0f5f0]473{
[fa295e36]474        struct imcb_ask_cb_data *cbd = data;
475       
476        cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
477       
478        g_free( cbd->handle );
479        g_free( cbd );
480}
481
482static void imcb_ask_auth_cb_yes( void *data )
483{
484        struct imcb_ask_cb_data *cbd = data;
485       
486        cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
487       
488        g_free( cbd->handle );
489        g_free( cbd );
490}
491
492void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
493{
494        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
495        char *s, *realname_ = NULL;
496       
497        if( realname != NULL )
498                realname_ = g_strdup_printf( " (%s)", realname );
499       
500        s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
[daae10f]501                             handle, realname_ ? realname_ : "" );
[fa295e36]502       
503        g_free( realname_ );
504       
505        data->ic = ic;
506        data->handle = g_strdup( handle );
[e00da63]507        query_add( (irc_t *) ic->bee->ui_data, ic, s,
[1e52e1f]508                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data );
[fa295e36]509}
510
511
512static void imcb_ask_add_cb_no( void *data )
513{
514        g_free( ((struct imcb_ask_cb_data*)data)->handle );
[7bf0f5f0]515        g_free( data );
516}
517
[fa295e36]518static void imcb_ask_add_cb_yes( void *data )
[7bf0f5f0]519{
[fa295e36]520        struct imcb_ask_cb_data *cbd = data;
[7bf0f5f0]521       
[fa295e36]522        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
[9143aeb]523       
[daae10f]524        imcb_ask_add_cb_no( data );
[7bf0f5f0]525}
526
[fa295e36]527void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
[b7d3cc34]528{
[fa295e36]529        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
[7bf0f5f0]530        char *s;
531       
532        /* TODO: Make a setting for this! */
[e00da63]533        if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
[7bf0f5f0]534                return;
535       
536        s = g_strdup_printf( "The user %s is not in your buddy list yet. Do you want to add him/her now?", handle );
537       
[0da65d5]538        data->ic = ic;
[7bf0f5f0]539        data->handle = g_strdup( handle );
[e00da63]540        query_add( (irc_t *) ic->bee->ui_data, ic, s,
[1e52e1f]541                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data );
[b7d3cc34]542}
543
[81e04e1]544struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
545{
546        return bee_user_by_handle( ic->bee, ic, handle );
[b7d3cc34]547}
548
[226fce1]549/* The plan is to not allow straight calls to prpl functions anymore, but do
550   them all from some wrappers. We'll start to define some down here: */
551
[84b045d]552int imc_chat_msg( struct groupchat *c, char *msg, int flags )
[b7d3cc34]553{
[e27661d]554        char *buf = NULL;
[b7d3cc34]555       
[6bbb939]556        if( ( c->ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
[e27661d]557        {
558                buf = escape_html( msg );
[b7d3cc34]559                msg = buf;
560        }
561       
[f6c963b]562        c->ic->acc->prpl->chat_msg( c, msg, flags );
[e27661d]563        g_free( buf );
564       
[0da65d5]565        return 1;
[b7d3cc34]566}
[226fce1]567
[34fbbf9]568static char *imc_away_state_find( GList *gcm, char *away, char **message );
[226fce1]569
[58adb7e]570int imc_away_send_update( struct im_connection *ic )
[226fce1]571{
[3e1ef92c]572        char *away, *msg = NULL;
[226fce1]573       
[91cec2f]574        if( ic->acc->prpl->away_states == NULL ||
575            ic->acc->prpl->set_away == NULL )
576                return 0;
577       
[58adb7e]578        away = set_getstr( &ic->acc->set, "away" ) ?
[81e04e1]579             : set_getstr( &ic->bee->set, "away" );
[34fbbf9]580        if( away && *away )
[226fce1]581        {
[34fbbf9]582                GList *m = ic->acc->prpl->away_states( ic );
[58adb7e]583                msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL;
584                away = imc_away_state_find( m, away, &msg ) ? : m->data;
585        }
586        else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE )
587        {
588                away = NULL;
589                msg = set_getstr( &ic->acc->set, "status" ) ?
[81e04e1]590                    : set_getstr( &ic->bee->set, "status" );
[226fce1]591        }
592       
[58adb7e]593        ic->acc->prpl->set_away( ic, away, msg );
[226fce1]594       
[34fbbf9]595        return 1;
[226fce1]596}
597
[84b045d]598static char *imc_away_alias_list[8][5] =
[226fce1]599{
600        { "Away from computer", "Away", "Extended away", NULL },
601        { "NA", "N/A", "Not available", NULL },
602        { "Busy", "Do not disturb", "DND", "Occupied", NULL },
603        { "Be right back", "BRB", NULL },
604        { "On the phone", "Phone", "On phone", NULL },
605        { "Out to lunch", "Lunch", "Food", NULL },
606        { "Invisible", "Hidden" },
607        { NULL }
608};
609
[34fbbf9]610static char *imc_away_state_find( GList *gcm, char *away, char **message )
[226fce1]611{
612        GList *m;
613        int i, j;
614       
[34fbbf9]615        for( m = gcm; m; m = m->next )
616                if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 )
617                {
618                        /* At least the Yahoo! module works better if message
619                           contains no data unless it adds something to what
620                           we have in state already. */
621                        if( strlen( m->data ) == strlen( away ) )
622                                *message = NULL;
623                       
624                        return m->data;
625                }
626       
[84b045d]627        for( i = 0; *imc_away_alias_list[i]; i ++ )
[226fce1]628        {
[34fbbf9]629                int keep_message;
630               
[84b045d]631                for( j = 0; imc_away_alias_list[i][j]; j ++ )
632                        if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 )
[34fbbf9]633                        {
634                                keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );
[226fce1]635                                break;
[34fbbf9]636                        }
[226fce1]637               
[84b045d]638                if( !imc_away_alias_list[i][j] )        /* If we reach the end, this row */
[226fce1]639                        continue;                       /* is not what we want. Next!    */
640               
641                /* Now find an entry in this row which exists in gcm */
[84b045d]642                for( j = 0; imc_away_alias_list[i][j]; j ++ )
[226fce1]643                {
[34fbbf9]644                        for( m = gcm; m; m = m->next )
[84b045d]645                                if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 )
[34fbbf9]646                                {
647                                        if( !keep_message )
648                                                *message = NULL;
649                                       
650                                        return imc_away_alias_list[i][j];
651                                }
[226fce1]652                }
[34fbbf9]653               
654                /* No need to look further, apparently this state doesn't
655                   have any good alias for this protocol. */
656                break;
[226fce1]657        }
658       
[34fbbf9]659        return NULL;
[226fce1]660}
[da3b536]661
[84b045d]662void imc_add_allow( struct im_connection *ic, char *handle )
[da3b536]663{
[0da65d5]664        if( g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]665        {
[0da65d5]666                ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) );
[da3b536]667        }
668       
[0da65d5]669        ic->acc->prpl->add_permit( ic, handle );
[da3b536]670}
671
[84b045d]672void imc_rem_allow( struct im_connection *ic, char *handle )
[da3b536]673{
674        GSList *l;
675       
[0da65d5]676        if( ( l = g_slist_find_custom( ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]677        {
678                g_free( l->data );
[0da65d5]679                ic->permit = g_slist_delete_link( ic->permit, l );
[da3b536]680        }
681       
[0da65d5]682        ic->acc->prpl->rem_permit( ic, handle );
[da3b536]683}
684
[84b045d]685void imc_add_block( struct im_connection *ic, char *handle )
[da3b536]686{
[0da65d5]687        if( g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) == NULL )
[da3b536]688        {
[0da65d5]689                ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) );
[da3b536]690        }
691       
[0da65d5]692        ic->acc->prpl->add_deny( ic, handle );
[da3b536]693}
694
[84b045d]695void imc_rem_block( struct im_connection *ic, char *handle )
[da3b536]696{
697        GSList *l;
698       
[0da65d5]699        if( ( l = g_slist_find_custom( ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp ) ) )
[da3b536]700        {
701                g_free( l->data );
[0da65d5]702                ic->deny = g_slist_delete_link( ic->deny, l );
[da3b536]703        }
704       
[0da65d5]705        ic->acc->prpl->rem_deny( ic, handle );
[da3b536]706}
[85023c6]707
708void imcb_clean_handle( struct im_connection *ic, char *handle )
709{
710        /* Accepts a handle and does whatever is necessary to make it
711           BitlBee-friendly. Currently this means removing everything
712           outside 33-127 (ASCII printable excl spaces), @ (only one
713           is allowed) and ! and : */
714        char out[strlen(handle)+1];
715        int s, d;
716       
717        s = d = 0;
718        while( handle[s] )
719        {
720                if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' &&
721                    ( handle[s] & 0x80 ) == 0 )
722                {
723                        if( handle[s] == '@' )
724                        {
725                                /* See if we got an @ already? */
726                                out[d] = 0;
727                                if( strchr( out, '@' ) )
728                                        continue;
729                        }
730                       
731                        out[d++] = handle[s];
732                }
733                s ++;
734        }
735        out[d] = handle[s];
736       
737        strcpy( handle, out );
738}
Note: See TracBrowser for help on using the repository browser.