4 * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
37 #include <sys/socket.h>
45 extern char *yahoo_crypt(char *, char *);
47 #include "pixmaps/status-away.xpm"
48 #include "pixmaps/status-here.xpm"
49 #include "pixmaps/status-idle.xpm"
50 #include "pixmaps/status-game.xpm"
52 /* Yahoo Smilies go here */
53 #include "pixmaps/protocols/yahoo/yahoo_alien.xpm"
54 #include "pixmaps/protocols/yahoo/yahoo_angel.xpm"
55 #include "pixmaps/protocols/yahoo/yahoo_angry.xpm"
56 #include "pixmaps/protocols/yahoo/yahoo_bigsmile.xpm"
57 #include "pixmaps/protocols/yahoo/yahoo_blush.xpm"
58 #include "pixmaps/protocols/yahoo/yahoo_bye.xpm"
59 #include "pixmaps/protocols/yahoo/yahoo_clown.xpm"
60 #include "pixmaps/protocols/yahoo/yahoo_cow.xpm"
61 #include "pixmaps/protocols/yahoo/yahoo_cowboy.xpm"
62 #include "pixmaps/protocols/yahoo/yahoo_cry.xpm"
63 #include "pixmaps/protocols/yahoo/yahoo_devil.xpm"
64 #include "pixmaps/protocols/yahoo/yahoo_flower.xpm"
65 #include "pixmaps/protocols/yahoo/yahoo_ghost.xpm"
66 #include "pixmaps/protocols/yahoo/yahoo_glasses.xpm"
67 #include "pixmaps/protocols/yahoo/yahoo_laughloud.xpm"
68 #include "pixmaps/protocols/yahoo/yahoo_love.xpm"
69 #include "pixmaps/protocols/yahoo/yahoo_mean.xpm"
70 #include "pixmaps/protocols/yahoo/yahoo_neutral.xpm"
71 #include "pixmaps/protocols/yahoo/yahoo_ooooh.xpm"
72 #include "pixmaps/protocols/yahoo/yahoo_question.xpm"
73 #include "pixmaps/protocols/yahoo/yahoo_sad.xpm"
74 #include "pixmaps/protocols/yahoo/yahoo_sleep.xpm"
75 #include "pixmaps/protocols/yahoo/yahoo_smiley.xpm"
76 #include "pixmaps/protocols/yahoo/yahoo_sunglas.xpm"
77 #include "pixmaps/protocols/yahoo/yahoo_tongue.xpm"
78 #include "pixmaps/protocols/yahoo/yahoo_wink.xpm"
82 #define USEROPT_MAIL 0
84 #define USEROPT_PAGERHOST 3
85 #define YAHOO_PAGER_HOST "cs.yahoo.com"
86 #define USEROPT_PAGERPORT 4
87 #define YAHOO_PAGER_PORT 5050
89 enum yahoo_service
{ /* these are easier to see in hex */
90 YAHOO_SERVICE_LOGON
= 1,
94 YAHOO_SERVICE_IDLE
, /* 5 (placemarker) */
95 YAHOO_SERVICE_MESSAGE
,
97 YAHOO_SERVICE_IDDEACT
,
98 YAHOO_SERVICE_MAILSTAT
,
99 YAHOO_SERVICE_USERSTAT
, /* 0xa */
100 YAHOO_SERVICE_NEWMAIL
,
101 YAHOO_SERVICE_CHATINVITE
,
102 YAHOO_SERVICE_CALENDAR
,
103 YAHOO_SERVICE_NEWPERSONALMAIL
,
104 YAHOO_SERVICE_NEWCONTACT
,
105 YAHOO_SERVICE_ADDIDENT
, /* 0x10 */
106 YAHOO_SERVICE_ADDIGNORE
,
108 YAHOO_SERVICE_GROUPRENAME
,
109 YAHOO_SERVICE_SYSMESSAGE
= 0x14,
110 YAHOO_SERVICE_PASSTHROUGH2
= 0x16,
111 YAHOO_SERVICE_CONFINVITE
= 0x18,
112 YAHOO_SERVICE_CONFLOGON
,
113 YAHOO_SERVICE_CONFDECLINE
,
114 YAHOO_SERVICE_CONFLOGOFF
,
115 YAHOO_SERVICE_CONFADDINVITE
,
116 YAHOO_SERVICE_CONFMSG
,
117 YAHOO_SERVICE_CHATLOGON
,
118 YAHOO_SERVICE_CHATLOGOFF
,
119 YAHOO_SERVICE_CHATMSG
= 0x20,
120 YAHOO_SERVICE_GAMELOGON
= 0x28,
121 YAHOO_SERVICE_GAMELOGOFF
,
122 YAHOO_SERVICE_GAMEMSG
= 0x2a,
123 YAHOO_SERVICE_FILETRANSFER
= 0x46,
124 YAHOO_SERVICE_NOTIFY
= 0x4B,
125 YAHOO_SERVICE_LIST
= 0x55,
126 YAHOO_SERVICE_ADDBUDDY
= 0x83,
127 YAHOO_SERVICE_REMBUDDY
= 0x84
131 YAHOO_STATUS_AVAILABLE
= 0,
134 YAHOO_STATUS_NOTATHOME
,
135 YAHOO_STATUS_NOTATDESK
,
136 YAHOO_STATUS_NOTINOFFICE
,
137 YAHOO_STATUS_ONPHONE
,
138 YAHOO_STATUS_ONVACATION
,
139 YAHOO_STATUS_OUTTOLUNCH
,
140 YAHOO_STATUS_STEPPEDOUT
,
141 YAHOO_STATUS_INVISIBLE
= 12,
142 YAHOO_STATUS_CUSTOM
= 99,
143 YAHOO_STATUS_IDLE
= 999,
144 YAHOO_STATUS_OFFLINE
= 0x5a55aa56, /* don't ask */
145 YAHOO_STATUS_TYPING
= 0x16
147 #define YAHOO_STATUS_GAME 0x2 /* Games don't fit into the regular status model */
164 struct yahoo_packet
{
171 static char *yahoo_name() {
175 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
177 static struct yahoo_packet
*yahoo_packet_new(enum yahoo_service service
, enum yahoo_status status
, int id
)
179 struct yahoo_packet
*pkt
= g_new0(struct yahoo_packet
, 1);
181 pkt
->service
= service
;
182 pkt
->status
= status
;
188 static void yahoo_packet_hash(struct yahoo_packet
*pkt
, int key
, char *value
)
190 struct yahoo_pair
*pair
= g_new0(struct yahoo_pair
, 1);
192 pair
->value
= g_strdup(value
);
193 pkt
->hash
= g_slist_append(pkt
->hash
, pair
);
196 static int yahoo_packet_length(struct yahoo_packet
*pkt
)
204 struct yahoo_pair
*pair
= l
->data
;
211 len
+= strlen(pair
->value
);
219 /* sometimes i wish prpls could #include things from other prpls. then i could just
220 * use the routines from libfaim and not have to admit to knowing how they work. */
221 #define yahoo_put16(buf, data) ( \
222 (*(buf) = (u_char)((data)>>8)&0xff), \
223 (*((buf)+1) = (u_char)(data)&0xff), \
225 #define yahoo_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
226 #define yahoo_put32(buf, data) ( \
227 (*((buf)) = (u_char)((data)>>24)&0xff), \
228 (*((buf)+1) = (u_char)((data)>>16)&0xff), \
229 (*((buf)+2) = (u_char)((data)>>8)&0xff), \
230 (*((buf)+3) = (u_char)(data)&0xff), \
232 #define yahoo_get32(buf) ((((*(buf))<<24)&0xff000000) + \
233 (((*((buf)+1))<<16)&0x00ff0000) + \
234 (((*((buf)+2))<< 8)&0x0000ff00) + \
235 (((*((buf)+3) )&0x000000ff)))
237 static void yahoo_packet_read(struct yahoo_packet
*pkt
, guchar
*data
, int len
)
241 while (pos
+ 1 < len
) {
242 char key
[64], *value
= NULL
;
246 struct yahoo_pair
*pair
= g_new0(struct yahoo_pair
, 1);
249 while (pos
+ 1 < len
) {
250 if (data
[pos
] == 0xc0 && data
[pos
+ 1] == 0x80)
252 key
[x
++] = data
[pos
++];
256 pair
->key
= strtol(key
, NULL
, 10);
257 accept
= x
; /* if x is 0 there was no key, so don't accept it */
260 value
= g_malloc(len
- pos
+ 1);
262 while (pos
+ 1 < len
) {
263 if (data
[pos
] == 0xc0 && data
[pos
+ 1] == 0x80)
266 value
[x
++] = data
[pos
++];
272 pair
->value
= g_strdup(value
);
274 pkt
->hash
= g_slist_append(pkt
->hash
, pair
);
275 debug_printf("Key: %d \tValue: %s\n", pair
->key
, pair
->value
);
282 static void yahoo_packet_write(struct yahoo_packet
*pkt
, guchar
*data
)
284 GSList
*l
= pkt
->hash
;
288 struct yahoo_pair
*pair
= l
->data
;
291 g_snprintf(buf
, sizeof(buf
), "%d", pair
->key
);
292 strcpy(data
+ pos
, buf
);
297 strcpy(data
+ pos
, pair
->value
);
298 pos
+= strlen(pair
->value
);
306 static void yahoo_packet_dump(guchar
*data
, int len
)
310 for (i
= 0; i
+ 1 < len
; i
+= 2) {
311 if ((i
% 16 == 0) && i
)
313 debug_printf("%02x", data
[i
]);
314 debug_printf("%02x ", data
[i
+1]);
317 debug_printf("%02x", data
[i
]);
319 for (i
= 0; i
< len
; i
++) {
320 if ((i
% 16 == 0) && i
)
322 if (isprint(data
[i
]))
323 debug_printf("%c ", data
[i
]);
331 static int yahoo_send_packet(struct yahoo_data
*yd
, struct yahoo_packet
*pkt
)
333 int pktlen
= yahoo_packet_length(pkt
);
334 int len
= YAHOO_PACKET_HDRLEN
+ pktlen
;
343 data
= g_malloc0(len
+ 1);
345 memcpy(data
+ pos
, "YMSG", 4); pos
+= 4;
346 pos
+= yahoo_put16(data
+ pos
, 0x0600);
347 pos
+= yahoo_put16(data
+ pos
, 0x0000);
348 pos
+= yahoo_put16(data
+ pos
, pktlen
);
349 pos
+= yahoo_put16(data
+ pos
, pkt
->service
);
350 pos
+= yahoo_put32(data
+ pos
, pkt
->status
);
351 pos
+= yahoo_put32(data
+ pos
, pkt
->id
);
353 yahoo_packet_write(pkt
, data
+ pos
);
355 yahoo_packet_dump(data
, len
);
356 ret
= write(yd
->fd
, data
, len
);
363 static void yahoo_packet_free(struct yahoo_packet
*pkt
)
366 struct yahoo_pair
*pair
= pkt
->hash
->data
;
369 pkt
->hash
= g_slist_remove(pkt
->hash
, pair
);
374 static void yahoo_process_status(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
376 struct yahoo_data
*yd
= gc
->proto_data
;
377 GSList
*l
= pkt
->hash
;
378 struct yahoo_packet
*newpkt
;
385 struct yahoo_pair
*pair
= l
->data
;
388 case 0: /* we won't actually do anything with this */
390 case 1: /* we don't get the full buddy list here. */
391 if (!yd
->logged_in
) {
393 serv_finish_login(gc
);
394 g_snprintf(gc
->displayname
, sizeof(gc
->displayname
), "%s", pair
->value
);
396 yd
->logged_in
= TRUE
;
398 /* this requests the list. i have a feeling that this is very evil */
399 newpkt
= yahoo_packet_new(YAHOO_SERVICE_LIST
, YAHOO_STATUS_OFFLINE
, 0);
400 yahoo_send_packet(yd
, newpkt
);
401 yahoo_packet_free(newpkt
);
404 case 8: /* how many online buddies we have */
406 case 7: /* the current buddy */
410 state
= strtol(pair
->value
, NULL
, 10);
412 case 19: /* custom message */
415 case 11: /* i didn't know what this was in the old protocol either */
417 case 17: /* in chat? */
419 case 13: /* in pager? */
420 if (pkt
->service
== YAHOO_SERVICE_LOGOFF
||
421 strtol(pair
->value
, NULL
, 10) == 0) {
422 serv_got_update(gc
, name
, 0, 0, 0, 0, 0, 0);
425 if (g_hash_table_lookup(yd
->games
, name
))
426 gamestate
= YAHOO_STATUS_GAME
;
427 if (state
== YAHOO_STATUS_AVAILABLE
)
428 serv_got_update(gc
, name
, 1, 0, 0, 0, gamestate
, 0);
430 serv_got_update(gc
, name
, 1, 0, 0, 0, (state
<< 2) | UC_UNAVAILABLE
| gamestate
, 0);
431 if (state
== YAHOO_STATUS_CUSTOM
) {
432 gpointer val
= g_hash_table_lookup(yd
->hash
, name
);
435 g_hash_table_insert(yd
->hash
, name
,
436 msg
? g_strdup(msg
) : g_malloc0(1));
438 g_hash_table_insert(yd
->hash
, g_strdup(name
),
439 msg
? g_strdup(msg
) : g_malloc0(1));
442 case 60: /* no clue */
444 case 16: /* Custom error message */
445 do_error_dialog(pair
->value
, "Gaim -- Yahoo! Error");
448 debug_printf("unknown status key %d\n", pair
->key
);
456 static void yahoo_process_list(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
458 GSList
*l
= pkt
->hash
;
459 gboolean export
= FALSE
;
467 struct yahoo_pair
*pair
= l
->data
;
473 lines
= g_strsplit(pair
->value
, "\n", -1);
474 for (tmp
= lines
; *tmp
; tmp
++) {
475 split
= g_strsplit(*tmp
, ":", 2);
478 if (!split
[0] || !split
[1]) {
482 buddies
= g_strsplit(split
[1], ",", -1);
483 for (bud
= buddies
; bud
&& *bud
; bud
++)
484 if (!find_buddy(gc
, *bud
)) {
485 add_buddy(gc
, split
[0], *bud
, *bud
);
498 static void yahoo_process_notify(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
504 GSList
*l
= pkt
->hash
;
505 struct yahoo_data
*yd
= (struct yahoo_data
*) gc
->proto_data
;
507 struct yahoo_pair
*pair
= l
->data
;
519 if (!g_strncasecmp(msg
, "TYPING", strlen("TYPING"))) {
521 serv_got_typing(gc
, from
, 0);
523 serv_got_typing_stopped(gc
, from
);
524 } else if (!g_strncasecmp(msg
, "GAME", strlen("GAME"))) {
525 struct buddy
*bud
= find_buddy(gc
, from
);
526 void *free1
=NULL
, *free2
=NULL
;
528 debug_printf("%s is playing a game, and doesn't want you to know.\n");
530 if (g_hash_table_lookup_extended (yd
->games
, from
, free1
, free2
)) {
534 g_hash_table_insert (yd
->games
, g_strdup(from
), g_strdup(game
));
536 serv_got_update(gc
, from
, 1, 0, 0, 0, bud
->uc
| YAHOO_STATUS_GAME
, 0);
538 if (g_hash_table_lookup_extended (yd
->games
, from
, free1
, free2
)) {
541 g_hash_table_remove (yd
->games
, from
);
544 serv_got_update(gc
, from
, 1, 0, 0, 0, bud
->uc
& ~YAHOO_STATUS_GAME
, 0);
549 static void yahoo_process_message(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
553 time_t tm
= time(NULL
);
554 GSList
*l
= pkt
->hash
;
557 struct yahoo_pair
*pair
= l
->data
;
563 tm
= strtol(pair
->value
, NULL
, 10);
567 if (pkt
->status
<= 1 || pkt
->status
== 5) {
572 for (i
= 0, j
= 0; m
[i
]; i
++) {
574 while (m
[i
] && (m
[i
] != 'm'))
583 serv_got_im(gc
, from
, msg
, 0, tm
, -1);
584 } else if (pkt
->status
== 2) {
585 do_error_dialog(_("Your message did not get sent."), _("Gaim - Error"));
590 static void yahoo_process_contact(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
592 struct yahoo_data
*yd
= gc
->proto_data
;
597 int state
= YAHOO_STATUS_AVAILABLE
;
600 GSList
*l
= pkt
->hash
;
603 struct yahoo_pair
*pair
= l
->data
;
606 else if (pair
->key
== 3)
608 else if (pair
->key
== 14)
610 else if (pair
->key
== 7)
612 else if (pair
->key
== 10)
613 state
= strtol(pair
->value
, NULL
, 10);
614 else if (pair
->key
== 13)
615 online
= strtol(pair
->value
, NULL
, 10);
620 show_got_added(gc
, id
, who
, NULL
, msg
);
622 if (state
== YAHOO_STATUS_AVAILABLE
)
623 serv_got_update(gc
, name
, 1, 0, 0, 0, 0, 0);
624 else if (state
== YAHOO_STATUS_IDLE
)
625 serv_got_update(gc
, name
, 1, 0, 0, time(NULL
) - 600, (state
<< 2), 0);
627 serv_got_update(gc
, name
, 1, 0, 0, 0, (state
<< 2) | UC_UNAVAILABLE
, 0);
628 if (state
== YAHOO_STATUS_CUSTOM
) {
629 gpointer val
= g_hash_table_lookup(yd
->hash
, name
);
632 g_hash_table_insert(yd
->hash
, name
,
633 msg
? g_strdup(msg
) : g_malloc0(1));
635 g_hash_table_insert(yd
->hash
, g_strdup(name
),
636 msg
? g_strdup(msg
) : g_malloc0(1));
641 static void yahoo_process_mail(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
647 GSList
*l
= pkt
->hash
;
650 struct yahoo_pair
*pair
= l
->data
;
652 count
= strtol(pair
->value
, NULL
, 10);
653 else if (pair
->key
== 43)
655 else if (pair
->key
== 42)
657 else if (pair
->key
== 18)
662 if (who
&& email
&& subj
) {
663 char *from
= g_strdup_printf("%s (%s)", who
, email
);
664 connection_has_mail(gc
, -1, from
, subj
, "http://mail.yahoo.com/");
667 connection_has_mail(gc
, count
, NULL
, NULL
, "http://mail.yahoo.com/");
670 static void yahoo_packet_process(struct gaim_connection
*gc
, struct yahoo_packet
*pkt
)
672 switch (pkt
->service
)
674 case YAHOO_SERVICE_LOGON
:
675 case YAHOO_SERVICE_LOGOFF
:
676 case YAHOO_SERVICE_ISAWAY
:
677 case YAHOO_SERVICE_ISBACK
:
678 case YAHOO_SERVICE_GAMELOGON
:
679 case YAHOO_SERVICE_GAMELOGOFF
:
680 yahoo_process_status(gc
, pkt
);
682 case YAHOO_SERVICE_NOTIFY
:
683 yahoo_process_notify(gc
, pkt
);
685 case YAHOO_SERVICE_MESSAGE
:
686 case YAHOO_SERVICE_GAMEMSG
:
687 yahoo_process_message(gc
, pkt
);
689 case YAHOO_SERVICE_NEWMAIL
:
690 yahoo_process_mail(gc
, pkt
);
692 case YAHOO_SERVICE_NEWCONTACT
:
693 yahoo_process_contact(gc
, pkt
);
695 case YAHOO_SERVICE_LIST
:
696 yahoo_process_list(gc
, pkt
);
699 debug_printf("unhandled service 0x%02x\n", pkt
->service
);
704 static void yahoo_pending(gpointer data
, gint source
, GaimInputCondition cond
)
706 struct gaim_connection
*gc
= data
;
707 struct yahoo_data
*yd
= gc
->proto_data
;
711 len
= read(yd
->fd
, buf
, sizeof(buf
));
714 hide_login_progress(gc
, "Unable to read");
719 yd
->rxqueue
= g_realloc(yd
->rxqueue
, len
+ yd
->rxlen
);
720 memcpy(yd
->rxqueue
+ yd
->rxlen
, buf
, len
);
724 struct yahoo_packet
*pkt
;
728 if (yd
->rxlen
< YAHOO_PACKET_HDRLEN
)
735 pktlen
= yahoo_get16(yd
->rxqueue
+ pos
); pos
+= 2;
736 debug_printf("%d bytes to read, rxlen is %d\n", pktlen
, yd
->rxlen
);
738 if (yd
->rxlen
< (YAHOO_PACKET_HDRLEN
+ pktlen
))
741 yahoo_packet_dump(yd
->rxqueue
, YAHOO_PACKET_HDRLEN
+ pktlen
);
743 pkt
= yahoo_packet_new(0, 0, 0);
745 pkt
->service
= yahoo_get16(yd
->rxqueue
+ pos
); pos
+= 2;
746 pkt
->status
= yahoo_get32(yd
->rxqueue
+ pos
); pos
+= 4;
747 debug_printf("Yahoo Service: 0x%02x Status: %d\n", pkt
->service
, pkt
->status
);
748 pkt
->id
= yahoo_get32(yd
->rxqueue
+ pos
); pos
+= 4;
750 yahoo_packet_read(pkt
, yd
->rxqueue
+ pos
, pktlen
);
752 yd
->rxlen
-= YAHOO_PACKET_HDRLEN
+ pktlen
;
754 char *tmp
= g_memdup(yd
->rxqueue
+ YAHOO_PACKET_HDRLEN
+ pktlen
, yd
->rxlen
);
762 yahoo_packet_process(gc
, pkt
);
764 yahoo_packet_free(pkt
);
768 static void yahoo_got_connected(gpointer data
, gint source
, GaimInputCondition cond
)
770 struct gaim_connection
*gc
= data
;
771 struct yahoo_data
*yd
;
772 struct yahoo_packet
*pkt
;
774 if (!g_slist_find(connections
, gc
)) {
780 hide_login_progress(gc
, "Unable to connect");
788 pkt
= yahoo_packet_new(YAHOO_SERVICE_LOGON
, YAHOO_STATUS_AVAILABLE
, 0);
790 yahoo_packet_hash(pkt
, 0, gc
->username
);
791 yahoo_packet_hash(pkt
, 1, gc
->username
);
792 yahoo_packet_hash(pkt
, 6, yahoo_crypt(gc
->password
, "$1$_2S43d5f$"));
794 yahoo_send_packet(yd
, pkt
);
796 yahoo_packet_free(pkt
);
798 gc
->inpa
= gaim_input_add(yd
->fd
, GAIM_INPUT_READ
, yahoo_pending
, gc
);
801 static void yahoo_login(struct aim_user
*user
) {
802 struct gaim_connection
*gc
= new_gaim_conn(user
);
803 struct yahoo_data
*yd
= gc
->proto_data
= g_new0(struct yahoo_data
, 1);
805 set_login_progress(gc
, 1, "Connecting");
808 yd
->hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
809 yd
->games
= g_hash_table_new(g_str_hash
, g_str_equal
);
811 if (!g_strncasecmp(user
->proto_opt
[USEROPT_PAGERHOST
], "scs.yahoo.com", strlen("scs.yahoo.com"))) {
812 /* As of this morning, Yahoo is no longer supporting its server at scs.yahoo.com
813 * I don't like to edit the preferences in a prpl, but we'll keep this here
814 * for a while until everybody's happy again. -5 Feb 2002*/
815 debug_printf("Setting new Yahoo! server.\n");
816 g_snprintf(user
->proto_opt
[USEROPT_PAGERHOST
], strlen("cs.yahoo.com") + 1, "cs.yahoo.com");
820 if (proxy_connect(user
->proto_opt
[USEROPT_PAGERHOST
][0] ?
821 user
->proto_opt
[USEROPT_PAGERHOST
] : YAHOO_PAGER_HOST
,
822 user
->proto_opt
[USEROPT_PAGERPORT
][0] ?
823 atoi(user
->proto_opt
[USEROPT_PAGERPORT
]) : YAHOO_PAGER_PORT
,
824 yahoo_got_connected
, gc
) < 0) {
825 hide_login_progress(gc
, "Connection problem");
832 static gboolean
yahoo_destroy_hash(gpointer key
, gpointer val
, gpointer data
)
839 static void yahoo_close(struct gaim_connection
*gc
) {
840 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
841 g_hash_table_foreach_remove(yd
->hash
, yahoo_destroy_hash
, NULL
);
842 g_hash_table_destroy(yd
->hash
);
843 g_hash_table_foreach_remove(yd
->games
, yahoo_destroy_hash
, NULL
);
844 g_hash_table_destroy(yd
->games
);
851 gaim_input_remove(gc
->inpa
);
855 static char **yahoo_list_icon(int uc
)
857 if ((uc
>> 2) == YAHOO_STATUS_IDLE
)
858 return status_idle_xpm
;
859 else if (uc
& UC_UNAVAILABLE
)
860 return status_away_xpm
;
861 else if (uc
& YAHOO_STATUS_GAME
)
862 return status_game_xpm
;
863 return status_here_xpm
;
866 static char *yahoo_get_status_string(enum yahoo_status a
)
869 case YAHOO_STATUS_BRB
:
870 return "Be Right Back";
871 case YAHOO_STATUS_BUSY
:
873 case YAHOO_STATUS_NOTATHOME
:
874 return "Not At Home";
875 case YAHOO_STATUS_NOTATDESK
:
876 return "Not At Desk";
877 case YAHOO_STATUS_NOTINOFFICE
:
878 return "Not In Office";
879 case YAHOO_STATUS_ONPHONE
:
881 case YAHOO_STATUS_ONVACATION
:
882 return "On Vacation";
883 case YAHOO_STATUS_OUTTOLUNCH
:
884 return "Out To Lunch";
885 case YAHOO_STATUS_STEPPEDOUT
:
886 return "Stepped Out";
887 case YAHOO_STATUS_INVISIBLE
:
894 static void yahoo_game(struct gaim_connection
*gc
, char *name
) {
895 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
896 char *game
= g_hash_table_lookup(yd
->games
, name
);
902 t
= game
= g_strdup(strstr(game
, "ante?room="));
906 g_snprintf(url
, sizeof url
, "http://games.yahoo.com/games/%s", game
);
910 static GList
*yahoo_buddy_menu(struct gaim_connection
*gc
, char *who
)
913 struct proto_buddy_menu
*pbm
;
914 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
915 struct buddy
*b
= find_buddy(gc
, who
); /* this should never be null. if it is,
916 segfault and get the bug report. */
917 static char buf
[1024];
918 static char buf2
[1024];
920 if (b
->uc
& UC_UNAVAILABLE
&& b
->uc
>> 2 != YAHOO_STATUS_IDLE
) {
921 pbm
= g_new0(struct proto_buddy_menu
, 1);
922 if ((b
->uc
>> 2) != YAHOO_STATUS_CUSTOM
)
923 g_snprintf(buf
, sizeof buf
,
924 "Status: %s", yahoo_get_status_string(b
->uc
>> 2));
926 g_snprintf(buf
, sizeof buf
, "Custom Status: %s",
927 (char *)g_hash_table_lookup(yd
->hash
, b
->name
));
929 pbm
->callback
= NULL
;
931 m
= g_list_append(m
, pbm
);
934 if (b
->uc
| YAHOO_STATUS_GAME
) {
935 char *game
= g_hash_table_lookup(yd
->games
, b
->name
);
941 pbm
= g_new0(struct proto_buddy_menu
, 1);
942 if (!(room
= strstr(game
, "&follow="))) /* skip ahead to the url */
944 while (*room
&& *room
!= '\t') /* skip to the tab */
946 t
= room
++; /* room as now at the name */
948 t
++; /* replace the \n with a space */
950 g_snprintf(buf2
, sizeof buf2
, "%s", room
);
952 pbm
->callback
= yahoo_game
;
954 m
= g_list_append(m
, pbm
);
961 static GList
*yahoo_user_opts()
964 struct proto_user_opt
*puo
;
966 puo
= g_new0(struct proto_user_opt
, 1);
967 puo
->label
= "Pager Host:";
968 puo
->def
= YAHOO_PAGER_HOST
;
969 puo
->pos
= USEROPT_PAGERHOST
;
970 m
= g_list_append(m
, puo
);
972 puo
= g_new0(struct proto_user_opt
, 1);
973 puo
->label
= "Pager Port:";
975 puo
->pos
= USEROPT_PAGERPORT
;
976 m
= g_list_append(m
, puo
);
981 static void yahoo_act_id(gpointer data
, char *entry
)
983 struct gaim_connection
*gc
= data
;
984 struct yahoo_data
*yd
= gc
->proto_data
;
986 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_IDACT
, YAHOO_STATUS_AVAILABLE
, 0);
987 yahoo_packet_hash(pkt
, 3, entry
);
988 yahoo_send_packet(yd
, pkt
);
989 yahoo_packet_free(pkt
);
991 g_snprintf(gc
->displayname
, sizeof(gc
->displayname
), "%s", entry
);
994 static void yahoo_do_action(struct gaim_connection
*gc
, char *act
)
996 if (!strcmp(act
, "Activate ID")) {
997 do_prompt_dialog("Activate which ID:", gc
->displayname
, gc
, yahoo_act_id
, NULL
);
1001 static GList
*yahoo_actions() {
1004 m
= g_list_append(m
, "Activate ID");
1009 static int yahoo_send_im(struct gaim_connection
*gc
, char *who
, char *what
, int len
, int flags
)
1011 struct yahoo_data
*yd
= gc
->proto_data
;
1012 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_MESSAGE
, YAHOO_STATUS_OFFLINE
, 0);
1014 yahoo_packet_hash(pkt
, 1, gc
->displayname
);
1015 yahoo_packet_hash(pkt
, 5, who
);
1016 yahoo_packet_hash(pkt
, 14, what
);
1018 yahoo_send_packet(yd
, pkt
);
1020 yahoo_packet_free(pkt
);
1025 int yahoo_send_typing(struct gaim_connection
*gc
, char *who
, int typ
)
1027 struct yahoo_data
*yd
= gc
->proto_data
;
1028 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_NOTIFY
, YAHOO_STATUS_TYPING
, 0);
1029 yahoo_packet_hash(pkt
, 49, "TYPING");
1030 yahoo_packet_hash(pkt
, 1, gc
->displayname
);
1031 yahoo_packet_hash(pkt
, 14, " ");
1032 yahoo_packet_hash(pkt
, 13, typ
? "1" : "0");
1033 yahoo_packet_hash(pkt
, 5, who
);
1034 yahoo_packet_hash(pkt
, 1002, "1");
1036 yahoo_send_packet(yd
, pkt
);
1038 yahoo_packet_free(pkt
);
1043 static void yahoo_set_away(struct gaim_connection
*gc
, char *state
, char *msg
)
1045 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
1046 struct yahoo_packet
*pkt
;
1053 yd
->current_status
= YAHOO_STATUS_CUSTOM
;
1057 if (!strcmp(state
, "Available")) {
1058 yd
->current_status
= YAHOO_STATUS_AVAILABLE
;
1060 } else if (!strcmp(state
, "Be Right Back")) {
1061 yd
->current_status
= YAHOO_STATUS_BRB
;
1062 } else if (!strcmp(state
, "Busy")) {
1063 yd
->current_status
= YAHOO_STATUS_BUSY
;
1064 } else if (!strcmp(state
, "Not At Home")) {
1065 yd
->current_status
= YAHOO_STATUS_NOTATHOME
;
1066 } else if (!strcmp(state
, "Not At Desk")) {
1067 yd
->current_status
= YAHOO_STATUS_NOTATDESK
;
1068 } else if (!strcmp(state
, "Not In Office")) {
1069 yd
->current_status
= YAHOO_STATUS_NOTINOFFICE
;
1070 } else if (!strcmp(state
, "On Phone")) {
1071 yd
->current_status
= YAHOO_STATUS_ONPHONE
;
1072 } else if (!strcmp(state
, "On Vacation")) {
1073 yd
->current_status
= YAHOO_STATUS_ONVACATION
;
1074 } else if (!strcmp(state
, "Out To Lunch")) {
1075 yd
->current_status
= YAHOO_STATUS_OUTTOLUNCH
;
1076 } else if (!strcmp(state
, "Stepped Out")) {
1077 yd
->current_status
= YAHOO_STATUS_STEPPEDOUT
;
1078 } else if (!strcmp(state
, "Invisible")) {
1079 yd
->current_status
= YAHOO_STATUS_INVISIBLE
;
1080 } else if (!strcmp(state
, GAIM_AWAY_CUSTOM
)) {
1082 yd
->current_status
= YAHOO_STATUS_IDLE
;
1084 yd
->current_status
= YAHOO_STATUS_AVAILABLE
;
1088 } else if (gc
->is_idle
) {
1089 yd
->current_status
= YAHOO_STATUS_IDLE
;
1091 yd
->current_status
= YAHOO_STATUS_AVAILABLE
;
1094 if (yd
->current_status
== YAHOO_STATUS_AVAILABLE
)
1095 service
= YAHOO_SERVICE_ISBACK
;
1097 service
= YAHOO_SERVICE_ISAWAY
;
1098 pkt
= yahoo_packet_new(service
, yd
->current_status
, 0);
1099 g_snprintf(s
, sizeof(s
), "%d", yd
->current_status
);
1100 yahoo_packet_hash(pkt
, 10, s
);
1101 if (yd
->current_status
== YAHOO_STATUS_CUSTOM
)
1102 yahoo_packet_hash(pkt
, 19, msg
);
1104 yahoo_send_packet(yd
, pkt
);
1105 yahoo_packet_free(pkt
);
1108 static void yahoo_set_idle(struct gaim_connection
*gc
, int idle
)
1110 struct yahoo_data
*yd
= gc
->proto_data
;
1111 struct yahoo_packet
*pkt
= NULL
;
1113 if (idle
&& yd
->current_status
== YAHOO_STATUS_AVAILABLE
) {
1114 pkt
= yahoo_packet_new(YAHOO_SERVICE_ISAWAY
, YAHOO_STATUS_IDLE
, 0);
1115 yd
->current_status
= YAHOO_STATUS_IDLE
;
1116 } else if (!idle
&& yd
->current_status
== YAHOO_STATUS_IDLE
) {
1117 pkt
= yahoo_packet_new(YAHOO_SERVICE_ISAWAY
, YAHOO_STATUS_AVAILABLE
, 0);
1118 yd
->current_status
= YAHOO_STATUS_AVAILABLE
;
1123 g_snprintf(buf
, sizeof(buf
), "%d", yd
->current_status
);
1124 yahoo_packet_hash(pkt
, 10, buf
);
1125 yahoo_send_packet(yd
, pkt
);
1126 yahoo_packet_free(pkt
);
1130 static GList
*yahoo_away_states(struct gaim_connection
*gc
)
1134 m
= g_list_append(m
, "Available");
1135 m
= g_list_append(m
, "Be Right Back");
1136 m
= g_list_append(m
, "Busy");
1137 m
= g_list_append(m
, "Not At Home");
1138 m
= g_list_append(m
, "Not At Desk");
1139 m
= g_list_append(m
, "Not In Office");
1140 m
= g_list_append(m
, "On Phone");
1141 m
= g_list_append(m
, "On Vacation");
1142 m
= g_list_append(m
, "Out To Lunch");
1143 m
= g_list_append(m
, "Stepped Out");
1144 m
= g_list_append(m
, "Invisible");
1145 m
= g_list_append(m
, GAIM_AWAY_CUSTOM
);
1150 static void yahoo_keepalive(struct gaim_connection
*gc
)
1152 struct yahoo_data
*yd
= gc
->proto_data
;
1153 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_PING
, YAHOO_STATUS_AVAILABLE
, 0);
1154 yahoo_send_packet(yd
, pkt
);
1155 yahoo_packet_free(pkt
);
1158 static void yahoo_add_buddy(struct gaim_connection
*gc
, char *who
)
1160 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
1161 struct yahoo_packet
*pkt
;
1168 g
= find_group_by_buddy(gc
, who
);
1174 pkt
= yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY
, YAHOO_STATUS_AVAILABLE
, 0);
1175 yahoo_packet_hash(pkt
, 1, gc
->displayname
);
1176 yahoo_packet_hash(pkt
, 7, who
);
1177 yahoo_packet_hash(pkt
, 65, group
);
1178 yahoo_send_packet(yd
, pkt
);
1179 yahoo_packet_free(pkt
);
1182 static void yahoo_remove_buddy(struct gaim_connection
*gc
, char *who
, char *group
)
1184 struct yahoo_data
*yd
= (struct yahoo_data
*)gc
->proto_data
;
1186 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_REMBUDDY
, YAHOO_STATUS_AVAILABLE
, 0);
1187 yahoo_packet_hash(pkt
, 1, gc
->displayname
);
1188 yahoo_packet_hash(pkt
, 7, who
);
1189 yahoo_packet_hash(pkt
, 65, group
);
1190 yahoo_send_packet(yd
, pkt
);
1191 yahoo_packet_free(pkt
);
1195 GSList
*yahoo_smiley_list()
1197 GSList
*smilies
= NULL
;
1199 smilies
= add_smiley(smilies
, "=:)", yahoo_alien
, 1);
1200 smilies
= add_smiley(smilies
, "=:-)", yahoo_alien
, 0);
1201 smilies
= add_smiley(smilies
, "o:)", yahoo_angel
, 0);
1202 smilies
= add_smiley(smilies
, "o:-)", yahoo_angel
, 0);
1203 smilies
= add_smiley(smilies
, "0:)", yahoo_angel
, 0);
1204 smilies
= add_smiley(smilies
, "0:-)", yahoo_angel
, 0);
1205 smilies
= add_smiley(smilies
, "X-(", yahoo_angry
, 1);
1206 smilies
= add_smiley(smilies
, "X(", yahoo_angry
, 0);
1207 smilies
= add_smiley(smilies
, "x-(", yahoo_angry
, 0);
1208 smilies
= add_smiley(smilies
, "x(", yahoo_angry
, 0);
1209 smilies
= add_smiley(smilies
, ":D", yahoo_bigsmile
, 1);
1210 smilies
= add_smiley(smilies
, ":-D", yahoo_bigsmile
, 0);
1211 smilies
= add_smiley(smilies
, ":\">", yahoo_blush
, 1);
1212 smilies
= add_smiley(smilies
, "=;", yahoo_bye
, 1);
1213 smilies
= add_smiley(smilies
, ":o)", yahoo_clown
, 1);
1214 smilies
= add_smiley(smilies
, ":0)", yahoo_clown
, 0);
1215 smilies
= add_smiley(smilies
, ":O)", yahoo_clown
, 0);
1216 smilies
= add_smiley(smilies
, "<@:)", yahoo_clown
, 0);
1217 smilies
= add_smiley(smilies
, "3:-0", yahoo_cow
, 1);
1218 smilies
= add_smiley(smilies
, "3:-o", yahoo_cow
, 0);
1219 smilies
= add_smiley(smilies
, "3:-O", yahoo_cow
, 0);
1220 smilies
= add_smiley(smilies
, "3:O", yahoo_cow
, 0);
1221 smilies
= add_smiley(smilies
, "<):)", yahoo_cowboy
, 1);
1222 smilies
= add_smiley(smilies
, ":((", yahoo_cry
, 1);
1223 smilies
= add_smiley(smilies
, ":-((", yahoo_cry
, 0);
1224 smilies
= add_smiley(smilies
, ">:)", yahoo_devil
, 1);
1225 smilies
= add_smiley(smilies
, "@};-", yahoo_flower
, 1);
1226 smilies
= add_smiley(smilies
, "8-X", yahoo_ghost
, 1);
1227 smilies
= add_smiley(smilies
, ":B", yahoo_glasses
, 1);
1228 smilies
= add_smiley(smilies
, ":-B", yahoo_glasses
, 0);
1229 smilies
= add_smiley(smilies
, ":))", yahoo_laughloud
, 1);
1230 smilies
= add_smiley(smilies
, ":-))", yahoo_laughloud
, 0);
1231 smilies
= add_smiley(smilies
, ":x", yahoo_love
, 1);
1232 smilies
= add_smiley(smilies
, ":-x", yahoo_love
, 0);
1233 smilies
= add_smiley(smilies
, ":X", yahoo_love
, 0);
1234 smilies
= add_smiley(smilies
, ":-X", yahoo_love
, 0);
1235 smilies
= add_smiley(smilies
, ":>", yahoo_mean
, 1);
1236 smilies
= add_smiley(smilies
, ":->", yahoo_mean
, 0);
1237 smilies
= add_smiley(smilies
, ":|", yahoo_neutral
, 1);
1238 smilies
= add_smiley(smilies
, ":-|", yahoo_neutral
, 0);
1239 smilies
= add_smiley(smilies
, ":O", yahoo_ooooh
, 1);
1240 smilies
= add_smiley(smilies
, ":-O", yahoo_ooooh
, 0);
1241 smilies
= add_smiley(smilies
, ":-\\", yahoo_question
, 1);
1242 smilies
= add_smiley(smilies
, ":-/", yahoo_question
, 0);
1243 smilies
= add_smiley(smilies
, ":(", yahoo_sad
, 1);
1244 smilies
= add_smiley(smilies
, ":-(", yahoo_sad
, 0);
1245 smilies
= add_smiley(smilies
, "I-)", yahoo_sleep
, 1);
1246 smilies
= add_smiley(smilies
, "|-)", yahoo_sleep
, 0);
1247 smilies
= add_smiley(smilies
, "I-|", yahoo_sleep
, 0);
1248 smilies
= add_smiley(smilies
, ":)", yahoo_smiley
, 1);
1249 smilies
= add_smiley(smilies
, ":-)", yahoo_smiley
, 0);
1250 smilies
= add_smiley(smilies
, "(:", yahoo_smiley
, 0);
1251 smilies
= add_smiley(smilies
, "(-:", yahoo_smiley
, 0);
1252 smilies
= add_smiley(smilies
, "B-)", yahoo_sunglas
, 1);
1253 smilies
= add_smiley(smilies
, ":-p", yahoo_tongue
, 1);
1254 smilies
= add_smiley(smilies
, ":p", yahoo_tongue
, 0);
1255 smilies
= add_smiley(smilies
, ":P", yahoo_tongue
, 0);
1256 smilies
= add_smiley(smilies
, ":-P", yahoo_tongue
, 0);
1257 smilies
= add_smiley(smilies
, ";)", yahoo_wink
, 1);
1258 smilies
= add_smiley(smilies
, ";-)", yahoo_wink
, 0);
1264 static struct prpl
*my_protocol
= NULL
;
1266 void yahoo_init(struct prpl
*ret
) {
1267 ret
->protocol
= PROTO_YAHOO
;
1268 ret
->options
= OPT_PROTO_MAIL_CHECK
;
1269 ret
->name
= yahoo_name
;
1270 ret
->user_opts
= yahoo_user_opts
;
1271 ret
->login
= yahoo_login
;
1272 ret
->close
= yahoo_close
;
1273 ret
->buddy_menu
= yahoo_buddy_menu
;
1274 ret
->list_icon
= yahoo_list_icon
;
1275 ret
->actions
= yahoo_actions
;
1276 ret
->do_action
= yahoo_do_action
;
1277 ret
->send_im
= yahoo_send_im
;
1278 ret
->away_states
= yahoo_away_states
;
1279 ret
->set_away
= yahoo_set_away
;
1280 ret
->set_idle
= yahoo_set_idle
;
1281 ret
->keepalive
= yahoo_keepalive
;
1282 ret
->add_buddy
= yahoo_add_buddy
;
1283 ret
->remove_buddy
= yahoo_remove_buddy
;
1284 ret
->send_typing
= yahoo_send_typing
;
1285 ret
->smiley_list
= yahoo_smiley_list
;
1292 char *gaim_plugin_init(GModule
*handle
)
1294 load_protocol(yahoo_init
, sizeof(struct prpl
));
1298 void gaim_plugin_remove()
1300 struct prpl
*p
= find_prpl(PROTO_YAHOO
);
1301 if (p
== my_protocol
)
1312 return PRPL_DESC("Yahoo");