source: skype/skype.c @ 4d30309

Last change on this file since 4d30309 was 7670b02, checked in by Miklos Vajna <vmiklos@…>, at 2010-08-03T12:39:52Z

build for <1.3

  • Property mode set to 100644
File size: 33.6 KB
RevLine 
[7daec06]1/*
2 *  skype.c - Skype plugin for BitlBee
[5adcc65]3 *
[7cf146f]4 *  Copyright (c) 2007, 2008, 2009, 2010 by Miklos Vajna <vmiklos@frugalware.org>
[f06e3ac]5 *
[7daec06]6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
[5adcc65]18 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
[7daec06]19 *  USA.
[f06e3ac]20 */
[7daec06]21
[f9c3e7b]22#define _XOPEN_SOURCE
[1f4fc80]23#define _BSD_SOURCE
[ed2e37f]24#include <poll.h>
[f06e3ac]25#include <bitlbee.h>
[c7304b2]26#include <bitlbee/ssl_client.h>
[f06e3ac]27
[f5aedd91]28#define SKYPE_DEFAULT_SERVER "localhost"
[4bbd9db]29#define SKYPE_DEFAULT_PORT "2727"
[c213d6b]30#define IRC_LINE_SIZE 1024
[ff436ba]31#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
[f06e3ac]32
[78d22cd0]33/*
34 * Compatibility with BitlBee 1.3+
35 */
[7670b02]36#if BITLBEE_VERSION_CODE < BITLBEE_VER(1, 3, 0)
37#define B_EV_IO_READ GAIM_INPUT_READ
[78d22cd0]38#endif
39
[bbba374]40/*
41 * Enumerations
42 */
43
[359f4d9]44enum {
[df9255d]45        SKYPE_CALL_RINGING = 1,
[9db0234]46        SKYPE_CALL_MISSED,
[2eb4b1f]47        SKYPE_CALL_CANCELLED,
[acd9478]48        SKYPE_CALL_FINISHED,
[d87daf3]49        SKYPE_CALL_REFUSED
[5365f84]50};
[bbba374]51
[359f4d9]52enum {
[df9255d]53        SKYPE_FILETRANSFER_NEW = 1,
54        SKYPE_FILETRANSFER_FAILED
[5365f84]55};
[df9255d]56
[7daec06]57/*
58 * Structures
59 */
60
[5adcc65]61struct skype_data {
[f06e3ac]62        struct im_connection *ic;
[a3d6427]63        char *username;
[368861e]64        /* The effective file descriptor. We store it here so any function can
65         * write() to it. */
[f06e3ac]66        int fd;
[368861e]67        /* File descriptor returned by bitlbee. we store it so we know when
68         * we're connected and when we aren't. */
69        int bfd;
[c7304b2]70        /* ssl_getfd() uses this to get the file desciptor. */
71        void *ssl;
[2a0f99c]72        /* When we receive a new message id, we query the properties, finally
73         * the chatname. Store the properties here so that we can use
[c81d0ef]74         * imcb_buddy_msg() when we got the chatname. */
[77c1abe]75        char *handle;
[a7af5f0]76        /* List, because of multiline messages. */
77        GList *body;
[2a0f99c]78        char *type;
[bbba374]79        /* This is necessary because we send a notification when we get the
80         * handle. So we store the state here and then we can send a
81         * notification about the handle is in a given status. */
[359f4d9]82        int call_status;
[2eb4b1f]83        char *call_id;
[48181f0]84        char *call_duration;
[d87daf3]85        /* If the call is outgoing or not */
86        int call_out;
[df9255d]87        /* Same for file transfers. */
[359f4d9]88        int filetransfer_status;
[86278cd]89        /* Using /j #nick we want to have a groupchat with two people. Usually
90         * not (default). */
[5adcc65]91        char *groupchat_with;
[f8674db]92        /* The user who invited us to the chat. */
[5adcc65]93        char *adder;
[a5f76a2]94        /* If we are waiting for a confirmation about we changed the topic. */
95        int topic_wait;
[67454bd]96        /* These are used by the info command. */
97        char *info_fullname;
98        char *info_phonehome;
99        char *info_phoneoffice;
100        char *info_phonemobile;
101        char *info_nrbuddies;
102        char *info_tz;
103        char *info_seen;
104        char *info_birthday;
105        char *info_sex;
106        char *info_language;
107        char *info_country;
108        char *info_province;
109        char *info_city;
110        char *info_homepage;
111        char *info_about;
[b054fad]112        /* When a call fails, we get the reason and later we get the failure
113         * event, so store the failure code here till then */
114        int failurereason;
[d9ce18c]115        /* If this is just an update of an already received message. */
116        int is_edit;
[f06e3ac]117};
118
[5adcc65]119struct skype_away_state {
[adce2de]120        char *code;
121        char *full_name;
122};
123
[5adcc65]124struct skype_buddy_ask_data {
[7daec06]125        struct im_connection *ic;
[e0074cb]126        /* This is also used for call IDs for simplicity */
[7daec06]127        char *handle;
128};
129
130/*
131 * Tables
132 */
133
[5adcc65]134const struct skype_away_state skype_away_state_list[] = {
[bc744df]135        { "AWAY", "Away" },
136        { "NA", "Not available" },
137        { "DND", "Do Not Disturb" },
138        { "INVISIBLE", "Invisible" },
139        { "OFFLINE", "Offline" },
[4b740c2]140        { "SKYPEME", "Skype Me" },
141        { "ONLINE", "Online" },
[23411c6]142        { NULL, NULL}
[adce2de]143};
144
[7daec06]145/*
146 * Functions
147 */
[d3cbd17]148
[7c300bb]149int skype_write(struct im_connection *ic, char *buf, int len)
[f06e3ac]150{
151        struct skype_data *sd = ic->proto_data;
[1fb89e3]152        struct pollfd pfd[1];
153
154        pfd[0].fd = sd->fd;
155        pfd[0].events = POLLOUT;
[f06e3ac]156
[7daec06]157        /* This poll is necessary or we'll get a SIGPIPE when we write() to
158         * sd->fd. */
[1fb89e3]159        poll(pfd, 1, 1000);
[5adcc65]160        if (pfd[0].revents & POLLHUP) {
161                imc_logout(ic, TRUE);
[1fb89e3]162                return FALSE;
163        }
[5adcc65]164        ssl_write(sd->ssl, buf, len);
[f06e3ac]165
[9fd4241]166        return TRUE;
[f06e3ac]167}
168
[1f4fc80]169int skype_printf(struct im_connection *ic, char *fmt, ...)
170{
171        va_list args;
172        char str[IRC_LINE_SIZE];
[5d9db76]173
[1f4fc80]174        va_start(args, fmt);
175        vsnprintf(str, IRC_LINE_SIZE, fmt, args);
176        va_end(args);
177
[7c300bb]178        return skype_write(ic, str, strlen(str));
[1f4fc80]179}
180
[5adcc65]181static void skype_buddy_ask_yes(void *data)
[d3cbd17]182{
[039116a]183        struct skype_buddy_ask_data *bla = data;
[1f4fc80]184        skype_printf(bla->ic, "SET USER %s ISAUTHORIZED TRUE",
[8c09bb3]185                bla->handle);
[d3cbd17]186        g_free(bla->handle);
187        g_free(bla);
188}
189
[5adcc65]190static void skype_buddy_ask_no(void *data)
[d3cbd17]191{
[039116a]192        struct skype_buddy_ask_data *bla = data;
[1f4fc80]193        skype_printf(bla->ic, "SET USER %s ISAUTHORIZED FALSE",
[8c09bb3]194                bla->handle);
[d3cbd17]195        g_free(bla->handle);
196        g_free(bla);
197}
198
[5adcc65]199void skype_buddy_ask(struct im_connection *ic, char *handle, char *message)
[d3cbd17]200{
[8c09bb3]201        struct skype_buddy_ask_data *bla = g_new0(struct skype_buddy_ask_data,
202                1);
[d3cbd17]203        char *buf;
204
205        bla->ic = ic;
206        bla->handle = g_strdup(handle);
207
[8c09bb3]208        buf = g_strdup_printf("The user %s wants to add you to "
209                "his/her buddy list, saying: '%s'.", handle, message);
[5adcc65]210        imcb_ask(ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no);
211        g_free(buf);
[d3cbd17]212}
213
[5adcc65]214static void skype_call_ask_yes(void *data)
[e0074cb]215{
[039116a]216        struct skype_buddy_ask_data *bla = data;
[1f4fc80]217        skype_printf(bla->ic, "SET CALL %s STATUS INPROGRESS",
[8c09bb3]218                bla->handle);
[e0074cb]219        g_free(bla->handle);
220        g_free(bla);
221}
222
[5adcc65]223static void skype_call_ask_no(void *data)
[e0074cb]224{
[039116a]225        struct skype_buddy_ask_data *bla = data;
[1f4fc80]226        skype_printf(bla->ic, "SET CALL %s STATUS FINISHED",
[8c09bb3]227                bla->handle);
[e0074cb]228        g_free(bla->handle);
229        g_free(bla);
230}
231
[5adcc65]232void skype_call_ask(struct im_connection *ic, char *call_id, char *message)
[e0074cb]233{
[8c09bb3]234        struct skype_buddy_ask_data *bla = g_new0(struct skype_buddy_ask_data,
235                1);
[e0074cb]236
237        bla->ic = ic;
238        bla->handle = g_strdup(call_id);
239
[5adcc65]240        imcb_ask(ic, message, bla, skype_call_ask_yes, skype_call_ask_no);
[e0074cb]241}
[5adcc65]242struct groupchat *skype_chat_by_name(struct im_connection *ic, char *name)
[72aa7f0]243{
[78d22cd0]244#if BITLBEE_VERSION_CODE < BITLBEE_VER(1, 3, 0)
[72aa7f0]245        struct groupchat *ret;
246
[5adcc65]247        for (ret = ic->groupchats; ret; ret = ret->next)
248                if (strcmp(name, ret->title) == 0)
[72aa7f0]249                        break;
250
251        return ret;
[78d22cd0]252#else
253        return bee_chat_by_title(ic->bee, ic, name);
254#endif
[72aa7f0]255}
256
[b054fad]257static char *skype_call_strerror(int err)
258{
[5adcc65]259        switch (err) {
260        case 1:
261                return "Miscellaneous error";
262        case 2:
263                return "User or phone number does not exist.";
264        case 3:
265                return "User is offline";
266        case 4:
267                return "No proxy found";
268        case 5:
269                return "Session terminated.";
270        case 6:
271                return "No common codec found.";
272        case 7:
273                return "Sound I/O error.";
274        case 8:
275                return "Problem with remote sound device.";
276        case 9:
277                return "Call blocked by recipient.";
278        case 10:
279                return "Recipient not a friend.";
280        case 11:
281                return "Current user not authorized by recipient.";
282        case 12:
283                return "Sound recording error.";
284        default:
285                return "Unknown error";
[b054fad]286        }
287}
288
[078b0b9]289static void skype_parse_users(struct im_connection *ic, char *line)
290{
[1f4fc80]291        char **i, **nicks;
[078b0b9]292
293        nicks = g_strsplit(line + 6, ", ", 0);
[1f4fc80]294        for (i = nicks; *i; i++)
295                skype_printf(ic, "GET USER %s ONLINESTATUS\n", *i);
[078b0b9]296        g_strfreev(nicks);
297}
298
[6e14204]299static void skype_parse_user(struct im_connection *ic, char *line)
300{
301        int flags = 0;
302        char *ptr;
303        struct skype_data *sd = ic->proto_data;
304        char *user = strchr(line, ' ');
305        char *status = strrchr(line, ' ');
306
307        status++;
308        ptr = strchr(++user, ' ');
309        if (!ptr)
310                return;
311        *ptr = '\0';
312        ptr++;
[49a3c02]313        if (!strncmp(ptr, "ONLINESTATUS ", 13)) {
314                        if (!strcmp(user, sd->username))
315                                return;
316                        if (!set_getbool(&ic->acc->set, "test_join")
317                                && !strcmp(user, "echo123"))
318                                return;
[6e14204]319                ptr = g_strdup_printf("%s@skype.com", user);
320                imcb_add_buddy(ic, ptr, NULL);
[62f51ee9]321                if (strcmp(status, "OFFLINE") && (strcmp(status, "SKYPEOUT") ||
322                        !set_getbool(&ic->acc->set, "skypeout_offline")))
[6e14204]323                        flags |= OPT_LOGGED_IN;
[62f51ee9]324                if (strcmp(status, "ONLINE") && strcmp(status, "SKYPEME"))
[6e14204]325                        flags |= OPT_AWAY;
326                imcb_buddy_status(ic, ptr, flags, NULL, NULL);
327                g_free(ptr);
328        } else if (!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20)) {
329                char *message = ptr + 20;
330                if (strlen(message))
331                        skype_buddy_ask(ic, user, message);
332        } else if (!strncmp(ptr, "BUDDYSTATUS ", 12)) {
333                char *st = ptr + 12;
334                if (!strcmp(st, "3")) {
335                        char *buf = g_strdup_printf("%s@skype.com", user);
336                        imcb_add_buddy(ic, buf, NULL);
337                        g_free(buf);
338                }
[78d22cd0]339        } else if (!strncmp(ptr, "MOOD_TEXT ", 10)) {
[4c674bb]340                char *buf = g_strdup_printf("%s@skype.com", user);
[78d22cd0]341#if BITLBEE_VERSION_CODE < BITLBEE_VER(1, 3, 0)
[4c674bb]342                user_t *u = user_findhandle(ic, buf);
343                g_free(buf);
344                buf = ptr + 10;
345                if (u) {
346                        if (u->status_msg)
347                                g_free(u->status_msg);
348                        if (strlen(buf))
349                                u->status_msg = g_strdup(buf);
350                        else
351                                u->status_msg = NULL;
352                }
[78d22cd0]353#else
354                bee_user_t *bu = bee_user_by_handle(ic->bee, ic, buf);
355                g_free(buf);
356                buf = ptr + 10;
357                if (bu) {
358                        imcb_buddy_status(ic, bu->handle, bu->flags, NULL,
[4ab7225]359                                        *buf ? buf : NULL);
[78d22cd0]360                }
361#endif
362                if (set_getbool(&ic->acc->set, "show_moods"))
363                        imcb_log(ic, "User `%s' changed mood text to `%s'", user, buf);
[3518933]364        } else if (!strncmp(ptr, "FULLNAME ", 9))
[d7938f9]365                sd->info_fullname = g_strdup(ptr + 9);
[6e14204]366        else if (!strncmp(ptr, "PHONE_HOME ", 11))
[d7938f9]367                sd->info_phonehome = g_strdup(ptr + 11);
[6e14204]368        else if (!strncmp(ptr, "PHONE_OFFICE ", 13))
[d7938f9]369                sd->info_phoneoffice = g_strdup(ptr + 13);
[6e14204]370        else if (!strncmp(ptr, "PHONE_MOBILE ", 13))
[d7938f9]371                sd->info_phonemobile = g_strdup(ptr + 13);
[6e14204]372        else if (!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20))
[d7938f9]373                sd->info_nrbuddies = g_strdup(ptr + 20);
[6e14204]374        else if (!strncmp(ptr, "TIMEZONE ", 9))
[d7938f9]375                sd->info_tz = g_strdup(ptr + 9);
[6e14204]376        else if (!strncmp(ptr, "LASTONLINETIMESTAMP ", 20))
[d7938f9]377                sd->info_seen = g_strdup(ptr + 20);
[6e14204]378        else if (!strncmp(ptr, "BIRTHDAY ", 9))
[d7938f9]379                sd->info_birthday = g_strdup(ptr + 9);
[6e14204]380        else if (!strncmp(ptr, "SEX ", 4))
[d7938f9]381                sd->info_sex = g_strdup(ptr + 4);
[6e14204]382        else if (!strncmp(ptr, "LANGUAGE ", 9))
[d7938f9]383                sd->info_language = g_strdup(ptr + 9);
[6e14204]384        else if (!strncmp(ptr, "COUNTRY ", 8))
[d7938f9]385                sd->info_country = g_strdup(ptr + 8);
[6e14204]386        else if (!strncmp(ptr, "PROVINCE ", 9))
[d7938f9]387                sd->info_province = g_strdup(ptr + 9);
[6e14204]388        else if (!strncmp(ptr, "CITY ", 5))
[d7938f9]389                sd->info_city = g_strdup(ptr + 5);
[6e14204]390        else if (!strncmp(ptr, "HOMEPAGE ", 9))
[d7938f9]391                sd->info_homepage = g_strdup(ptr + 9);
[6e14204]392        else if (!strncmp(ptr, "ABOUT ", 6)) {
[d7938f9]393                sd->info_about = g_strdup(ptr + 6);
[6e14204]394
395                GString *st = g_string_new("Contact Information\n");
396                g_string_append_printf(st, "Skype Name: %s\n", user);
397                if (sd->info_fullname) {
398                        if (strlen(sd->info_fullname))
[62f51ee9]399                                g_string_append_printf(st, "Full Name: %s\n",
400                                        sd->info_fullname);
[6e14204]401                        g_free(sd->info_fullname);
402                }
403                if (sd->info_phonehome) {
404                        if (strlen(sd->info_phonehome))
[62f51ee9]405                                g_string_append_printf(st, "Home Phone: %s\n",
406                                        sd->info_phonehome);
[6e14204]407                        g_free(sd->info_phonehome);
408                }
409                if (sd->info_phoneoffice) {
410                        if (strlen(sd->info_phoneoffice))
[62f51ee9]411                                g_string_append_printf(st, "Office Phone: %s\n",
412                                        sd->info_phoneoffice);
[6e14204]413                        g_free(sd->info_phoneoffice);
414                }
415                if (sd->info_phonemobile) {
416                        if (strlen(sd->info_phonemobile))
[62f51ee9]417                                g_string_append_printf(st, "Mobile Phone: %s\n",
418                                        sd->info_phonemobile);
[6e14204]419                        g_free(sd->info_phonemobile);
420                }
421                g_string_append_printf(st, "Personal Information\n");
422                if (sd->info_nrbuddies) {
423                        if (strlen(sd->info_nrbuddies))
[62f51ee9]424                                g_string_append_printf(st,
425                                        "Contacts: %s\n", sd->info_nrbuddies);
[6e14204]426                        g_free(sd->info_nrbuddies);
427                }
428                if (sd->info_tz) {
429                        if (strlen(sd->info_tz)) {
430                                char ib[256];
431                                time_t t = time(NULL);
432                                t += atoi(sd->info_tz)-(60*60*24);
433                                struct tm *gt = gmtime(&t);
434                                strftime(ib, 256, "%H:%M:%S", gt);
[62f51ee9]435                                g_string_append_printf(st,
436                                        "Local Time: %s\n", ib);
[6e14204]437                        }
438                        g_free(sd->info_tz);
439                }
440                if (sd->info_seen) {
441                        if (strlen(sd->info_seen)) {
442                                char ib[256];
443                                time_t it = atoi(sd->info_seen);
444                                struct tm *tm = localtime(&it);
445                                strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm);
[62f51ee9]446                                g_string_append_printf(st,
447                                        "Last Seen: %s\n", ib);
[6e14204]448                        }
449                        g_free(sd->info_seen);
450                }
451                if (sd->info_birthday) {
[62f51ee9]452                        if (strlen(sd->info_birthday) &&
453                                strcmp(sd->info_birthday, "0")) {
[6e14204]454                                char ib[256];
455                                struct tm tm;
456                                strptime(sd->info_birthday, "%Y%m%d", &tm);
457                                strftime(ib, 256, "%B %d, %Y", &tm);
[62f51ee9]458                                g_string_append_printf(st,
459                                        "Birthday: %s\n", ib);
[6e14204]460
461                                strftime(ib, 256, "%Y", &tm);
462                                int year = atoi(ib);
463                                time_t t = time(NULL);
464                                struct tm *lt = localtime(&t);
[62f51ee9]465                                g_string_append_printf(st,
466                                        "Age: %d\n", lt->tm_year+1900-year);
[6e14204]467                        }
468                        g_free(sd->info_birthday);
469                }
470                if (sd->info_sex) {
471                        if (strlen(sd->info_sex)) {
472                                char *iptr = sd->info_sex;
473                                while (*iptr++)
474                                        *iptr = tolower(*iptr);
[62f51ee9]475                                g_string_append_printf(st,
476                                        "Gender: %s\n", sd->info_sex);
[6e14204]477                        }
478                        g_free(sd->info_sex);
479                }
480                if (sd->info_language) {
481                        if (strlen(sd->info_language)) {
482                                char *iptr = strchr(sd->info_language, ' ');
483                                if (iptr)
484                                        iptr++;
485                                else
486                                        iptr = sd->info_language;
[62f51ee9]487                                g_string_append_printf(st,
488                                        "Language: %s\n", iptr);
[6e14204]489                        }
490                        g_free(sd->info_language);
491                }
492                if (sd->info_country) {
493                        if (strlen(sd->info_country)) {
494                                char *iptr = strchr(sd->info_country, ' ');
495                                if (iptr)
496                                        iptr++;
497                                else
498                                        iptr = sd->info_country;
[62f51ee9]499                                g_string_append_printf(st,
500                                        "Country: %s\n", iptr);
[6e14204]501                        }
502                        g_free(sd->info_country);
503                }
504                if (sd->info_province) {
505                        if (strlen(sd->info_province))
[62f51ee9]506                                g_string_append_printf(st,
507                                        "Region: %s\n", sd->info_province);
[6e14204]508                        g_free(sd->info_province);
509                }
510                if (sd->info_city) {
511                        if (strlen(sd->info_city))
[62f51ee9]512                                g_string_append_printf(st,
513                                        "City: %s\n", sd->info_city);
[6e14204]514                        g_free(sd->info_city);
515                }
516                if (sd->info_homepage) {
517                        if (strlen(sd->info_homepage))
[62f51ee9]518                                g_string_append_printf(st,
519                                        "Homepage: %s\n", sd->info_homepage);
[6e14204]520                        g_free(sd->info_homepage);
521                }
522                if (sd->info_about) {
523                        if (strlen(sd->info_about))
[62f51ee9]524                                g_string_append_printf(st, "%s\n",
525                                        sd->info_about);
[6e14204]526                        g_free(sd->info_about);
527                }
528                imcb_log(ic, "%s", st->str);
529                g_string_free(st, TRUE);
530        }
531}
532
533static void skype_parse_chatmessage(struct im_connection *ic, char *line)
534{
535        struct skype_data *sd = ic->proto_data;
[c213d6b]536        char buf[IRC_LINE_SIZE];
[6e14204]537        char *id = strchr(line, ' ');
538
[6b9d22a]539        if (!++id)
540                return;
541        char *info = strchr(id, ' ');
542
543        if (!info)
544                return;
545        *info = '\0';
546        info++;
[7825f58]547        if (!strcmp(info, "STATUS RECEIVED") || !strncmp(info, "EDITED_TIMESTAMP", 16)) {
[6b9d22a]548                /* New message ID:
549                 * (1) Request its from field
550                 * (2) Request its body
551                 * (3) Request its type
552                 * (4) Query chatname
553                 */
[1f4fc80]554                skype_printf(ic, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
[d1d5b34]555                if (!strcmp(info, "STATUS RECEIVED"))
556                        skype_printf(ic, "GET CHATMESSAGE %s BODY\n", id);
[d9ce18c]557                else
558                        sd->is_edit = 1;
[1f4fc80]559                skype_printf(ic, "GET CHATMESSAGE %s TYPE\n", id);
560                skype_printf(ic, "GET CHATMESSAGE %s CHATNAME\n", id);
[6b9d22a]561        } else if (!strncmp(info, "FROM_HANDLE ", 12)) {
562                info += 12;
563                /* New from field value. Store
564                 * it, then we can later use it
565                 * when we got the message's
566                 * body. */
567                g_free(sd->handle);
568                sd->handle = g_strdup_printf("%s@skype.com", info);
569        } else if (!strncmp(info, "EDITED_BY ", 10)) {
570                info += 10;
571                /* This is the same as
572                 * FROM_HANDLE, except that we
573                 * never request these lines
574                 * from Skype, we just get
575                 * them. */
576                g_free(sd->handle);
577                sd->handle = g_strdup_printf("%s@skype.com", info);
578        } else if (!strncmp(info, "BODY ", 5)) {
579                info += 5;
580                sd->body = g_list_append(sd->body, g_strdup(info));
581        }       else if (!strncmp(info, "TYPE ", 5)) {
582                info += 5;
583                g_free(sd->type);
584                sd->type = g_strdup(info);
[7825f58]585        } else if (!strncmp(info, "CHATNAME ", 9)) {
586                info += 9;
587                if (sd->handle && sd->body && sd->type) {
588                        struct groupchat *gc = skype_chat_by_name(ic, info);
589                        int i;
590                        for (i = 0; i < g_list_length(sd->body); i++) {
591                                char *body = g_list_nth_data(sd->body, i);
592                                if (!strcmp(sd->type, "SAID") ||
593                                        !strcmp(sd->type, "EMOTED")) {
594                                        if (!strcmp(sd->type, "SAID")) {
595                                                if (!sd->is_edit)
596                                                        g_snprintf(buf, IRC_LINE_SIZE, "%s",
597                                                                body);
598                                                else {
599                                                        g_snprintf(buf, IRC_LINE_SIZE, "%s %s",
600                                                                set_getstr(&ic->acc->set, "edit_prefix"),
601                                                                body);
602                                                        sd->is_edit = 0;
603                                                }
604                                        } else
605                                                g_snprintf(buf, IRC_LINE_SIZE, "/me %s",
606                                                        body);
607                                        if (!gc)
608                                                /* Private message */
609                                                imcb_buddy_msg(ic,
610                                                        sd->handle, buf, 0, 0);
611                                        else
612                                                /* Groupchat message */
613                                                imcb_chat_msg(gc,
614                                                        sd->handle, buf, 0, 0);
615                                } else if (!strcmp(sd->type, "SETTOPIC") && gc)
616                                        imcb_chat_topic(gc,
617                                                sd->handle, body, 0);
618                                else if (!strcmp(sd->type, "LEFT") && gc)
619                                        imcb_chat_remove_buddy(gc,
620                                                sd->handle, NULL);
[6e14204]621                        }
[7825f58]622                        g_list_free(sd->body);
623                        sd->body = NULL;
624                }
[6e14204]625        }
626}
627
[9f2f25f]628static void skype_parse_call(struct im_connection *ic, char *line)
629{
630        struct skype_data *sd = ic->proto_data;
631        char *id = strchr(line, ' ');
[c213d6b]632        char buf[IRC_LINE_SIZE];
[9f2f25f]633
[6b9d22a]634        if (!++id)
635                return;
636        char *info = strchr(id, ' ');
637
638        if (!info)
639                return;
640        *info = '\0';
641        info++;
642        if (!strncmp(info, "FAILUREREASON ", 14))
643                sd->failurereason = atoi(strchr(info, ' '));
644        else if (!strcmp(info, "STATUS RINGING")) {
645                if (sd->call_id)
646                        g_free(sd->call_id);
647                sd->call_id = g_strdup(id);
[1f4fc80]648                skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id);
[6b9d22a]649                sd->call_status = SKYPE_CALL_RINGING;
650        } else if (!strcmp(info, "STATUS MISSED")) {
[1f4fc80]651                skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id);
[6b9d22a]652                sd->call_status = SKYPE_CALL_MISSED;
653        } else if (!strcmp(info, "STATUS CANCELLED")) {
[1f4fc80]654                skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id);
[6b9d22a]655                sd->call_status = SKYPE_CALL_CANCELLED;
656        } else if (!strcmp(info, "STATUS FINISHED")) {
[1f4fc80]657                skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id);
[6b9d22a]658                sd->call_status = SKYPE_CALL_FINISHED;
659        } else if (!strcmp(info, "STATUS REFUSED")) {
[1f4fc80]660                skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id);
[6b9d22a]661                sd->call_status = SKYPE_CALL_REFUSED;
662        } else if (!strcmp(info, "STATUS UNPLACED")) {
663                if (sd->call_id)
664                        g_free(sd->call_id);
665                /* Save the ID for later usage (Cancel/Finish). */
666                sd->call_id = g_strdup(id);
667                sd->call_out = TRUE;
668        } else if (!strcmp(info, "STATUS FAILED")) {
[62f51ee9]669                imcb_error(ic, "Call failed: %s",
670                        skype_call_strerror(sd->failurereason));
[6b9d22a]671                sd->call_id = NULL;
672        } else if (!strncmp(info, "DURATION ", 9)) {
673                if (sd->call_duration)
674                        g_free(sd->call_duration);
675                sd->call_duration = g_strdup(info+9);
676        } else if (!strncmp(info, "PARTNER_HANDLE ", 15)) {
677                info += 15;
[62f51ee9]678                if (!sd->call_status)
679                        return;
680                switch (sd->call_status) {
681                case SKYPE_CALL_RINGING:
682                        if (sd->call_out)
683                                imcb_log(ic, "You are currently ringing "
684                                        "the user %s.", info);
685                        else {
[c213d6b]686                                g_snprintf(buf, IRC_LINE_SIZE,
[62f51ee9]687                                        "The user %s is currently ringing you.",
688                                        info);
689                                skype_call_ask(ic, sd->call_id, buf);
[9f2f25f]690                        }
[62f51ee9]691                        break;
692                case SKYPE_CALL_MISSED:
693                        imcb_log(ic, "You have missed a call from user %s.",
694                                info);
695                        break;
696                case SKYPE_CALL_CANCELLED:
697                        imcb_log(ic, "You cancelled the call to the user %s.",
698                                info);
[6b9d22a]699                        sd->call_status = 0;
[62f51ee9]700                        sd->call_out = FALSE;
701                        break;
702                case SKYPE_CALL_REFUSED:
703                        if (sd->call_out)
704                                imcb_log(ic, "The user %s refused the call.",
705                                        info);
706                        else
707                                imcb_log(ic,
708                                        "You refused the call from user %s.",
709                                        info);
710                        sd->call_out = FALSE;
711                        break;
712                case SKYPE_CALL_FINISHED:
713                        if (sd->call_duration)
714                                imcb_log(ic,
715                                        "You finished the call to the user %s "
716                                        "(duration: %s seconds).",
717                                        info, sd->call_duration);
718                        else
719                                imcb_log(ic,
720                                        "You finished the call to the user %s.",
721                                        info);
722                        sd->call_out = FALSE;
723                        break;
724                default:
725                        /* Don't be noisy, ignore other statuses for now. */
726                        break;
[9f2f25f]727                }
[62f51ee9]728                sd->call_status = 0;
[9f2f25f]729        }
730}
731
[e200daf]732static void skype_parse_filetransfer(struct im_connection *ic, char *line)
733{
734        struct skype_data *sd = ic->proto_data;
735        char *id = strchr(line, ' ');
736
[6b9d22a]737        if (!++id)
738                return;
739        char *info = strchr(id, ' ');
740
741        if (!info)
742                return;
743        *info = '\0';
744        info++;
745        if (!strcmp(info, "STATUS NEW")) {
[1f4fc80]746                skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n",
[62f51ee9]747                        id);
[6b9d22a]748                sd->filetransfer_status = SKYPE_FILETRANSFER_NEW;
749        } else if (!strcmp(info, "STATUS FAILED")) {
[1f4fc80]750                skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n",
[62f51ee9]751                        id);
[6b9d22a]752                sd->filetransfer_status = SKYPE_FILETRANSFER_FAILED;
753        } else if (!strncmp(info, "PARTNER_HANDLE ", 15)) {
754                info += 15;
[62f51ee9]755                if (!sd->filetransfer_status)
756                        return;
757                switch (sd->filetransfer_status) {
758                case SKYPE_FILETRANSFER_NEW:
759                        imcb_log(ic, "The user %s offered a new file for you.",
760                                info);
761                        break;
762                case SKYPE_FILETRANSFER_FAILED:
763                        imcb_log(ic, "Failed to transfer file from user %s.",
764                                info);
765                        break;
[e200daf]766                }
[62f51ee9]767                sd->filetransfer_status = 0;
[e200daf]768        }
769}
770
[c35bf7a]771static void skype_parse_chat(struct im_connection *ic, char *line)
772{
773        struct skype_data *sd = ic->proto_data;
[c213d6b]774        char buf[IRC_LINE_SIZE];
[c35bf7a]775        char *id = strchr(line, ' ');
776
[6b9d22a]777        if (!++id)
778                return;
779        struct groupchat *gc;
780        char *info = strchr(id, ' ');
[c35bf7a]781
[6b9d22a]782        if (!info)
783                return;
784        *info = '\0';
785        info++;
786        /* Remove fake chat if we created one in skype_chat_with() */
787        gc = skype_chat_by_name(ic, "");
788        if (gc)
789                imcb_chat_free(gc);
790        if (!strcmp(info, "STATUS MULTI_SUBSCRIBED")) {
[72b60c7e]791                gc = imcb_chat_new(ic, id);
792                imcb_chat_name_hint(gc, id);
[1f4fc80]793                skype_printf(ic, "GET CHAT %s ADDER\n", id);
794                skype_printf(ic, "GET CHAT %s TOPIC\n", id);
[6b9d22a]795        } else if (!strcmp(info, "STATUS DIALOG") && sd->groupchat_with) {
796                gc = imcb_chat_new(ic, id);
[72b60c7e]797                imcb_chat_name_hint(gc, id);
[6b9d22a]798                /* According to the docs this
799                 * is necessary. However it
800                 * does not seem the situation
801                 * and it would open an extra
802                 * window on our client, so
803                 * just leave it out. */
[1f4fc80]804                /*skype_printf(ic, "OPEN CHAT %s\n", id);*/
[5d9db76]805                g_snprintf(buf, IRC_LINE_SIZE, "%s@skype.com",
806                                sd->groupchat_with);
[6b9d22a]807                imcb_chat_add_buddy(gc, buf);
808                imcb_chat_add_buddy(gc, sd->username);
809                g_free(sd->groupchat_with);
810                sd->groupchat_with = NULL;
[1f4fc80]811                skype_printf(ic, "GET CHAT %s ADDER\n", id);
812                skype_printf(ic, "GET CHAT %s TOPIC\n", id);
[6b9d22a]813        } else if (!strcmp(info, "STATUS UNSUBSCRIBED")) {
814                gc = skype_chat_by_name(ic, id);
[c35bf7a]815                if (gc)
[6b9d22a]816                        gc->data = (void *)FALSE;
817        } else if (!strncmp(info, "ADDER ", 6)) {
818                info += 6;
819                g_free(sd->adder);
820                sd->adder = g_strdup_printf("%s@skype.com", info);
821        } else if (!strncmp(info, "TOPIC ", 6)) {
822                info += 6;
823                gc = skype_chat_by_name(ic, id);
824                if (gc && (sd->adder || sd->topic_wait)) {
825                        if (sd->topic_wait) {
826                                sd->adder = g_strdup(sd->username);
827                                sd->topic_wait = 0;
[c35bf7a]828                        }
[6b9d22a]829                        imcb_chat_topic(gc, sd->adder, info, 0);
830                        g_free(sd->adder);
831                        sd->adder = NULL;
832                }
833        } else if (!strncmp(info, "ACTIVEMEMBERS ", 14)) {
834                info += 14;
835                gc = skype_chat_by_name(ic, id);
836                /* Hack! We set ->data to TRUE
837                 * while we're on the channel
838                 * so that we won't rejoin
839                 * after a /part. */
[62f51ee9]840                if (!gc || gc->data)
841                        return;
842                char **members = g_strsplit(info, " ", 0);
843                int i;
844                for (i = 0; members[i]; i++) {
845                        if (!strcmp(members[i], sd->username))
846                                continue;
[5d9db76]847                        g_snprintf(buf, IRC_LINE_SIZE, "%s@skype.com",
848                                        members[i]);
[62f51ee9]849                        if (!g_list_find_custom(gc->in_room, buf,
850                                (GCompareFunc)strcmp))
851                                imcb_chat_add_buddy(gc, buf);
[c35bf7a]852                }
[62f51ee9]853                imcb_chat_add_buddy(gc, sd->username);
854                g_strfreev(members);
[c35bf7a]855        }
856}
857
[2709f4c]858static void skype_parse_password(struct im_connection *ic, char *line)
859{
860        if (!strncmp(line+9, "OK", 2))
861                imcb_connected(ic);
862        else {
863                imcb_error(ic, "Authentication Failed");
864                imc_logout(ic, TRUE);
865        }
866}
867
[607f5e3]868static void skype_parse_profile(struct im_connection *ic, char *line)
869{
870        imcb_log(ic, "SkypeOut balance value is '%s'.", line+21);
871}
872
873static void skype_parse_ping(struct im_connection *ic, char *line)
874{
[1f4fc80]875        skype_printf(ic, "PONG\n");
[607f5e3]876}
877
878static void skype_parse_chats(struct im_connection *ic, char *line)
879{
880        char **i;
881        char **chats = g_strsplit(line + 6, ", ", 0);
882
883        i = chats;
884        while (*i) {
[1f4fc80]885                skype_printf(ic, "GET CHAT %s STATUS\n", *i);
886                skype_printf(ic, "GET CHAT %s ACTIVEMEMBERS\n", *i);
[607f5e3]887                i++;
888        }
889        g_strfreev(chats);
890}
891
[ff436ba]892typedef void (*skype_parser)(struct im_connection *ic, char *line);
893
[8c09bb3]894static gboolean skype_read_callback(gpointer data, gint fd,
895                                    b_input_condition cond)
[1323e36]896{
897        struct im_connection *ic = data;
898        struct skype_data *sd = ic->proto_data;
[c213d6b]899        char buf[IRC_LINE_SIZE];
[ff436ba]900        int st, i;
[6e14204]901        char **lines, **lineptr, *line;
[ff436ba]902        static struct parse_map {
903                char *k;
904                skype_parser v;
905        } parsers[] = {
906                { "USERS ", skype_parse_users },
907                { "USER ", skype_parse_user },
908                { "CHATMESSAGE ", skype_parse_chatmessage },
909                { "CALL ", skype_parse_call },
910                { "FILETRANSFER ", skype_parse_filetransfer },
911                { "CHAT ", skype_parse_chat },
912                { "PASSWORD ", skype_parse_password },
913                { "PROFILE PSTN_BALANCE ", skype_parse_profile },
914                { "PING", skype_parse_ping },
915                { "CHATS ", skype_parse_chats },
916        };
[1323e36]917
[5adcc65]918        if (!sd || sd->fd == -1)
[1323e36]919                return FALSE;
[7daec06]920        /* Read the whole data. */
[5adcc65]921        st = ssl_read(sd->ssl, buf, sizeof(buf));
922        if (st > 0) {
[1323e36]923                buf[st] = '\0';
[7daec06]924                /* Then split it up to lines. */
[9fd4241]925                lines = g_strsplit(buf, "\n", 0);
926                lineptr = lines;
[5adcc65]927                while ((line = *lineptr)) {
928                        if (!strlen(line))
[9fd4241]929                                break;
[b820226]930                        if (set_getbool(&ic->acc->set, "skypeconsole_receive"))
931                                imcb_buddy_msg(ic, "skypeconsole", line, 0, 0);
[6b9d22a]932                        for (i = 0; i < ARRAY_SIZE(parsers); i++)
933                                if (!strncmp(line, parsers[i].k,
934                                        strlen(parsers[i].k))) {
[ff436ba]935                                        parsers[i].v(ic, line);
936                                        break;
937                                }
[9fd4241]938                        lineptr++;
939                }
940                g_strfreev(lines);
[5adcc65]941        } else if (st == 0 || (st < 0 && !sockerr_again())) {
942                closesocket(sd->fd);
[1323e36]943                sd->fd = -1;
944
[5adcc65]945                imcb_error(ic, "Error while reading from server");
946                imc_logout(ic, TRUE);
[1323e36]947                return FALSE;
948        }
949        return TRUE;
950}
951
[5adcc65]952gboolean skype_start_stream(struct im_connection *ic)
[f06e3ac]953{
[1323e36]954        struct skype_data *sd = ic->proto_data;
[f06e3ac]955        int st;
956
[5adcc65]957        if (!sd)
[1fb89e3]958                return FALSE;
959
[5adcc65]960        if (sd->bfd <= 0)
[7670b02]961                sd->bfd = b_input_add(sd->fd, B_EV_IO_READ,
[8c09bb3]962                        skype_read_callback, ic);
[1323e36]963
[a0b206b]964        /* Log in */
[1f4fc80]965        skype_printf(ic, "USERNAME %s\n", ic->acc->user);
966        skype_printf(ic, "PASSWORD %s\n", ic->acc->pass);
[a0b206b]967
[7daec06]968        /* This will download all buddies. */
[1f4fc80]969        st = skype_printf(ic, "SEARCH FRIENDS\n");
970        skype_printf(ic, "SET USERSTATUS ONLINE\n");
[5acf9ab]971
972        /* Auto join to bookmarked chats if requested.*/
[1f4fc80]973        if (set_getbool(&ic->acc->set, "auto_join"))
974                skype_printf(ic, "SEARCH BOOKMARKEDCHATS\n");
[f06e3ac]975        return st;
976}
977
[5adcc65]978gboolean skype_connected(gpointer data, void *source, b_input_condition cond)
[f06e3ac]979{
980        struct im_connection *ic = data;
[c7304b2]981        struct skype_data *sd = ic->proto_data;
[5adcc65]982        if (!source) {
[c7304b2]983                sd->ssl = NULL;
[5adcc65]984                imcb_error(ic, "Could not connect to server");
985                imc_logout(ic, TRUE);
[c7304b2]986                return FALSE;
987        }
[5adcc65]988        imcb_log(ic, "Connected to server, logging in");
[f06e3ac]989        return skype_start_stream(ic);
990}
991
[5adcc65]992static void skype_login(account_t *acc)
[f06e3ac]993{
[5adcc65]994        struct im_connection *ic = imcb_new(acc);
995        struct skype_data *sd = g_new0(struct skype_data, 1);
[f06e3ac]996
997        ic->proto_data = sd;
998
[5adcc65]999        imcb_log(ic, "Connecting");
[8c09bb3]1000        sd->ssl = ssl_connect(set_getstr(&acc->set, "server"),
1001                set_getint(&acc->set, "port"), skype_connected, ic);
[5adcc65]1002        sd->fd = sd->ssl ? ssl_getfd(sd->ssl) : -1;
1003        sd->username = g_strdup(acc->user);
[f06e3ac]1004
1005        sd->ic = ic;
[08a355b]1006
1007        if (set_getbool(&acc->set, "skypeconsole"))
1008                imcb_add_buddy(ic, "skypeconsole", NULL);
[f06e3ac]1009}
1010
[5adcc65]1011static void skype_logout(struct im_connection *ic)
[f06e3ac]1012{
1013        struct skype_data *sd = ic->proto_data;
[98bca36]1014
[1f4fc80]1015        skype_printf(ic, "SET USERSTATUS OFFLINE\n");
[98bca36]1016
[a3d6427]1017        g_free(sd->username);
[7613670]1018        g_free(sd->handle);
[f06e3ac]1019        g_free(sd);
[98bca36]1020        ic->proto_data = NULL;
[f06e3ac]1021}
1022
[8c09bb3]1023static int skype_buddy_msg(struct im_connection *ic, char *who, char *message,
1024                           int flags)
[93ece66]1025{
[1f4fc80]1026        char *ptr, *nick;
[93ece66]1027        int st;
1028
[cbec0d6]1029        nick = g_strdup(who);
[77c1abe]1030        ptr = strchr(nick, '@');
[5adcc65]1031        if (ptr)
[0bb1b7f]1032                *ptr = '\0';
[93ece66]1033
[08a355b]1034        if (!strncmp(who, "skypeconsole", 12))
[1f4fc80]1035                st = skype_printf(ic, "%s\n", message);
[08a355b]1036        else
[1f4fc80]1037                st = skype_printf(ic, "MESSAGE %s %s\n", nick, message);
[77c1abe]1038        g_free(nick);
[93ece66]1039
1040        return st;
1041}
1042
[5adcc65]1043const struct skype_away_state *skype_away_state_by_name(char *name)
[23411c6]1044{
1045        int i;
1046
[5adcc65]1047        for (i = 0; skype_away_state_list[i].full_name; i++)
1048                if (g_strcasecmp(skype_away_state_list[i].full_name, name) == 0)
1049                        return skype_away_state_list + i;
[23411c6]1050
1051        return NULL;
1052}
1053
[8c09bb3]1054static void skype_set_away(struct im_connection *ic, char *state_txt,
1055                           char *message)
[f06e3ac]1056{
[23411c6]1057        const struct skype_away_state *state;
1058
[4b740c2]1059        if (state_txt == NULL)
1060                state = skype_away_state_by_name("Online");
[23411c6]1061        else
[5adcc65]1062                state = skype_away_state_by_name(state_txt);
[1f4fc80]1063        skype_printf(ic, "SET USERSTATUS %s\n", state->code);
[f06e3ac]1064}
1065
[5adcc65]1066static GList *skype_away_states(struct im_connection *ic)
[f06e3ac]1067{
[5adcc65]1068        static GList *l;
[adce2de]1069        int i;
[5adcc65]1070
1071        if (l == NULL)
1072                for (i = 0; skype_away_state_list[i].full_name; i++)
[8c09bb3]1073                        l = g_list_append(l,
1074                                (void *)skype_away_state_list[i].full_name);
[5adcc65]1075
[f06e3ac]1076        return l;
1077}
1078
[5adcc65]1079static char *skype_set_display_name(set_t *set, char *value)
[93dffea]1080{
1081        account_t *acc = set->data;
1082        struct im_connection *ic = acc->ic;
1083
[1f4fc80]1084        skype_printf(ic, "SET PROFILE FULLNAME %s", value);
[5adcc65]1085        return value;
[93dffea]1086}
1087
[5adcc65]1088static char *skype_set_balance(set_t *set, char *value)
[2af671a]1089{
1090        account_t *acc = set->data;
1091        struct im_connection *ic = acc->ic;
1092
[1f4fc80]1093        skype_printf(ic, "GET PROFILE PSTN_BALANCE");
[5adcc65]1094        return value;
[2af671a]1095}
1096
[5adcc65]1097static char *skype_set_call(set_t *set, char *value)
[b68b023]1098{
1099        account_t *acc = set->data;
1100        struct im_connection *ic = acc->ic;
[2eb4b1f]1101        struct skype_data *sd = ic->proto_data;
[1f4fc80]1102        char *nick, *ptr;
[b68b023]1103
[5adcc65]1104        if (value) {
[78d22cd0]1105#if BITLBEE_VERSION_CODE < BITLBEE_VER(1, 3, 0)
1106                /* IRC stuff shouldn't be touched from inside IM modules. */
[2eb4b1f]1107                user_t *u = user_find(acc->irc, value);
1108                /* We are starting a call */
[78d22cd0]1109                if (u)
[a317ba6]1110                        nick = g_strdup(u->handle);
[78d22cd0]1111                else
1112#endif
1113                        nick = g_strdup(value);
[2eb4b1f]1114                ptr = strchr(nick, '@');
[5adcc65]1115                if (ptr)
[2eb4b1f]1116                        *ptr = '\0';
1117
[1f4fc80]1118                skype_printf(ic, "CALL %s", nick);
[2eb4b1f]1119                g_free(nick);
[5adcc65]1120        } else {
[2eb4b1f]1121                /* We are ending a call */
[5adcc65]1122                if (sd->call_id) {
[1f4fc80]1123                        skype_printf(ic, "SET CALL %s STATUS FINISHED",
[8c09bb3]1124                                sd->call_id);
[9fd7202]1125                        g_free(sd->call_id);
1126                        sd->call_id = NULL;
[5adcc65]1127                } else
[2eb4b1f]1128                        imcb_error(ic, "There are no active calls currently.");
[b68b023]1129        }
[5adcc65]1130        return value;
[b68b023]1131}
1132
[5adcc65]1133static void skype_add_buddy(struct im_connection *ic, char *who, char *group)
[f06e3ac]1134{
[1f4fc80]1135        char *nick, *ptr;
[6627d92]1136
[cbec0d6]1137        nick = g_strdup(who);
[6627d92]1138        ptr = strchr(nick, '@');
[5adcc65]1139        if (ptr)
[6627d92]1140                *ptr = '\0';
[1f4fc80]1141        skype_printf(ic, "SET USER %s BUDDYSTATUS 2 Please authorize me\n",
[8c09bb3]1142                nick);
[6627d92]1143        g_free(nick);
[f06e3ac]1144}
1145
[5adcc65]1146static void skype_remove_buddy(struct im_connection *ic, char *who, char *group)
[f06e3ac]1147{
[1f4fc80]1148        char *nick, *ptr;
[6627d92]1149
[cbec0d6]1150        nick = g_strdup(who);
[6627d92]1151        ptr = strchr(nick, '@');
[5adcc65]1152        if (ptr)
[6627d92]1153                *ptr = '\0';
[1f4fc80]1154        skype_printf(ic, "SET USER %s BUDDYSTATUS 1\n", nick);
[6627d92]1155        g_free(nick);
[f06e3ac]1156}
1157
[5adcc65]1158void skype_chat_msg(struct groupchat *gc, char *message, int flags)
[66c9558]1159{
[79e20f9]1160        struct im_connection *ic = gc->ic;
[1f4fc80]1161        skype_printf(ic, "CHATMESSAGE %s %s\n", gc->title, message);
[66c9558]1162}
1163
[5adcc65]1164void skype_chat_leave(struct groupchat *gc)
[b01dc6c]1165{
1166        struct im_connection *ic = gc->ic;
[1f4fc80]1167        skype_printf(ic, "ALTER CHAT %s LEAVE\n", gc->title);
[5adcc65]1168        gc->data = (void *)TRUE;
[760319d]1169}
1170
1171void skype_chat_invite(struct groupchat *gc, char *who, char *message)
1172{
1173        struct im_connection *ic = gc->ic;
[1f4fc80]1174        char *ptr, *nick;
[760319d]1175        nick = g_strdup(message);
1176        ptr = strchr(nick, '@');
[5adcc65]1177        if (ptr)
[760319d]1178                *ptr = '\0';
[1f4fc80]1179        skype_printf(ic, "ALTER CHAT %s ADDMEMBERS %s\n", gc->title, nick);
[760319d]1180        g_free(nick);
[b01dc6c]1181}
1182
[09e2a69]1183void skype_chat_topic(struct groupchat *gc, char *message)
1184{
1185        struct im_connection *ic = gc->ic;
[a5f76a2]1186        struct skype_data *sd = ic->proto_data;
[1f4fc80]1187        skype_printf(ic, "ALTER CHAT %s SETTOPIC %s\n",
[8c09bb3]1188                gc->title, message);
[a5f76a2]1189        sd->topic_wait = 1;
[09e2a69]1190}
1191
[86278cd]1192struct groupchat *skype_chat_with(struct im_connection *ic, char *who)
1193{
1194        struct skype_data *sd = ic->proto_data;
[1f4fc80]1195        char *ptr, *nick;
[86278cd]1196        nick = g_strdup(who);
1197        ptr = strchr(nick, '@');
[5adcc65]1198        if (ptr)
[86278cd]1199                *ptr = '\0';
[1f4fc80]1200        skype_printf(ic, "CHAT CREATE %s\n", nick);
[86278cd]1201        sd->groupchat_with = g_strdup(nick);
1202        g_free(nick);
[5652d43]1203        /* We create a fake chat for now. We will replace it with a real one in
1204         * the real callback. */
[5adcc65]1205        return imcb_chat_new(ic, "");
[86278cd]1206}
1207
[67454bd]1208static void skype_get_info(struct im_connection *ic, char *who)
1209{
[1f4fc80]1210        char *ptr, *nick;
[67454bd]1211        nick = g_strdup(who);
1212        ptr = strchr(nick, '@');
[5adcc65]1213        if (ptr)
[67454bd]1214                *ptr = '\0';
[1f4fc80]1215        skype_printf(ic, "GET USER %s FULLNAME\n", nick);
1216        skype_printf(ic, "GET USER %s PHONE_HOME\n", nick);
1217        skype_printf(ic, "GET USER %s PHONE_OFFICE\n", nick);
1218        skype_printf(ic, "GET USER %s PHONE_MOBILE\n", nick);
1219        skype_printf(ic, "GET USER %s NROF_AUTHED_BUDDIES\n", nick);
1220        skype_printf(ic, "GET USER %s TIMEZONE\n", nick);
1221        skype_printf(ic, "GET USER %s LASTONLINETIMESTAMP\n", nick);
1222        skype_printf(ic, "GET USER %s BIRTHDAY\n", nick);
1223        skype_printf(ic, "GET USER %s SEX\n", nick);
1224        skype_printf(ic, "GET USER %s LANGUAGE\n", nick);
1225        skype_printf(ic, "GET USER %s COUNTRY\n", nick);
1226        skype_printf(ic, "GET USER %s PROVINCE\n", nick);
1227        skype_printf(ic, "GET USER %s CITY\n", nick);
1228        skype_printf(ic, "GET USER %s HOMEPAGE\n", nick);
1229        skype_printf(ic, "GET USER %s ABOUT\n", nick);
[67454bd]1230}
1231
[5adcc65]1232static void skype_set_my_name(struct im_connection *ic, char *info)
[93dffea]1233{
[5adcc65]1234        skype_set_display_name(set_find(&ic->acc->set, "display_name"), info);
[93dffea]1235}
1236
[5adcc65]1237static void skype_init(account_t *acc)
[93dffea]1238{
1239        set_t *s;
1240
[8c09bb3]1241        s = set_add(&acc->set, "server", SKYPE_DEFAULT_SERVER, set_eval_account,
1242                acc);
[93dffea]1243        s->flags |= ACC_SET_OFFLINE_ONLY;
1244
[5adcc65]1245        s = set_add(&acc->set, "port", SKYPE_DEFAULT_PORT, set_eval_int, acc);
[93dffea]1246        s->flags |= ACC_SET_OFFLINE_ONLY;
1247
[8c09bb3]1248        s = set_add(&acc->set, "display_name", NULL, skype_set_display_name,
1249                acc);
[93dffea]1250        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
[b68b023]1251
[5adcc65]1252        s = set_add(&acc->set, "call", NULL, skype_set_call, acc);
[b68b023]1253        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
[2af671a]1254
[5adcc65]1255        s = set_add(&acc->set, "balance", NULL, skype_set_balance, acc);
[2af671a]1256        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
[bd417a1]1257
[5adcc65]1258        s = set_add(&acc->set, "skypeout_offline", "true", set_eval_bool, acc);
[08a355b]1259
[5adcc65]1260        s = set_add(&acc->set, "skypeconsole", "false", set_eval_bool, acc);
[08a355b]1261        s->flags |= ACC_SET_OFFLINE_ONLY;
[5acf9ab]1262
[8c09bb3]1263        s = set_add(&acc->set, "skypeconsole_receive", "false", set_eval_bool,
1264                acc);
[b820226]1265        s->flags |= ACC_SET_OFFLINE_ONLY;
1266
[5adcc65]1267        s = set_add(&acc->set, "auto_join", "false", set_eval_bool, acc);
[5acf9ab]1268        s->flags |= ACC_SET_OFFLINE_ONLY;
[f4d37c6]1269
[49a3c02]1270        s = set_add(&acc->set, "test_join", "false", set_eval_bool, acc);
1271        s->flags |= ACC_SET_OFFLINE_ONLY;
1272
[304aa33]1273        s = set_add(&acc->set, "show_moods", "false", set_eval_bool, acc);
1274
[f4d37c6]1275        s = set_add(&acc->set, "edit_prefix", "EDIT:",
[1e3120f]1276                        NULL, acc);
[93dffea]1277}
1278
[f06e3ac]1279void init_plugin(void)
1280{
[5adcc65]1281        struct prpl *ret = g_new0(struct prpl, 1);
[f06e3ac]1282
1283        ret->name = "skype";
1284        ret->login = skype_login;
1285        ret->init = skype_init;
1286        ret->logout = skype_logout;
[93ece66]1287        ret->buddy_msg = skype_buddy_msg;
[67454bd]1288        ret->get_info = skype_get_info;
[93dffea]1289        ret->set_my_name = skype_set_my_name;
[f06e3ac]1290        ret->away_states = skype_away_states;
[7daec06]1291        ret->set_away = skype_set_away;
[f06e3ac]1292        ret->add_buddy = skype_add_buddy;
1293        ret->remove_buddy = skype_remove_buddy;
[66c9558]1294        ret->chat_msg = skype_chat_msg;
[b01dc6c]1295        ret->chat_leave = skype_chat_leave;
[760319d]1296        ret->chat_invite = skype_chat_invite;
[86278cd]1297        ret->chat_with = skype_chat_with;
[f06e3ac]1298        ret->handle_cmp = g_strcasecmp;
[09e2a69]1299        ret->chat_topic = skype_chat_topic;
[5adcc65]1300        register_protocol(ret);
[f06e3ac]1301}
Note: See TracBrowser for help on using the repository browser.