source: protocols/nogaim.c @ d28fe1c4

Last change on this file since d28fe1c4 was d28fe1c4, checked in by jgeboski <jgeboski@…>, at 2016-05-26T02:48:08Z

Implemented plugin information for external plugins

As of now, bitlbee will load any plugin regardless of the ABI it was
built against. This is really problematic when structures or symbols
are changed within bitlbee. This often leads to the plugin not loading
or the plugin acting in an undefined way. Typically a simple rebuild of
the plugin will resolve such issues, but many users have no idea that
this is required after they have updated bitlbee.

Furthermore, it is often times impossible to determine the version of
a plugin, without relying on the package manager of the system. This is
quite a problem when users are reporting bugs for external plugins, and
they have no idea what version of the plugin they are running. This is
also an opportunity to provide additional metadata for each plugin that
can then be displayed to the user.

Solving these issues is done by adding a new required function to each
plugin. The init_plugin_info() function must now be implemented along
with the init_plugin() function. This function then returns a static
structure, which retains all of the metadata for the plugin. Then this
is used by bitlbee to check the ABI version and provide information to
the user.

The introduction of the new function is required as bitlbee needs to
obtain the ABI version before calling init_plugin().

The boiler-plate implementation of init_plugin_info():

#ifdef BITLBEE_ABI_VERSION_CODE
struct plugin_info *init_plugin_info(void)
{

static struct plugin_info info = {

BITLBEE_ABI_VERSION_CODE, /* Required */
"plugin-name", /* Required */
"1.3.3.7", /* Required */
"A short description of the plugin", /* Optional */
"First Last <alias@…>", /* Optional */
"http://www.domain.tld" /* Optional */

};

return &info;

}
#endif

The example wraps the function declaration in an if block for backwards
compatibility with older bitlbee versions.

Displaying the plugin metadata is done via the newly added "plugins"
command, which simply dumps formatted data to the root channel.

  • Property mode set to 100644
