2 * gaim - Napster Protocol Plugin
4 * Copyright (C) 2000-2001, Rob Flynn <rob@tgflinux.com>
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.
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.
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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
34 #include <sys/socket.h>
40 #include "pixmaps/napster.xpm"
42 #define NAP_BUF_LEN 4096
44 GSList
*nap_connections
= NULL
;
46 static unsigned int chat_id
= 0;
61 static char *nap_name()
67 /* FIXME: Make this use va_arg stuff */
68 static void nap_write_packet(struct gaim_connection
*gc
, unsigned short command
, char *message
)
70 struct nap_data
*ndata
= (struct nap_data
*)gc
->proto_data
;
73 size
= strlen(message
);
75 write(ndata
->fd
, &size
, 2);
76 write(ndata
->fd
, &command
, 2);
77 write(ndata
->fd
, message
, size
);
80 static int nap_send_im(struct gaim_connection
*gc
, char *who
, char *message
, int len
, int flags
)
82 gchar buf
[NAP_BUF_LEN
];
84 g_snprintf(buf
, NAP_BUF_LEN
, "%s %s", who
, message
);
85 nap_write_packet(gc
, 0xCD, buf
);
90 static struct nap_channel
*find_channel_by_name(struct gaim_connection
*gc
, char *name
)
92 struct nap_channel
*channel
;
93 struct nap_data
*ndata
= (struct nap_data
*)gc
->proto_data
;
96 channels
= ndata
->channels
;
99 channel
= (struct nap_channel
*)channels
->data
;
102 if (!g_strcasecmp(name
, channel
->name
)) {
106 channels
= g_slist_next(channels
);
112 static struct nap_channel
*find_channel_by_id(struct gaim_connection
*gc
, int id
)
114 struct nap_channel
*channel
;
115 struct nap_data
*ndata
= (struct nap_data
*)gc
->proto_data
;
118 channels
= ndata
->channels
;
121 channel
= (struct nap_channel
*)channels
->data
;
122 if (id
== channel
->id
) {
126 channels
= g_slist_next(channels
);
132 static struct conversation
*find_conversation_by_id(struct gaim_connection
*gc
, int id
)
134 GSList
*bc
= gc
->buddy_chats
;
135 struct conversation
*b
= NULL
;
138 b
= (struct conversation
*)bc
->data
;
149 static void nap_callback(gpointer data
, gint source
, GaimInputCondition condition
)
151 struct gaim_connection
*gc
= data
;
152 struct nap_data
*ndata
= gc
->proto_data
;
154 unsigned short header
[2];
160 if (recv(source
, header
, 4, 0) != 4) {
161 hide_login_progress(gc
, "Unable to read");
169 buf
= (gchar
*)g_malloc(sizeof(gchar
) * (len
+ 1));
173 int tmp
= recv(source
, buf
+ i
, len
- i
, 0);
176 hide_login_progress(gc
, "Unable to read");
185 debug_printf("DEBUG: %s\n", buf
);
187 if (command
== 0xd6) {
188 res
= g_strsplit(buf
, " ", 0);
189 /* Do we want to report what the users are doing? */
190 printf("users: %s, files: %s, size: %sGB\n", res
[0], res
[1], res
[2]);
196 if (command
== 0x26d) {
197 /* Do we want to use the MOTD? */
202 if (command
== 0xCD) {
203 res
= g_strsplit(buf
, " ", 1);
204 serv_got_im(gc
, res
[0], res
[1], 0, time(NULL
), -1);
210 if (command
== 0x195) {
211 struct nap_channel
*channel
;
213 channel
= find_channel_by_name(gc
, buf
);
218 channel
= g_new0(struct nap_channel
, 1);
220 channel
->id
= chat_id
;
221 channel
->name
= g_strdup(buf
);
223 ndata
->channels
= g_slist_append(ndata
->channels
, channel
);
225 serv_got_joined_chat(gc
, chat_id
, buf
);
232 if (command
== 0x198 || command
== 0x196) {
233 struct nap_channel
*channel
;
234 struct conversation
*convo
;
237 res
= g_strsplit(buf
, " ", 0);
239 channel
= find_channel_by_name(gc
, res
[0]);
240 convo
= find_conversation_by_id(gc
, channel
->id
);
242 add_chat_buddy(convo
, res
[1]);
250 if (command
== 0x197) {
251 struct nap_channel
*channel
;
252 struct conversation
*convo
;
255 res
= g_strsplit(buf
, " ", 0);
257 channel
= find_channel_by_name(gc
, res
[0]);
258 convo
= find_conversation_by_id(gc
, channel
->id
);
260 remove_chat_buddy(convo
, res
[1], NULL
);
267 if (command
== 0x193) {
269 struct nap_channel
*channel
;
271 res
= g_strsplit(buf
, " ", 2);
273 channel
= find_channel_by_name(gc
, res
[0]);
276 serv_got_chat_in(gc
, channel
->id
, res
[1], 0, res
[2], time((time_t)NULL
));
283 if (command
== 0x194) {
284 do_error_dialog(buf
, "Gaim: Napster Error");
289 if (command
== 0x12e) {
290 gchar buf2
[NAP_BUF_LEN
];
292 g_snprintf(buf2
, NAP_BUF_LEN
, "Unable to add '%s' to your hotlist", buf
);
293 do_error_dialog(buf2
, "Gaim: Napster Error");
300 if (command
== 0x191) {
301 struct nap_channel
*channel
;
303 channel
= find_channel_by_name(gc
, buf
);
305 if (!channel
) /* I'm not sure how this would happen =) */
308 serv_got_chat_left(gc
, channel
->id
);
309 ndata
->channels
= g_slist_remove(ndata
->channels
, channel
);
316 if (command
== 0xd1) {
319 res
= g_strsplit(buf
, " ", 0);
321 serv_got_update(gc
, res
[0], 1, 0, 0, 0, 0, 0);
328 if (command
== 0xd2) {
329 serv_got_update(gc
, buf
, 0, 0, 0, 0, 0, 0);
334 if (command
== 0x12d) {
335 /* Our buddy was added successfully */
340 if (command
== 0x2ec) {
341 /* Looks like someone logged in as us! =-O */
348 debug_printf("NAP: [COMMAND: 0x%04x] %s\n", command
, buf
);
354 static void nap_login_callback(gpointer data
, gint source
, GaimInputCondition condition
)
356 struct gaim_connection
*gc
= data
;
357 struct nap_data
*ndata
= gc
->proto_data
;
358 gchar buf
[NAP_BUF_LEN
];
359 unsigned short header
[2];
363 read(source
, header
, 4);
367 read(source
, buf
, len
);
370 /* If we have some kind of error, get outta here */
373 do_error_dialog(buf
, "Gaim: Napster Error");
374 gaim_input_remove(ndata
->inpa
);
381 if (command
== 0x03) {
382 printf("Registered with E-Mail address of: %s\n", buf
);
383 ndata
->email
= g_strdup(buf
);
385 /* Remove old inpa, add new one */
386 gaim_input_remove(ndata
->inpa
);
388 gc
->inpa
= gaim_input_add(ndata
->fd
, GAIM_INPUT_READ
, nap_callback
, gc
);
390 /* Our signon is complete */
392 serv_finish_login(gc
);
394 if (bud_list_cache_exists(gc
))
402 static void nap_login_connect(gpointer data
, gint source
, GaimInputCondition cond
)
404 struct gaim_connection
*gc
= data
;
405 struct nap_data
*ndata
;
406 char buf
[NAP_BUF_LEN
];
408 if (!g_slist_find(connections
, gc
)) {
414 hide_login_progress(gc
, "Unable to connect");
419 ndata
= gc
->proto_data
;
420 if (ndata
->fd
!= source
)
423 /* And write our signon data */
424 g_snprintf(buf
, NAP_BUF_LEN
, "%s %s 0 \"gaimster\" 0", gc
->username
, gc
->password
);
425 nap_write_packet(gc
, 0x02, buf
);
427 /* And set up the input watcher */
428 ndata
->inpa
= gaim_input_add(ndata
->fd
, GAIM_INPUT_READ
, nap_login_callback
, gc
);
432 static void nap_login(struct aim_user
*user
)
434 struct gaim_connection
*gc
= new_gaim_conn(user
);
435 struct nap_data
*ndata
= gc
->proto_data
= g_new0(struct nap_data
, 1);
437 ndata
->fd
= proxy_connect("64.124.41.187", 8888, nap_login_connect
, gc
);
439 hide_login_progress(gc
, "Unable to connect");
444 static GList
*nap_chat_info(struct gaim_connection
*gc
)
447 struct proto_chat_entry
*pce
;
449 pce
= g_new0(struct proto_chat_entry
, 1);
450 pce
->label
= _("Join what group:");
451 m
= g_list_append(m
, pce
);
456 static void nap_join_chat(struct gaim_connection
*gc
, GList
*data
)
458 gchar buf
[NAP_BUF_LEN
];
466 /* Make sure the name has a # preceeding it */
468 g_snprintf(buf
, NAP_BUF_LEN
, "#%s", name
);
470 g_snprintf(buf
, NAP_BUF_LEN
, "%s", name
);
472 nap_write_packet(gc
, 0x190, buf
);
475 static void nap_chat_leave(struct gaim_connection
*gc
, int id
)
477 struct nap_data
*ndata
= (struct nap_data
*)gc
->proto_data
;
478 struct nap_channel
*channel
= NULL
;
480 channel
= find_channel_by_id(gc
, id
);
482 if (!channel
) /* Again, I'm not sure how this would happen */
485 nap_write_packet(gc
, 0x191, channel
->name
);
487 ndata
->channels
= g_slist_remove(ndata
->channels
, channel
);
488 g_free(channel
->name
);
493 static int nap_chat_send(struct gaim_connection
*gc
, int id
, char *message
)
495 struct nap_channel
*channel
= NULL
;
496 gchar buf
[NAP_BUF_LEN
];
498 channel
= find_channel_by_id(gc
, id
);
501 /* This shouldn't happen */
505 g_snprintf(buf
, NAP_BUF_LEN
, "%s %s", channel
->name
, message
);
506 nap_write_packet(gc
, 0x192, buf
);
510 static void nap_add_buddy(struct gaim_connection
*gc
, char *name
)
512 nap_write_packet(gc
, 0xCF, name
);
515 static void nap_remove_buddy(struct gaim_connection
*gc
, char *name
, char *group
)
517 nap_write_packet(gc
, 0x12F, name
);
520 static void nap_close(struct gaim_connection
*gc
)
522 struct nap_data
*ndata
= (struct nap_data
*)gc
->proto_data
;
523 struct nap_channel
*channel
;
526 gaim_input_remove(gc
->inpa
);
528 while (ndata
->channels
) {
529 channel
= (struct nap_channel
*)ndata
->channels
->data
;
530 g_free(channel
->name
);
531 ndata
->channels
= g_slist_remove(ndata
->channels
, channel
);
535 g_free(gc
->proto_data
);
538 static void nap_add_buddies(struct gaim_connection
*gc
, GList
*buddies
)
541 nap_write_packet(gc
, 0xd0, (char *)buddies
->data
);
542 buddies
= buddies
-> next
;
546 static char** nap_list_icon(int uc
)
551 static struct prpl
*my_protocol
= NULL
;
553 void napster_init(struct prpl
*ret
)
555 ret
->protocol
= PROTO_NAPSTER
;
556 ret
->name
= nap_name
;
557 ret
->list_icon
= nap_list_icon
;
558 ret
->user_opts
= NULL
;
559 ret
->login
= nap_login
;
560 ret
->close
= nap_close
;
561 ret
->send_im
= nap_send_im
;
562 ret
->set_info
= NULL
;
563 ret
->get_info
= NULL
;
564 ret
->set_away
= NULL
;
567 ret
->dir_search
= NULL
;
568 ret
->set_idle
= NULL
;
569 ret
->change_passwd
= NULL
;
570 ret
->add_buddy
= nap_add_buddy
;
571 ret
->add_buddies
= nap_add_buddies
;
572 ret
->remove_buddy
= nap_remove_buddy
;
573 ret
->add_permit
= NULL
;
574 ret
->rem_permit
= NULL
;
575 ret
->add_deny
= NULL
;
576 ret
->rem_deny
= NULL
;
578 ret
->chat_info
= nap_chat_info
;
579 ret
->join_chat
= nap_join_chat
;
580 ret
->chat_invite
= NULL
;
581 ret
->chat_leave
= nap_chat_leave
;
582 ret
->chat_whisper
= NULL
;
583 ret
->chat_send
= nap_chat_send
;
584 ret
->keepalive
= NULL
;
591 char *gaim_plugin_init(GModule
* handle
)
593 load_protocol(napster_init
, sizeof(struct prpl
));
597 void gaim_plugin_remove()
599 struct prpl
*p
= find_prpl(PROTO_NAPSTER
);
600 if (p
== my_protocol
)
611 return PRPL_DESC("Napster");