source: protocols/nogaim.c @ c6bc434

Last change on this file since c6bc434 was 977a9d5, checked in by dequis <dx@…>, at 2015-12-09T07:58:59Z

Revert "imc_away_send_update: Fix leak of away_states linked list"

This reverts commit ed431c389887080dc4fa45e30d051ce733f4ce57.

I'm going to let this leak. Turns out only purple allocates an empty
list for every time this is called. Other protocols have statics, and
they always return the same thing, can't free those. Whatever. The
purple leak was insignificant, just more scratching of itches.

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