Changes in / [9f03c47:537d9b9]


Ignore:
Files:
7 added
4 deleted
18 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r9f03c47 r537d9b9  
    3232bitlbee.service
    3333bitlbee@.service
     34*.pyc
  • configure

    r9f03c47 r537d9b9  
    1616config='/var/lib/bitlbee/'
    1717plugindir='$prefix/lib/bitlbee/'
     18rpcplugindir='$plugindir/rpc/'
    1819includedir='$prefix/include/bitlbee/'
    1920systemdsystemunitdir=''
     
    3940twitter=1
    4041purple=0
     42rpc=1
    4143
    4244doc=1
     
    123125--datadir=...                                           $datadir
    124126--plugindir=...                                         $plugindir
     127--rpcplugindir=...                                      $rpcplugindir
    125128--systemdsystemunitdir=...                              $systemdsystemunitdir
    126129--pidfile=...                                           $pidfile
     
    135138--purple=0/1    Disable/enable libpurple support        $purple
    136139                (automatically disables other protocol modules)
     140--rpc=0/1       Disable/enable RPC plugin interface     $rpc
    137141
    138142--pam=0/1       Disable/enable PAM authentication       $pam
     
    173177config=$(eval echo "$config/" | sed 's/\/\{1,\}/\//g')
    174178plugindir=$(eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g')
     179rpcplugindir=$(eval echo "$rpcplugindir/" | sed 's/\/\{1,\}/\//g')
    175180includedir=$(eval echo "$includedir"/ | sed 's/\/\{1,\}/\//g')
    176181libevent=$(eval echo "$libevent"/ | sed 's/\/\{1,\}/\//g')
     
    194199DATADIR=$datadir
    195200PLUGINDIR=$plugindir
     201RPCPLUGINDIR=$rpcplugindir
    196202CONFIG=$config
    197203INCLUDEDIR=$includedir
     
    243249#define VARDIR "$datadir"
    244250#define PLUGINDIR "$plugindir"
     251#define RPCPLUGINDIR "$rpcplugindir"
    245252#define PIDFILE "$pidfile"
    246253#define IPCSOCKET "$ipcsocket"
     
    283290        LDFLAGS="$LDFLAGS -fsanitize=address"
    284291        debug=1
     292fi
     293
     294if [ "$tsan" = "1" ]; then
     295        echo
     296        echo "Threaded BitlBee? Have a nice tall glass of http://imgur.com/gallery/tX4qxzS"
     297        echo "No need to sanitise threads in a single-threaded process!"
    285298fi
    286299
     
    706719fi
    707720
     721if [ "$rpc" = 0 ]; then
     722        # Somewhat pointless at this stage already but at least this keeps it
     723        # out of bitlbee.pc which is probably a good thing.
     724        rpcplugindir=""
     725fi
     726
    708727otrprefix=""
    709728if [ "$otr" = "auto" ]; then
     
    784803includedir=$includedir
    785804plugindir=$plugindir
     805rpcplugindir=$rpcplugindir
    786806
    787807Name: bitlbee
     
    876896        protocols=$protocols'twitter '
    877897        protoobjs=$protoobjs'twitter_mod.o '
     898fi
     899
     900if [ "$rpc" = 0 ]; then
     901        echo '#undef WITH_RPC' >> config.h
     902else
     903        echo '#define WITH_RPC' >> config.h
     904        protocols=$protocols'rpc '
     905        protoobjs=$protoobjs'rpc_mod.o '
    878906fi
    879907
     
    965993echo '  Using event handler: '$events
    966994echo '  Using SSL library: '$ssl
    967 #echo '  Building with these storage backends: '$STORAGES
    968995
    969996if [ -n "$protocols" ]; then
  • irc_channel.c

    r9f03c47 r537d9b9  
    757757        }
    758758
     759        if (!bu->ic->acc->prpl->add_buddy) {
     760                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
     761                return FALSE;
     762        }
     763
    759764        bu->ic->acc->prpl->add_buddy(bu->ic, bu->handle,
    760765                                     icc->group ? icc->group->name : NULL);
     
    774779        if (icc->type != IRC_CC_TYPE_GROUP) {
    775780                irc_send_num(ic->irc, 482, "%s :Kicks are only possible to fill_by=group channels", ic->name);
     781                return;
     782        }
     783
     784        if (!bu->ic->acc->prpl->remove_buddy) {
     785                irc_send_num(ic->irc, 482, "%s :IM protocol does not support contact list modification", ic->name);
    776786                return;
    777787        }
  • irc_commands.c

    r9f03c47 r537d9b9  
    287287                           showed an error message, or is doing some work
    288288                           before the join should be confirmed. (In the
    289                            latter case, the caller should take care of that
     289                           latter case, the callee should take care of that
    290290                           confirmation.) TRUE means all's good, let the
    291291                           user join the channel right away. */
  • lib/Makefile

    r9f03c47 r537d9b9  
    1313
    1414# [SH] Program variables
    15 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ns_parse.o
     15objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o oauth2.o parson.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ns_parse.o
    1616
    1717LFLAGS += -r
  • lib/misc.c

    r9f03c47 r537d9b9  
    431431}
    432432
    433 int is_bool(char *value)
     433int is_bool(const char *value)
    434434{
    435435        if (*value == 0) {
     
    457457}
    458458
    459 int bool2int(char *value)
     459int bool2int(const char *value)
    460460{
    461461        int i;
  • lib/misc.h

    r9f03c47 r537d9b9  
    137137G_MODULE_EXPORT void random_bytes(unsigned char *buf, int count);
    138138
    139 G_MODULE_EXPORT int is_bool(char *value);
    140 G_MODULE_EXPORT int bool2int(char *value);
     139G_MODULE_EXPORT int is_bool(const char *value);
     140G_MODULE_EXPORT int bool2int(const char *value);
    141141
    142142G_MODULE_EXPORT struct ns_srv_reply **srv_lookup(char *service, char *protocol, char *domain);
  • lib/oauth2.c

    r9f03c47 r537d9b9  
    4242#include "oauth2.h"
    4343#include "oauth.h"
    44 #include "json.h"
    45 #include "json_util.h"
     44#include "parson.h"
    4645#include "url.h"
     46
     47#define JSON_O_FOREACH(o, k, v) \
     48    const char *k; const JSON_Value *v; int __i; \
     49    for (__i = 0; json_object_get_tuple(o, __i, &k, &v); __i++)
    4750
    4851char *oauth2_url(const struct oauth2_service *sp)
     
    113116}
    114117
    115 static char* oauth2_parse_error(json_value *e)
     118static char* oauth2_parse_error(const JSON_Value *e)
    116119{
    117120        /* This does a reasonable job with some of the flavours of error
    118121           responses I've seen. Because apparently it's not standardised. */
    119122
    120         if (e->type == json_object) {
     123        if (json_type(e) == JSONObject) {
    121124                /* Facebook style */
    122                 const char *msg = json_o_str(e, "message");
    123                 const char *type = json_o_str(e, "type");
    124                 json_value *code_o = json_o_get(e, "code");
    125                 int code = 0;
    126 
    127                 if (code_o && code_o->type == json_integer) {
    128                         code = code_o->u.integer;
    129                 }
    130 
     125                const char *msg = json_object_get_string(json_object(e), "message");
     126                const char *type = json_object_get_string(json_object(e), "type");
     127                JSON_Value *code_o = json_object_get_value(json_object(e), "code");
     128                int code = json_value_get_integer(code_o);
    131129                return g_strdup_printf("Error %d: %s", code, msg ? msg : type ? type : "Unknown error");
    132         } else if (e->type == json_string) {
    133                 return g_strdup(e->u.string.ptr);
     130        } else if (json_type(e) == JSONString) {
     131                return g_strdup(json_string(e));
    134132        }
    135133        return NULL;
     
    156154        if (content_type && (strstr(content_type, "application/json") ||
    157155                             strstr(content_type, "text/javascript"))) {
    158                 json_value *js = json_parse(req->reply_body, req->body_size);
    159                 if (js && js->type == json_object) {
    160                         JSON_O_FOREACH(js, k, v){
     156                JSON_Value *js = json_parse_string(req->reply_body);
     157                if (js && json_type(js) == JSONObject) {
     158                        JSON_O_FOREACH(json_object(js), k, v){
    161159                                if (strcmp(k, "error") == 0) {
    162160                                        error = oauth2_parse_error(v);
    163161                                }
    164                                 if (v->type != json_string) {
     162                                if (json_type(v) != JSONString) {
    165163                                        continue;
    166164                                }
    167165                                if (strcmp(k, "access_token") == 0) {
    168                                         atoken = g_strdup(v->u.string.ptr);
     166                                        atoken = g_strdup(json_string(v));
    169167                                }
    170168                                if (strcmp(k, "refresh_token") == 0) {
    171                                         rtoken = g_strdup(v->u.string.ptr);
     169                                        rtoken = g_strdup(json_string(v));
    172170                                }
    173171                        }
  • protocols/account.c

    r9f03c47 r537d9b9  
    2727#include "bitlbee.h"
    2828#include "account.h"
    29 
    30 static const char* account_protocols_local[] = {
    31         "gg", "whatsapp", NULL
    32 };
    3329
    3430static char *set_eval_nick_source(set_t *set, char *value);
     
    461457        return a->auto_reconnect_delay;
    462458}
    463 
    464 int protocol_account_islocal(const char* protocol)
    465 {
    466         const char** p = account_protocols_local;
    467 
    468         do {
    469                 if (strcmp(*p, protocol) == 0) {
    470                         return 1;
    471                 }
    472         } while (*(++p));
    473         return 0;
    474 }
  • protocols/account.h

    r9f03c47 r537d9b9  
    5858int account_reconnect_delay(account_t *a);
    5959
    60 int protocol_account_islocal(const char* protocol);
    61 
    6260typedef enum {
    6361        ACC_SET_OFFLINE_ONLY = 0x02,    /* Allow changes only if the acct is offline. */
     
    7068        ACC_FLAG_STATUS_MESSAGE = 0x02, /* Supports status messages (without being away). */
    7169        ACC_FLAG_HANDLE_DOMAINS = 0x04, /* Contact handles need a domain portion. */
    72         ACC_FLAG_LOCAL = 0x08,          /* Contact list is local. */
     70        ACC_FLAG_LOCAL_CONTACTS = 0x08, /* Contact list is local. */
    7371        ACC_FLAG_LOCKED = 0x10,         /* Account is locked (cannot be deleted, certain settings can't changed) */
    7472} account_flag_t;
  • protocols/nogaim.c

    r9f03c47 r537d9b9  
    204204        extern void twitter_initmodule();
    205205        extern void purple_initmodule();
     206        extern void rpc_initmodule();
    206207
    207208#ifdef WITH_MSN
     
    227228#ifdef WITH_PURPLE
    228229        purple_initmodule();
     230#endif
     231
     232#ifdef WITH_RPC
     233        rpc_initmodule();
    229234#endif
    230235
     
    392397        }
    393398
    394         if (ic->acc->flags & ACC_FLAG_LOCAL) {
     399        if ((ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS) &&
     400            !(ic->flags & OPT_LOCAL_CONTACTS_SENT) &&
     401            ic->acc->prpl->add_buddy) {
    395402                GHashTableIter nicks;
    396                 gpointer k, v;
     403                gpointer handle;
    397404                g_hash_table_iter_init(&nicks, ic->acc->nicks);
    398                 while (g_hash_table_iter_next(&nicks, &k, &v)) {
    399                         ic->acc->prpl->add_buddy(ic, (char *) k, NULL);
     405                while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     406                        ic->acc->prpl->add_buddy(ic, (char *) handle, NULL);
    400407                }
    401408        }
     
    492499        query_del_by_conn((irc_t *) ic->bee->ui_data, ic);
    493500
     501        /* Throw away groupchats owned by this account. Historically this was only
     502           ever done by IM modules which is a bug. But it gives them opportunity
     503           to clean up protocol-specific bits as well so keep it that way, just
     504           do another cleanup here as a fallback. Don't want to leave any dangling
     505           pointers! */
     506        while (ic->groupchats) {
     507                imcb_chat_free(ic->groupchats->data);
     508        }
     509
    494510        if (!a) {
    495511                /* Uhm... This is very sick. */
     
    590606}
    591607
     608/* Returns the local contacts for an IM account (based on assigned nicks).
     609   Linked list should be freed, the strings themselves not! So look at it
     610   like a GSList<const char*> I guess? Empty list means NULL retval (as
     611   always with GSList). */
     612GSList *imcb_get_local_contacts(struct im_connection *ic)
     613{
     614        GHashTableIter nicks;
     615        GSList *ret = NULL;
     616       
     617        if (!(ic->acc->flags & ACC_FLAG_LOCAL_CONTACTS)) {
     618                /* Only allow protocols that indicate local contact list
     619                   support to use this function. */
     620                return ret;
     621        }
     622       
     623        g_hash_table_iter_init(&nicks, ic->acc->nicks);
     624        gpointer handle;
     625        while (g_hash_table_iter_next(&nicks, &handle, NULL)) {
     626                ret = g_slist_prepend(ret, (char *) handle);
     627        }
     628       
     629        /* If the protocol asked for the list, assume we won't have to send it
     630           anymore in imcb_connected(). */
     631        ic->flags |= OPT_LOCAL_CONTACTS_SENT;
     632       
     633        return ret;
     634}
     635
     636
    592637struct imcb_ask_cb_data {
    593638        struct im_connection *ic;
     
    647692        struct imcb_ask_cb_data *cbd = data;
    648693
    649         cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     694        if (cbd->ic->acc->prpl->add_buddy) {
     695                cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
     696        }
    650697
    651698        imcb_ask_cb_free(data);
  • protocols/nogaim.h

    r9f03c47 r537d9b9  
    5757
    5858/* Sharing flags between all kinds of things. I just hope I won't hit any
    59    limits before 32-bit machines become extinct. ;-) */
     59   limits before 32-bit machines become extinct. ;-)
     60   
     61   Argh! This needs to be renamed to be more clear which field they're used
     62   for. As said it's currently mixed which is nonsense. Some are for the
     63   im_connection flags field, some for imcb_buddy_status(), some for typing
     64   notifications, and who knows what else... */
    6065#define OPT_LOGGED_IN   0x00000001
    6166#define OPT_LOGGING_OUT 0x00000002
     
    7075#define OPT_PONGS       0x00010000 /* Service sends us keep-alives */
    7176#define OPT_PONGED      0x00020000 /* Received a keep-alive during last interval */
     77#define OPT_LOCAL_CONTACTS_SENT 0x00040000 /* Protocol already requested local contact list, so don't send it after finishing login. */
    7278#define OPT_SELFMESSAGE 0x00080000 /* A message sent by self from another location */
    7379
     
    371377G_MODULE_EXPORT void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick);
    372378G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data);
     379G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic);
    373380
    374381G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags);
  • protocols/purple/purple.c

    r9f03c47 r537d9b9  
    298298        }
    299299        purple_accounts_remove(pa);
     300       
     301        /* Last, some protocols want their contact lists locally. */
     302        if (strcmp(acc->prpl->name, "whatsapp") == 0 || strcmp(acc->prpl->name, "gg") == 0) {
     303                acc->flags |= ACC_FLAG_LOCAL_CONTACTS;
     304        }
    300305}
    301306
  • protocols/twitter/twitter_lib.c

    r9f03c47 r537d9b9  
    3636#include "base64.h"
    3737#include "twitter_lib.h"
    38 #include "json_util.h"
     38#include "parson.h"
    3939#include <ctype.h>
    4040#include <errno.h>
     
    6464        gboolean from_filter;
    6565};
     66
     67#define JSON_O_FOREACH(o, k, v) \
     68    const char *k; const JSON_Value *v; int __i; \
     69    for (__i = 0; json_object_get_tuple(o, __i, &k, &v); __i++)
    6670
    6771/**
     
    166170{
    167171        static char *ret = NULL;
    168         json_value *root, *err;
     172        JSON_Value *root, *err;
    169173
    170174        g_free(ret);
     
    172176
    173177        if (req->body_size > 0) {
    174                 root = json_parse(req->reply_body, req->body_size);
    175                 err = json_o_get(root, "errors");
    176                 if (err && err->type == json_array && (err = err->u.array.values[0]) &&
    177                     err->type == json_object) {
    178                         const char *msg = json_o_str(err, "message");
     178                root = json_parse_string(req->reply_body);
     179                err = json_object_get_value(json_object(root), "errors");
     180                if (err && json_type(err) == JSONArray &&
     181                    (err = json_array_get_value(json_array(err), 0)) &&
     182                    json_type(err) == JSONObject) {
     183                        const char *msg = json_object_get_string(json_object(err), "message");
    179184                        if (msg) {
    180185                                ret = g_strdup_printf("%s (%s)", req->status_string, msg);
     
    189194/* WATCH OUT: This function might or might not destroy your connection.
    190195   Sub-optimal indeed, but just be careful when this returns NULL! */
    191 static json_value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
     196static JSON_Value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
    192197{
    193198        gboolean logging_in = !(ic->flags & OPT_LOGGED_IN);
    194199        gboolean periodic;
    195200        struct twitter_data *td = ic->proto_data;
    196         json_value *ret;
     201        JSON_Value *ret;
    197202        char path[64] = "", *s;
    198203
     
    232237        }
    233238
    234         if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) {
     239        if ((ret = json_parse_string(req->reply_body)) == NULL) {
    235240                imcb_error(ic, "Could not retrieve %s: %s",
    236241                           path, "XML parse error");
     
    289294 * Fill a list of ids.
    290295 */
    291 static gboolean twitter_xt_get_friends_id_list(json_value *node, struct twitter_xml_list *txl)
    292 {
    293         json_value *c;
     296static gboolean twitter_xt_get_friends_id_list(JSON_Value *node, struct twitter_xml_list *txl)
     297{
     298        JSON_Array *c;
    294299        int i;
    295300
     
    297302        txl->type = TXL_ID;
    298303
    299         c = json_o_get(node, "ids");
    300         if (!c || c->type != json_array) {
     304        if (!(c = json_object_get_array(json_object(node), "ids"))) {
    301305                return FALSE;
    302306        }
    303307
    304         for (i = 0; i < c->u.array.length; i++) {
    305                 if (c->u.array.values[i]->type != json_integer) {
    306                         continue;
    307                 }
     308        for (i = 0; i < json_array_get_count(c); i++) {
     309                jint id = json_array_get_integer(c, i);
    308310
    309311                txl->list = g_slist_prepend(txl->list,
    310                                             g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer));
    311         }
    312 
    313         c = json_o_get(node, "next_cursor");
    314         if (c && c->type == json_integer) {
    315                 txl->next_cursor = c->u.integer;
     312                                            g_strdup_printf("%lld", id));
     313        }
     314
     315        JSON_Value *next = json_object_get_value(json_object(node), "next_cursor");
     316        if (next && json_type(next) == JSONInteger) {
     317                txl->next_cursor = json_integer(next);
    316318        } else {
    317319                txl->next_cursor = -1;
     
    329331{
    330332        struct im_connection *ic;
    331         json_value *parsed;
     333        JSON_Value *parsed;
    332334        struct twitter_xml_list *txl;
    333335        struct twitter_data *td;
     
    373375{
    374376        struct im_connection *ic = req->data;
    375         json_value *parsed;
     377        JSON_Value *parsed;
    376378        struct twitter_xml_list *txl;
    377379        struct twitter_data *td;
     
    418420{
    419421        struct im_connection *ic = req->data;
    420         json_value *parsed;
     422        JSON_Value *parsed;
    421423        struct twitter_xml_list *txl;
    422424        struct twitter_data *td;
     
    444446        // Process the retweet ids
    445447        txl->type = TXL_ID;
    446         if (parsed->type == json_array) {
     448        if (json_type(parsed) == JSONArray) {
     449                JSON_Array *arr = json_array(parsed);
    447450                unsigned int i;
    448                 for (i = 0; i < parsed->u.array.length; i++) {
    449                         json_value *c = parsed->u.array.values[i];
    450                         if (c->type != json_integer) {
    451                                 continue;
    452                         }
     451                for (i = 0; i < json_array_get_count(arr); i++) {
     452                        jint id = json_array_get_integer(arr, i);
    453453                        txl->list = g_slist_prepend(txl->list,
    454                                                     g_strdup_printf("%"PRIu64, c->u.integer));
     454                                                    g_strdup_printf("%lld", id));
    455455                }
    456456        }
     
    463463}
    464464
    465 static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl);
     465static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl);
    466466static void twitter_http_get_users_lookup(struct http_request *req);
    467467
     
    504504{
    505505        struct im_connection *ic = req->data;
    506         json_value *parsed;
     506        JSON_Value *parsed;
    507507        struct twitter_xml_list *txl;
    508508        GSList *l = NULL;
     
    537537}
    538538
    539 struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
     539struct twitter_xml_user *twitter_xt_get_user(const JSON_Object *node)
    540540{
    541541        struct twitter_xml_user *txu;
    542         json_value *jv;
     542       
     543        if (!node)
     544                return NULL;
    543545
    544546        txu = g_new0(struct twitter_xml_user, 1);
    545         txu->name = g_strdup(json_o_str(node, "name"));
    546         txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
    547 
    548         jv = json_o_get(node, "id");
    549         txu->uid = jv->u.integer;
     547        txu->name = g_strdup(json_object_get_string(node, "name"));
     548        txu->screen_name = g_strdup(json_object_get_string(node, "screen_name"));
     549        txu->uid = json_object_get_integer(node, "id");
    550550
    551551        return txu;
     
    557557 *  - all <user>s from the <users> element.
    558558 */
    559 static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl)
     559static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl)
    560560{
    561561        struct twitter_xml_user *txu;
     
    565565        txl->type = TXL_USER;
    566566
    567         if (!node || node->type != json_array) {
     567        if (json_type(node) != JSONArray) {
    568568                return FALSE;
    569569        }
    570 
     570       
    571571        // The root <users> node should hold the list of users <user>
    572572        // Walk over the nodes children.
    573         for (i = 0; i < node->u.array.length; i++) {
    574                 txu = twitter_xt_get_user(node->u.array.values[i]);
     573        JSON_Array *arr = json_array(node);
     574        for (i = 0; i < json_array_get_count(arr); i++) {
     575                JSON_Object *o = json_array_get_object(arr, i);
     576                if (!o)
     577                        continue;
     578                txu = twitter_xt_get_user(o);
    575579                if (txu) {
    576580                        txl->list = g_slist_prepend(txl->list, txu);
     
    587591#endif
    588592
    589 static void expand_entities(char **text, const json_value *node, const json_value *extended_node);
     593static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node);
    590594
    591595/**
     
    597601 *  - the user in a twitter_xml_user struct.
    598602 */
    599 static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
     603static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node)
    600604{
    601605        struct twitter_xml_status *txs = {0};
    602         const json_value *rt = NULL;
    603         const json_value *text_value = NULL;
    604         const json_value *extended_node = NULL;
    605 
    606         if (node->type != json_object) {
     606        const JSON_Object *rt = NULL;
     607        const JSON_Value *text_value = NULL;
     608        const JSON_Object *extended_node = NULL;
     609
     610        if (!node) {
    607611                return FALSE;
    608612        }
     
    610614
    611615        JSON_O_FOREACH(node, k, v) {
    612                 if (strcmp("text", k) == 0 && v->type == json_string && text_value == NULL) {
     616                if (strcmp("text", k) == 0 && json_type(v) == JSONString && text_value == NULL) {
    613617                        text_value = v;
    614                 } else if (strcmp("full_text", k) == 0 && v->type == json_string) {
     618                } else if (strcmp("full_text", k) == 0 && json_type(v) == JSONString) {
    615619                        text_value = v;
    616                 } else if (strcmp("extended_tweet", k) == 0 && v->type == json_object) {
    617                         text_value = json_o_get(v, "full_text");
    618                         extended_node = v;
    619                 } else if (strcmp("retweeted_status", k) == 0 && v->type == json_object) {
    620                         rt = v;
    621                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     620                } else if (strcmp("extended_tweet", k) == 0 && json_type(v) == JSONObject) {
     621                        text_value = json_object_get_value(json_object(v), "full_text");
     622                        extended_node = json_object(v);
     623                } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) {
     624                        // Handling below.
     625                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    622626                        struct tm parsed;
    623627
     
    625629                           this field. :-( Also assumes the timezone used
    626630                           is UTC since C time handling functions suck. */
    627                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     631                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    628632                                txs->created_at = mktime_utc(&parsed);
    629633                        }
    630                 } else if (strcmp("user", k) == 0 && v->type == json_object) {
    631                         txs->user = twitter_xt_get_user(v);
    632                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    633                         txs->rt_id = txs->id = v->u.integer;
    634                 } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    635                         txs->reply_to = v->u.integer;
     634                } else if (strcmp("user", k) == 0 && json_type(v) == JSONObject) {
     635                        txs->user = twitter_xt_get_user(json_object(v));
     636                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     637                        txs->rt_id = txs->id = json_integer(v);
     638                } else if (strcmp("in_reply_to_status_id", k) == 0 && json_type(v) == JSONInteger) {
     639                        txs->reply_to = json_integer(v);
    636640                }
    637641        }
     
    646650                        txs_free(rtxs);
    647651                }
    648         } else if (text_value && text_value->type == json_string) {
    649                 txs->text = g_memdup(text_value->u.string.ptr, text_value->u.string.length + 1);
     652        } else if (text_value && json_type(text_value) == JSONString) {
     653                txs->text = g_strdup(json_string(text_value));
    650654                strip_html(txs->text);
    651655                expand_entities(&txs->text, node, extended_node);
     
    663667 * Function to fill a twitter_xml_status struct (DM variant).
    664668 */
    665 static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
     669static struct twitter_xml_status *twitter_xt_get_dm(const JSON_Object *node)
    666670{
    667671        struct twitter_xml_status *txs;
    668672
    669         if (node->type != json_object) {
     673        if (!node) {
    670674                return FALSE;
    671675        }
     
    673677
    674678        JSON_O_FOREACH(node, k, v) {
    675                 if (strcmp("text", k) == 0 && v->type == json_string) {
    676                         txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
     679                if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
    677680                        strip_html(txs->text);
    678                 } else if (strcmp("created_at", k) == 0 && v->type == json_string) {
     681                } else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
    679682                        struct tm parsed;
    680683
     
    682685                           this field. :-( Also assumes the timezone used
    683686                           is UTC since C time handling functions suck. */
    684                         if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
     687                        if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
    685688                                txs->created_at = mktime_utc(&parsed);
    686689                        }
    687                 } else if (strcmp("sender", k) == 0 && v->type == json_object) {
    688                         txs->user = twitter_xt_get_user(v);
    689                 } else if (strcmp("id", k) == 0 && v->type == json_integer) {
    690                         txs->id = v->u.integer;
     690                } else if (strcmp("sender", k) == 0 && json_type(v) == JSONObject) {
     691                        txs->user = twitter_xt_get_user(json_object(v));
     692                } else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
     693                        txs->id = json_integer(v);
    691694                }
    692695        }
     
    702705}
    703706
    704 static void expand_entities(char **text, const json_value *node, const json_value *extended_node)
    705 {
    706         json_value *entities, *extended_entities, *quoted;
     707static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node)
     708{
     709        JSON_Object *entities, *extended_entities, *quoted;
    707710        char *quote_url = NULL, *quote_text = NULL;
    708711
    709         if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
    710                 return;
    711         if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
     712        if (!(entities = json_object_get_object(node, "entities")))
     713                return;
     714        if ((quoted = json_object_get_object(node, "quoted_status"))) {
    712715                /* New "retweets with comments" feature. Note that this info
    713716                 * seems to be included in the streaming API only! Grab the
     
    723726
    724727        if (extended_node) {
    725                 extended_entities = json_o_get(extended_node, "entities");
    726                 if (extended_entities && extended_entities->type == json_object) {
     728                extended_entities = json_object_get_object(extended_node, "entities");
     729                if (extended_entities) {
    727730                        entities = extended_entities;
    728731                }
     
    732735                int i;
    733736
    734                 if (v->type != json_array) {
     737                if (json_type(v) != JSONArray) {
    735738                        continue;
    736739                }
     
    739742                }
    740743
    741                 for (i = 0; i < v->u.array.length; i++) {
     744                for (i = 0; i < json_array_get_count(json_array(v)); i++) {
    742745                        const char *format = "%s%s <%s>%s";
    743 
    744                         if (v->u.array.values[i]->type != json_object) {
     746                        JSON_Object *r = json_array_get_object(json_array(v), i);
     747
     748                        if (!r) {
    745749                                continue;
    746750                        }
    747751
    748                         const char *kort = json_o_str(v->u.array.values[i], "url");
    749                         const char *disp = json_o_str(v->u.array.values[i], "display_url");
    750                         const char *full = json_o_str(v->u.array.values[i], "expanded_url");
     752                        const char *kort = json_object_get_string(r, "url");
     753                        const char *disp = json_object_get_string(r, "display_url");
     754                        const char *full = json_object_get_string(r, "expanded_url");
    751755                        char *pos, *new;
    752756
     
    777781 *  - the next_cursor.
    778782 */
    779 static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_value *node,
     783static gboolean twitter_xt_get_status_list(struct im_connection *ic, const JSON_Value *node,
    780784                                           struct twitter_xml_list *txl)
    781785{
     
    786790        txl->type = TXL_STATUS;
    787791
    788         if (node->type != json_array) {
     792        if (json_type(node) != JSONArray) {
    789793                return FALSE;
    790794        }
     
    792796        // The root <statuses> node should hold the list of statuses <status>
    793797        // Walk over the nodes children.
    794         for (i = 0; i < node->u.array.length; i++) {
    795                 txs = twitter_xt_get_status(node->u.array.values[i]);
     798        for (i = 0; i < json_array_get_count(json_array(node)); i++) {
     799                txs = twitter_xt_get_status(json_array_get_object(json_array(node), i));
    796800                if (!txs) {
    797801                        continue;
     
    978982       
    979983        /* Check this is not a tweet that should be muted */
    980         uid_str = g_strdup_printf("%" PRIu64, status->user->uid);
     984        uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, status->user->uid);
    981985
    982986        if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) {
     
    10131017}
    10141018
    1015 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
     1019static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter);
    10161020
    10171021static void twitter_http_stream(struct http_request *req)
     
    10191023        struct im_connection *ic = req->data;
    10201024        struct twitter_data *td;
    1021         json_value *parsed;
     1025        JSON_Value *parsed;
    10221026        int len = 0;
    10231027        char c, *nl;
     
    10601064                req->reply_body[len] = '\0';
    10611065
    1062                 if ((parsed = json_parse(req->reply_body, req->body_size))) {
     1066                if ((parsed = json_parse_string(req->reply_body))) {
    10631067                        from_filter = (req == td->filter_stream);
    1064                         twitter_stream_handle_object(ic, parsed, from_filter);
     1068                        twitter_stream_handle_object(ic, json_object(parsed), from_filter);
    10651069                }
    10661070                json_value_free(parsed);
     
    10761080}
    10771081
    1078 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
     1082static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o);
    10791083static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
    10801084
    1081 static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
     1085static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter)
    10821086{
    10831087        struct twitter_data *td = ic->proto_data;
    10841088        struct twitter_xml_status *txs;
    1085         json_value *c;
     1089        JSON_Object *c;
    10861090
    10871091        if ((txs = twitter_xt_get_status(o))) {
     
    10901094                txs_free(txs);
    10911095                return ret;
    1092         } else if ((c = json_o_get(o, "direct_message")) &&
     1096        } else if ((c = json_object_get_object(o, "direct_message")) &&
    10931097                   (txs = twitter_xt_get_dm(c))) {
    10941098                if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
     
    10981102                txs_free(txs);
    10991103                return TRUE;
    1100         } else if ((c = json_o_get(o, "event")) && c->type == json_string) {
     1104        } else if (json_object_get_string(o, "event")) {
    11011105                twitter_stream_handle_event(ic, o);
    11021106                return TRUE;
    1103         } else if ((c = json_o_get(o, "disconnect")) && c->type == json_object) {
     1107        } else if ((c = json_object_get_object(o, "disconnect"))) {
    11041108                /* HACK: Because we're inside an event handler, we can't just
    11051109                   disconnect here. Instead, just change the HTTP status string
    11061110                   into a Twitter status string. */
    1107                 char *reason = json_o_strdup(c, "reason");
     1111                char *reason = g_strdup(json_object_get_string(c, "reason"));
    11081112                if (reason) {
    11091113                        g_free(td->stream->status_string);
     
    11441148}
    11451149
    1146 static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o)
     1150static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o)
    11471151{
    11481152        struct twitter_data *td = ic->proto_data;
    1149         json_value *source = json_o_get(o, "source");
    1150         json_value *target = json_o_get(o, "target");
    1151         const char *type = json_o_str(o, "event");
     1153        JSON_Object *source = json_object_get_object(o, "source");
     1154        JSON_Object *target = json_object_get_object(o, "target");
     1155        const char *type = json_object_get_string(o, "event");
    11521156        struct twitter_xml_user *us = NULL;
    11531157        struct twitter_xml_user *ut = NULL;
    11541158
    1155         if (!type || !source || source->type != json_object
    1156             || !target || target->type != json_object) {
     1159        if (!type || !source || !target) {
    11571160                return FALSE;
    11581161        }
     
    11681171                char *uid_str;
    11691172                ut = twitter_xt_get_user(target);
    1170                 uid_str = g_strdup_printf("%" PRIu64, ut->uid);
     1173                uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid);
    11711174                if (!(found = g_slist_find_custom(td->mutes_ids, uid_str,
    11721175                                                  (GCompareFunc)strcmp))) {
     
    11751178                twitter_log(ic, "Muted user %s", ut->screen_name);
    11761179                if (getenv("BITLBEE_DEBUG")) {
    1177                         fprintf(stderr, "New mute: %s %"PRIu64"\n",
     1180                        fprintf(stderr, "New mute: %s %"G_GUINT64_FORMAT"\n",
    11781181                                ut->screen_name, ut->uid);
    11791182                }
     
    11821185                char *uid_str;
    11831186                ut = twitter_xt_get_user(target);
    1184                 uid_str = g_strdup_printf("%" PRIu64, ut->uid);
     1187                uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid);
    11851188                if ((found = g_slist_find_custom(td->mutes_ids, uid_str,
    11861189                                                (GCompareFunc)strcmp))) {
     
    11921195                twitter_log(ic, "Unmuted user %s", ut->screen_name);
    11931196                if (getenv("BITLBEE_DEBUG")) {
    1194                         fprintf(stderr, "New unmute: %s %"PRIu64"\n",
     1197                        fprintf(stderr, "New unmute: %s %"G_GUINT64_FORMAT"\n",
    11951198                                ut->screen_name, ut->uid);
    11961199                }
     
    12831286        struct twitter_filter *tf;
    12841287        GList *users = NULL;
    1285         json_value *parsed;
    1286         json_value *id;
    1287         const char *name;
     1288        JSON_Value *parsed;
    12881289        GString *fstr;
    12891290        GSList *l;
     
    13101311        }
    13111312
    1312         if (parsed->type != json_array) {
     1313        if (json_type(parsed) != JSONArray) {
    13131314                goto finish;
    13141315        }
    13151316
    1316         for (i = 0; i < parsed->u.array.length; i++) {
    1317                 id = json_o_get(parsed->u.array.values[i], "id");
    1318                 name = json_o_str(parsed->u.array.values[i], "screen_name");
    1319 
    1320                 if (!name || !id || id->type != json_integer) {
     1317        for (i = 0; i < json_array_get_count(json_array(parsed)); i++) {
     1318                JSON_Object *o = json_array_get_object(json_array(parsed), i);
     1319                jint id = json_object_get_integer(o, "id");
     1320                const char *name = json_object_get_string(o, "screen_name");
     1321
     1322                if (!name || !id) {
    13211323                        continue;
    13221324                }
     
    13261328
    13271329                        if (g_strcasecmp(tf->text, name) == 0) {
    1328                                 tf->uid = id->u.integer;
     1330                                tf->uid = id;
    13291331                                users = g_list_delete_link(users, u);
    13301332                                break;
     
    15711573        struct im_connection *ic = req->data;
    15721574        struct twitter_data *td;
    1573         json_value *parsed;
     1575        JSON_Value *parsed;
    15741576        struct twitter_xml_list *txl;
    15751577
     
    16111613        struct im_connection *ic = req->data;
    16121614        struct twitter_data *td;
    1613         json_value *parsed;
     1615        JSON_Value *parsed;
    16141616        struct twitter_xml_list *txl;
    16151617
     
    16521654        struct im_connection *ic = req->data;
    16531655        struct twitter_data *td;
    1654         json_value *parsed, *id;
     1656        JSON_Value *parsed;
     1657        jint id;
    16551658
    16561659        // Check if the connection is still active.
     
    16661669        }
    16671670
    1668         if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
    1669                 td->last_status_id = id->u.integer;
     1671        if ((id = json_object_get_integer(json_object(parsed), "id"))) {
     1672                td->last_status_id = id;
    16701673        }
    16711674
     
    17881791{
    17891792        struct im_connection *ic = req->data;
    1790         json_value *parsed, *id;
     1793        JSON_Value *parsed;
     1794        uint64_t id;
    17911795        const char *name;
    17921796
     
    18001804        }
    18011805
    1802         /* for the parson branch:
    18031806        name = json_object_dotget_string(json_object(parsed), "user.screen_name");
    18041807        id = json_object_get_integer(json_object(parsed), "id");
    1805         */
    1806 
    1807         name = json_o_str(json_o_get(parsed, "user"), "screen_name");
    1808         id = json_o_get(parsed, "id");
    1809 
    1810         if (name && id && id->type == json_integer) {
    1811                 twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id->u.integer);
     1808
     1809        if (name && id) {
     1810                twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id);
    18121811        } else {
    18131812                twitter_log(ic, "Error: could not fetch tweet url.");
  • root_commands.c

    r9f03c47 r537d9b9  
    499499
    500500                for (a = irc->b->accounts; a; a = a->next) {
    501                         char *con;
     501                        char *con = NULL, *protocol = NULL;
    502502
    503503                        if (a->ic && (a->ic->flags & OPT_LOGGED_IN)) {
     
    510510                                con = "";
    511511                        }
    512 
    513                         irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, a->prpl->name, a->user, con);
     512                        if (a->prpl == &protocol_missing) {
     513                                protocol = g_strdup_printf("%s (missing!)", set_getstr(&a->set, "_protocol_name"));
     514                        } else {
     515                                protocol = g_strdup(a->prpl->name);
     516                        }
     517
     518                        irc_rootmsg(irc, "%2d (%s): %s, %s%s", i, a->tag, protocol, a->user, con);
     519                        g_free(protocol);
    514520
    515521                        i++;
     
    525531
    526532                        for (a = irc->b->accounts; a; a = a->next) {
    527                                 if (!a->ic && a->auto_connect) {
     533                                if (!a->ic && a->auto_connect && a->prpl != &protocol_missing) {
    528534                                        if (strcmp(a->pass, PASSWORD_PENDING) == 0) {
    529535                                                irc_rootmsg(irc, "Enter password for account %s "
     
    585591                        irc_rootmsg(irc, "Enter password for account %s "
    586592                                    "first (use /OPER)", a->tag);
     593                } else if (a->prpl == &protocol_missing) {
     594                        irc_rootmsg(irc, "Protocol `%s' not recognised (plugin may be missing or not running?)",
     595                                    set_getstr(&a->set, "_protocol_name"));
    587596                } else {
    588597                        account_on(irc->b, a);
     
    689698                irc_rootmsg(irc, "That account is not on-line");
    690699                return;
     700        } else if (add_on_server && !a->prpl->add_buddy) {
     701                irc_rootmsg(irc, "IM protocol does not support contact list modification");
     702                return;
     703        }
     704
     705        if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
     706            (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
     707                /* If there's no @ or it's the last char, append the user's
     708                   domain name now. Exclude handles starting with a _ so
     709                   adding _xmlconsole will keep working. */
     710                if (s) {
     711                        *s = '\0';
     712                }
     713                if ((s = strchr(a->user, '@'))) {
     714                        cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
     715                }
    691716        }
    692717
     
    703728        }
    704729
    705         if ((a->flags & ACC_FLAG_HANDLE_DOMAINS) && cmd[2][0] != '_' &&
    706             (!(s = strchr(cmd[2], '@')) || s[1] == '\0')) {
    707                 /* If there's no @ or it's the last char, append the user's
    708                    domain name now. Exclude handles starting with a _ so
    709                    adding _xmlconsole will keep working. */
    710                 if (s) {
    711                         *s = '\0';
    712                 }
    713                 if ((s = strchr(a->user, '@'))) {
    714                         cmd[2] = handle = g_strconcat(cmd[2], s, NULL);
    715                 }
    716         }
    717 
    718730        if (add_on_server) {
    719731                irc_channel_t *ic;
     
    759771        s = g_strdup(bu->handle);
    760772
    761         bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     773        if (bu->ic->acc->prpl->remove_buddy) {
     774                bu->ic->acc->prpl->remove_buddy(bu->ic, bu->handle, NULL);
     775        } else {
     776                irc_rootmsg(irc, "IM protocol does not support contact list modification, "
     777                                 "removal will likely not be permanent");
     778        }
     779
    762780        nick_del(bu);
    763781        if (g_slist_find(irc->users, iu)) {
  • storage.c

    r9f03c47 r537d9b9  
    3232
    3333static GList *storage_backends = NULL;
     34
     35const struct prpl protocol_missing = {
     36        .name = "_unknown",
     37};
    3438
    3539void register_storage_backend(storage_t *backend)
  • storage.h

    r9f03c47 r537d9b9  
    6363G_GNUC_MALLOC GList *storage_init(const char *primary, char **migrate);
    6464
     65extern const struct prpl protocol_missing;
     66
    6567#endif /* __STORAGE_H__ */
  • storage_xml.c

    r9f03c47 r537d9b9  
    8989}
    9090
     91/* Use for unsupported/not-found protocols. Save settings as-is but don't allow changes. */
     92static void handle_settings_raw(struct xt_node *node, set_t **head)
     93{
     94        struct xt_node *c;
     95
     96        for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) {
     97                char *name = xt_find_attr(c, "name");
     98
     99                if (!name) {
     100                        continue;
     101                }
     102
     103                set_t *s = set_add(head, name, NULL, NULL, NULL);
     104                set_setstr(head, name, c->text);
     105                s->flags |= SET_HIDDEN |
     106                            ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
     107        }
     108}
     109
    91110static xt_status handle_account(struct xt_node *node, gpointer data)
    92111{
     
    95114        char *pass_b64 = NULL;
    96115        unsigned char *pass_cr = NULL;
    97         int pass_len, local = 0;
     116        int pass_len;
    98117        struct prpl *prpl = NULL;
    99118        account_t *acc;
     
    111130                prpl = find_protocol(protocol);
    112131                if (!prpl) {
    113                         irc_rootmsg(xd->irc, "Error loading user config: Protocol not found: `%s'", protocol);
    114                         return XT_ABORT;
    115                 }
    116                 local = protocol_account_islocal(protocol);
     132                        irc_rootmsg(xd->irc, "Warning: Protocol not found: `%s'", protocol);
     133                        prpl = (struct prpl*) &protocol_missing;
     134                }
    117135        }
    118136
     
    143161                set_setstr(&acc->set, "tag", tag);
    144162        }
    145         if (local) {
    146                 acc->flags |= ACC_FLAG_LOCAL;
    147         }
    148163        if (locked && !g_strcasecmp(locked, "true")) {
    149164                acc->flags |= ACC_FLAG_LOCKED;
    150165        }
     166        if (prpl == &protocol_missing) {
     167                set_t *s = set_add(&acc->set, "_protocol_name", protocol, NULL, NULL);
     168                s->flags |= SET_HIDDEN | SET_NOSAVE |
     169                            ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY;
     170        }
    151171
    152172        g_free(pass_cr);
    153173        g_free(password);
    154174
    155         handle_settings(node, &acc->set);
     175        if (prpl == &protocol_missing) {
     176                handle_settings_raw(node, &acc->set);
     177        } else {
     178                handle_settings(node, &acc->set);
     179        }
    156180
    157181        for (c = node->children; (c = xt_find_node(c, "buddy")); c = c->next) {
     
    342366
    343367                cur = xt_new_node("account", NULL, NULL);
    344                 xt_add_attr(cur, "protocol", acc->prpl->name);
     368                if (acc->prpl == &protocol_missing) {
     369                        xt_add_attr(cur, "protocol", set_getstr(&acc->set, "_protocol_name"));
     370                } else {
     371                        xt_add_attr(cur, "protocol", acc->prpl->name);
     372                }
    345373                xt_add_attr(cur, "handle", acc->user);
    346374                xt_add_attr(cur, "password", pass_b64);
Note: See TracChangeset for help on using the changeset viewer.