File size: 19.4 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
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., 51 Franklin St.,
31  Fifth Floor, Boston, MA  02110-1301  USA
32*/
33
34#define BITLBEE_CORE
35#include <ctype.h>
36
37#include "nogaim.h"
38
39GSList *connections;
40
41#ifdef WITH_PLUGINS
42GList *plugins = NULL;
43
44static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data)
45{
46        const struct plugin_info *ia = a;
47        const struct plugin_info *ib = b;
48
49        return g_strcasecmp(ia->name, ib->name);
50}
51
52gboolean load_plugin(char *path)
53{
54        GList *l;
55        struct plugin_info *i;
56        struct plugin_info *info;
57        struct plugin_info * (*info_function) (void) = NULL;
58        void (*init_function) (void);
59
60        GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
61        gboolean loaded = FALSE;
62
63        if (!mod) {
64                log_message(LOGLVL_ERROR, "Error loading plugin `%s': %s\n", path, g_module_error());
65                return FALSE;
66        }
67
68        if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) {
69                info = info_function();
70
71                if (info->abiver != BITLBEE_ABI_VERSION_CODE) {
72                        log_message(LOGLVL_ERROR,
73                                    "`%s' uses ABI %u but %u is required\n",
74                                    path, info->abiver,
75                                    BITLBEE_ABI_VERSION_CODE);
76                        g_module_close(mod);
77                        return FALSE;
78                }
79
80                if (!info->name || !info->version) {
81                        log_message(LOGLVL_ERROR,
82                                    "Name or version missing from the "
83                                    "plugin info in `%s'\n", path);
84                        g_module_close(mod);
85                        return FALSE;
86                }
87
88                for (l = plugins; l; l = l->next) {
89                        i = l->data;
90
91                        if (g_strcasecmp(i->name, info->name) == 0) {
92                                loaded = TRUE;
93                                break;
94                        }
95                }
96
97                if (loaded) {
98                        log_message(LOGLVL_WARNING,
99                                    "%s plugin already loaded\n",
100                                    info->name);
101                        g_module_close(mod);
102                        return FALSE;
103                }
104        } else {
105                log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path);
106        }
107
108        if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) {
109                log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
110                g_module_close(mod);
111                return FALSE;
112        }
113
114        if (info_function) {
115                plugins = g_list_insert_sorted_with_data(plugins, info,
116                                                         pluginscmp, NULL);
117        }
118
119        init_function();
120        return TRUE;
121}
122
123void load_plugins(void)
124{
125        GDir *dir;
126        GError *error = NULL;
127
128        dir = g_dir_open(global.conf->plugindir, 0, &error);
129
130        if (dir) {
131                const gchar *entry;
132                char *path;
133
134                while ((entry = g_dir_read_name(dir))) {
135                        path = g_build_filename(global.conf->plugindir, entry, NULL);
136                        if (!path) {
137                                log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
138                                continue;
139                        }
140
141                        load_plugin(path);
142
143                        g_free(path);
144                }
145
146                g_dir_close(dir);
147        }
148}
149
150GList *get_plugins()
151{
152        return plugins;
153}
154#endif
155
156GList *protocols = NULL;
157GList *disabled_protocols = NULL;
158
159void register_protocol(struct prpl *p)
160{
161        int i;
162        gboolean refused = global.conf->protocols != NULL;
163
164        for (i = 0; global.conf->protocols && global.conf->protocols[i]; i++) {
165                if (g_strcasecmp(p->name, global.conf->protocols[i]) == 0) {
166                        refused = FALSE;
167                }
168        }
169
170        if (refused) {
171                disabled_protocols = g_list_append(disabled_protocols, p);
172        } else {
173                protocols = g_list_append(protocols, p);
174        }
175}
176
177static int proto_name_cmp(const void *proto_, const void *name)
178{
179        const struct prpl *proto = proto_;
180        return g_strcasecmp(proto->name, name);
181}
182
183struct prpl *find_protocol(const char *name)
184{
185        GList *gl = g_list_find_custom(protocols, name, proto_name_cmp);
186        return gl ? gl->data: NULL;
187}
188
189gboolean is_protocol_disabled(const char *name)
190{
191        return g_list_find_custom(disabled_protocols, name, proto_name_cmp) != NULL;
192}
193
194void nogaim_init()
195{
196        extern void msn_initmodule();
197        extern void oscar_initmodule();
198        extern void byahoo_initmodule();
199        extern void jabber_initmodule();
200        extern void twitter_initmodule();
201        extern void purple_initmodule();
202
203#ifdef WITH_MSN
204        msn_initmodule();
205#endif
206
207#ifdef WITH_OSCAR
208        oscar_initmodule();
209#endif
210
211#ifdef WITH_YAHOO
212        byahoo_initmodule();
213#endif
214
215#ifdef WITH_JABBER
216        jabber_initmodule();
217#endif
218
219#ifdef WITH_TWITTER
220        twitter_initmodule();
221#endif
222
223#ifdef WITH_PURPLE
224        purple_initmodule();
225#endif
226
227#ifdef WITH_PLUGINS
228        load_plugins();
229#endif
230}
231
232GSList *get_connections()
233{
234        return connections;
235}
236
237struct im_connection *imcb_new(account_t *acc)
238{
239        struct im_connection *ic;
240
241        ic = g_new0(struct im_connection, 1);
242
243        ic->bee = acc->bee;
244        ic->acc = acc;
245        acc->ic = ic;
246
247        connections = g_slist_append(connections, ic);
248
249        return(ic);
250}
251
252void imc_free(struct im_connection *ic)
253{
254        account_t *a;
255
256        /* Destroy the pointer to this connection from the account list */
257        for (a = ic->bee->accounts; a; a = a->next) {
258                if (a->ic == ic) {
259                        a->ic = NULL;
260                        break;
261                }
262        }
263
264        connections = g_slist_remove(connections, ic);
265        g_free(ic);
266}
267
268static void serv_got_crap(struct im_connection *ic, char *format, ...)
269{
270        va_list params;
271        char *text;
272        account_t *a;
273
274        if (!ic->bee->ui->log) {
275                return;
276        }
277
278        va_start(params, format);
279        text = g_strdup_vprintf(format, params);
280        va_end(params);
281
282        if ((g_strcasecmp(set_getstr(&ic->bee->set, "strip_html"), "always") == 0) ||
283            ((ic->flags & OPT_DOES_HTML) && set_getbool(&ic->bee->set, "strip_html"))) {
284                strip_html(text);
285        }
286
287        /* Try to find a different connection on the same protocol. */
288        for (a = ic->bee->accounts; a; a = a->next) {
289                if (a->prpl == ic->acc->prpl && a->ic != ic) {
290                        break;
291                }
292        }
293
294        /* If we found one, include the screenname in the message. */
295        if (a) {
296                ic->bee->ui->log(ic->bee, ic->acc->tag, text);
297        } else {
298                ic->bee->ui->log(ic->bee, ic->acc->prpl->name, text);
299        }
300
301        g_free(text);
302}
303
304void imcb_log(struct im_connection *ic, char *format, ...)
305{
306        va_list params;
307        char *text;
308
309        va_start(params, format);
310        text = g_strdup_vprintf(format, params);
311        va_end(params);
312
313        if (ic->flags & OPT_LOGGED_IN) {
314                serv_got_crap(ic, "%s", text);
315        } else {
316                serv_got_crap(ic, "Logging in: %s", text);
317        }
318
319        g_free(text);
320}
321
322void imcb_error(struct im_connection *ic, char *format, ...)
323{
324        va_list params;
325        char *text;
326
327        va_start(params, format);
328        text = g_strdup_vprintf(format, params);
329        va_end(params);
330
331        if (ic->flags & OPT_LOGGED_IN) {
332                serv_got_crap(ic, "Error: %s", text);
333        } else {
334                serv_got_crap(ic, "Login error: %s", text);
335        }
336
337        g_free(text);
338}
339
340static gboolean send_keepalive(gpointer d, gint fd, b_input_condition cond)
341{
342        struct im_connection *ic = d;
343
344        if ((ic->flags & OPT_PONGS) && !(ic->flags & OPT_PONGED)) {
345                /* This protocol is expected to ack keepalives and hasn't
346                   since the last time we were here. */
347                imcb_error(ic, "Connection timeout");
348                imc_logout(ic, TRUE);
349                return FALSE;
350        }
351        ic->flags &= ~OPT_PONGED;
352
353        if (ic->acc->prpl->keepalive) {
354                ic->acc->prpl->keepalive(ic);
355        }
356
357        return TRUE;
358}
359
360void start_keepalives(struct im_connection *ic, int interval)
361{
362        b_event_remove(ic->keepalive);
363        ic->keepalive = b_timeout_add(interval, send_keepalive, ic);
364
365        /* Connecting successfully counts as a first successful pong. */
366        if (ic->flags & OPT_PONGS) {
367                ic->flags |= OPT_PONGED;
368        }
369}
370
371void imcb_connected(struct im_connection *ic)
372{
373        /* MSN servers sometimes redirect you to a different server and do
374           the whole login sequence again, so these "late" calls to this
375           function should be handled correctly. (IOW, ignored) */
376        if (ic->flags & OPT_LOGGED_IN) {
377                return;
378        }
379
380        if (ic->acc->flags & ACC_FLAG_LOCAL) {
381                GHashTableIter nicks;
382                gpointer k, v;
383                g_hash_table_iter_init(&nicks, ic->acc->nicks);
384                while (g_hash_table_iter_next(&nicks, &k, &v)) {
385                        ic->acc->prpl->add_buddy(ic, (char *) k, NULL);
386                }
387        }
388
389        imcb_log(ic, "Logged in");
390
391        ic->flags |= OPT_LOGGED_IN;
392        start_keepalives(ic, 60000);
393
394        /* Necessary to send initial presence status, even if we're not away. */
395        imc_away_send_update(ic);
396
397        /* Apparently we're connected successfully, so reset the
398           exponential backoff timer. */
399        ic->acc->auto_reconnect_delay = 0;
400
401        if (ic->bee->ui->imc_connected) {
402                ic->bee->ui->imc_connected(ic);
403        }
404}
405
406gboolean auto_reconnect(gpointer data, gint fd, b_input_condition cond)
407{
408        account_t *a = data;
409
410        a->reconnect = 0;
411        account_on(a->bee, a);
412
413        return(FALSE);          /* Only have to run the timeout once */
414}
415
416void cancel_auto_reconnect(account_t *a)
417{
418        b_event_remove(a->reconnect);
419        a->reconnect = 0;
420}
421
422void imc_logout(struct im_connection *ic, int allow_reconnect)
423{
424        bee_t *bee = ic->bee;
425        account_t *a;
426        GSList *l;
427        int delay;
428
429        /* Nested calls might happen sometimes, this is probably the best
430           place to catch them. */
431        if (ic->flags & OPT_LOGGING_OUT) {
432                return;
433        } else {
434                ic->flags |= OPT_LOGGING_OUT;
435        }
436
437        if (ic->bee->ui->imc_disconnected) {
438                ic->bee->ui->imc_disconnected(ic);
439        }
440
441        imcb_log(ic, "Signing off..");
442
443        /* TBH I don't remember anymore why I didn't just use ic->acc... */
444        for (a = bee->accounts; a; a = a->next) {
445                if (a->ic == ic) {
446                        break;
447                }
448        }
449
450        if (a && !allow_reconnect && !(ic->flags & OPT_LOGGED_IN) &&
451            set_getbool(&a->set, "oauth")) {
452                /* If this account supports OAuth, we're not logged in yet and
453                   not allowed to retry, assume there were auth issues. Give a
454                   helpful message on what might be necessary to fix this. */
455                imcb_log(ic, "If you're having problems logging in, try re-requesting "
456                         "an OAuth token: account %s set password \"\"", a->tag);
457        }
458
459        for (l = bee->users; l; ) {
460                bee_user_t *bu = l->data;
461                GSList *next = l->next;
462
463                if (bu->ic == ic) {
464                        bee_user_free(bee, bu);
465                }
466
467                l = next;
468        }
469
470        b_event_remove(ic->keepalive);
471        ic->keepalive = 0;
472        ic->acc->prpl->logout(ic);
473        b_event_remove(ic->inpa);
474
475        g_free(ic->away);
476        ic->away = NULL;
477
478        query_del_by_conn((irc_t *) ic->bee->ui_data, ic);
479
480        if (!a) {
481                /* Uhm... This is very sick. */
482        } else if (allow_reconnect && set_getbool(&bee->set, "auto_reconnect") &&
483                   set_getbool(&a->set, "auto_reconnect") &&
484                   (delay = account_reconnect_delay(a)) > 0) {
485                imcb_log(ic, "Reconnecting in %d seconds..", delay);
486                a->reconnect = b_timeout_add(delay * 1000, auto_reconnect, a);
487        }
488
489        imc_free(ic);
490}
491
492void imcb_ask(struct im_connection *ic, char *msg, void *data,
493              query_callback doit, query_callback dont)
494{
495        query_add((irc_t *) ic->bee->ui_data, ic, msg, doit, dont, g_free, data);
496}
497
498void imcb_ask_with_free(struct im_connection *ic, char *msg, void *data,
499                        query_callback doit, query_callback dont, query_callback myfree)
500{
501        query_add((irc_t *) ic->bee->ui_data, ic, msg, doit, dont, myfree, data);
502}
503
504void imcb_add_buddy(struct im_connection *ic, const char *handle, const char *group)
505{
506        bee_user_t *bu;
507        bee_t *bee = ic->bee;
508        bee_group_t *oldg;
509
510        if (!(bu = bee_user_by_handle(bee, ic, handle))) {
511                bu = bee_user_new(bee, ic, handle, 0);
512        }
513
514        oldg = bu->group;
515        bu->group = bee_group_by_name(bee, group, TRUE);
516
517        if (bee->ui->user_group && bu->group != oldg) {
518                bee->ui->user_group(bee, bu);
519        }
520}
521
522void imcb_rename_buddy(struct im_connection *ic, const char *handle, const char *fullname)
523{
524        bee_t *bee = ic->bee;
525        bee_user_t *bu = bee_user_by_handle(bee, ic, handle);
526
527        if (!bu || !fullname) {
528                return;
529        }
530
531        if (!bu->fullname || strcmp(bu->fullname, fullname) != 0) {
532                g_free(bu->fullname);
533                bu->fullname = g_strdup(fullname);
534
535                if (bee->ui->user_fullname) {
536                        bee->ui->user_fullname(bee, bu);
537                }
538        }
539}
540
541void imcb_remove_buddy(struct im_connection *ic, const char *handle, char *group)
542{
543        bee_user_free(ic->bee, bee_user_by_handle(ic->bee, ic, handle));
544}
545
546/* Implements either imcb_buddy_nick_hint() or imcb_buddy_nick_change() depending on the value of 'change' */
547static void buddy_nick_hint_or_change(struct im_connection *ic, const char *handle, const char *nick, gboolean change)
548{
549        bee_t *bee = ic->bee;
550        bee_user_t *bu = bee_user_by_handle(bee, ic, handle);
551
552        if (!bu || !nick) {
553                return;
554        }
555
556        g_free(bu->nick);
557        bu->nick = g_strdup(nick);
558
559        if (change && bee->ui->user_nick_change) {
560                bee->ui->user_nick_change(bee, bu, nick);
561        } else if (!change && bee->ui->user_nick_hint) {
562                bee->ui->user_nick_hint(bee, bu, nick);
563        }
564}
565
566/* Soft variant, for newly created users. Does nothing if it's already online */
567void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick)
568{
569        buddy_nick_hint_or_change(ic, handle, nick, FALSE);
570}
571
572/* Hard variant, always changes the nick */
573void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick)
574{
575        buddy_nick_hint_or_change(ic, handle, nick, TRUE);
576}
577
578struct imcb_ask_cb_data {
579        struct im_connection *ic;
580        char *handle;
581};
582
583static void imcb_ask_cb_free(void *data)
584{
585        struct imcb_ask_cb_data *cbd = data;
586
587        g_free(cbd->handle);
588        g_free(cbd);
589}
590
591static void imcb_ask_auth_cb_no(void *data)
592{
593        struct imcb_ask_cb_data *cbd = data;
594
595        cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
596
597        imcb_ask_cb_free(cbd);
598}
599
600static void imcb_ask_auth_cb_yes(void *data)
601{
602        struct imcb_ask_cb_data *cbd = data;
603
604        cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle);
605
606        imcb_ask_cb_free(cbd);
607}
608
609void imcb_ask_auth(struct im_connection *ic, const char *handle, const char *realname)
610{
611        struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);
612        char *s, *realname_ = NULL;
613
614        if (realname != NULL) {
615                realname_ = g_strdup_printf(" (%s)", realname);
616        }
617
618        s = g_strdup_printf("The user %s%s wants to add you to his/her buddy list.",
619                            handle, realname_ ? realname_ : "");
620
621        g_free(realname_);
622
623        data->ic = ic;
624        data->handle = g_strdup(handle);
625        query_add((irc_t *) ic->bee->ui_data, ic, s,
626                  imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data);
627
628        g_free(s);
629}
630
631static void imcb_ask_add_cb_yes(void *data)
632{
633        struct imcb_ask_cb_data *cbd = data;
634
635        cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
636
637        imcb_ask_cb_free(data);
638}
639
640void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname)
641{
642        struct imcb_ask_cb_data *data;
643        char *s;
644
645        /* TODO: Make a setting for this! */
646        if (bee_user_by_handle(ic->bee, ic, handle) != NULL) {
647                return;
648        }
649
650        data = g_new0(struct imcb_ask_cb_data, 1);
651
652        s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle);
653
654        data->ic = ic;
655        data->handle = g_strdup(handle);
656        query_add((irc_t *) ic->bee->ui_data, ic, s,
657                  imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data);
658
659        g_free(s);
660}
661
662struct bee_user *imcb_buddy_by_handle(struct im_connection *ic, const char *handle)
663{
664        return bee_user_by_handle(ic->bee, ic, handle);
665}
666
667/* The plan is to not allow straight calls to prpl functions anymore, but do
668   them all from some wrappers. We'll start to define some down here: */
669
670int imc_chat_msg(struct groupchat *c, char *msg, int flags)
671{
672        char *buf = NULL;
673
674        if ((c->ic->flags & OPT_DOES_HTML) && (g_strncasecmp(msg, "<html>", 6) != 0)) {
675                buf = escape_html(msg);
676                msg = buf;
677        }
678
679        c->ic->acc->prpl->chat_msg(c, msg, flags);
680        g_free(buf);
681
682        return 1;
683}
684
685static char *imc_away_state_find(GList *gcm, char *away, char **message);
686
687int imc_away_send_update(struct im_connection *ic)
688{
689        char *away, *msg = NULL;
690
691        if (ic->acc->prpl->away_states == NULL ||
692            ic->acc->prpl->set_away == NULL) {
693                return 0;
694        }
695
696        away = set_getstr(&ic->acc->set, "away") ?
697               : set_getstr(&ic->bee->set, "away");
698        if (away && *away) {
699                GList *m = ic->acc->prpl->away_states(ic);
700                msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL;
701                away = imc_away_state_find(m, away, &msg) ? :
702                       (imc_away_state_find(m, "away", &msg) ? : m->data);
703        } else if (ic->acc->flags & ACC_FLAG_STATUS_MESSAGE) {
704                away = NULL;
705                msg = set_getstr(&ic->acc->set, "status") ?
706                      : set_getstr(&ic->bee->set, "status");
707        }
708
709        ic->acc->prpl->set_away(ic, away, msg);
710
711        return 1;
712}
713
714static char *imc_away_alias_list[8][5] =
715{
716        { "Away from computer", "Away", "Extended away", NULL },
717        { "NA", "N/A", "Not available", NULL },
718        { "Busy", "Do not disturb", "DND", "Occupied", NULL },
719        { "Be right back", "BRB", NULL },
720        { "On the phone", "Phone", "On phone", NULL },
721        { "Out to lunch", "Lunch", "Food", NULL },
722        { "Invisible", "Hidden" },
723        { NULL }
724};
725
726static char *imc_away_state_find(GList *gcm, char *away, char **message)
727{
728        GList *m;
729        int i, j;
730
731        for (m = gcm; m; m = m->next) {
732                if (g_strncasecmp(m->data, away, strlen(m->data)) == 0) {
733                        /* At least the Yahoo! module works better if message
734                           contains no data unless it adds something to what
735                           we have in state already. */
736                        if (strlen(m->data) == strlen(away)) {
737                                *message = NULL;
738                        }
739
740                        return m->data;
741                }
742        }
743
744        for (i = 0; *imc_away_alias_list[i]; i++) {
745                int keep_message;
746
747                for (j = 0; imc_away_alias_list[i][j]; j++) {
748                        if (g_strncasecmp(away, imc_away_alias_list[i][j], strlen(imc_away_alias_list[i][j])) == 0) {
749                                keep_message = strlen(away) != strlen(imc_away_alias_list[i][j]);
750                                break;
751                        }
752                }
753
754                if (!imc_away_alias_list[i][j]) {       /* If we reach the end, this row */
755                        continue;                       /* is not what we want. Next!    */
756
757                }
758                /* Now find an entry in this row which exists in gcm */
759                for (j = 0; imc_away_alias_list[i][j]; j++) {
760                        for (m = gcm; m; m = m->next) {
761                                if (g_strcasecmp(imc_away_alias_list[i][j], m->data) == 0) {
762                                        if (!keep_message) {
763                                                *message = NULL;
764                                        }
765
766                                        return imc_away_alias_list[i][j];
767                                }
768                        }
769                }
770
771                /* No need to look further, apparently this state doesn't
772                   have any good alias for this protocol. */
773                break;
774        }
775
776        return NULL;
777}
778
779void imc_add_allow(struct im_connection *ic, char *handle)
780{
781        if (g_slist_find_custom(ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp) == NULL) {
782                ic->permit = g_slist_prepend(ic->permit, g_strdup(handle));
783        }
784
785        ic->acc->prpl->add_permit(ic, handle);
786}
787
788void imc_rem_allow(struct im_connection *ic, char *handle)
789{
790        GSList *l;
791
792        if ((l = g_slist_find_custom(ic->permit, handle, (GCompareFunc) ic->acc->prpl->handle_cmp))) {
793                g_free(l->data);
794                ic->permit = g_slist_delete_link(ic->permit, l);
795        }
796
797        ic->acc->prpl->rem_permit(ic, handle);
798}
799
800void imc_add_block(struct im_connection *ic, char *handle)
801{
802        if (g_slist_find_custom(ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp) == NULL) {
803                ic->deny = g_slist_prepend(ic->deny, g_strdup(handle));
804        }
805
806        ic->acc->prpl->add_deny(ic, handle);
807}
808
809void imc_rem_block(struct im_connection *ic, char *handle)
810{
811        GSList *l;
812
813        if ((l = g_slist_find_custom(ic->deny, handle, (GCompareFunc) ic->acc->prpl->handle_cmp))) {
814                g_free(l->data);
815                ic->deny = g_slist_delete_link(ic->deny, l);
816        }
817
818        ic->acc->prpl->rem_deny(ic, handle);
819}
820
821/* Deprecated: using this function resulted in merging several handles accidentally
822 * Also the irc layer handles this decently nowadays */
823void imcb_clean_handle(struct im_connection *ic, char *handle)
824{
825}
Note: See TracBrowser for help on using the repository browser.