3 #include "icq.h" /* well, we're doing ICQ, right? */
4 #include "multi.h" /* needed for gaim_connection */
5 #include "prpl.h" /* needed for prpl */
6 #include "gaim.h" /* needed for every other damn thing */
9 #include "pixmaps/gnomeicu-online.xpm"
10 #include "pixmaps/gnomeicu-away.xpm"
11 #include "pixmaps/gnomeicu-dnd.xpm"
12 #include "pixmaps/gnomeicu-na.xpm"
13 #include "pixmaps/gnomeicu-occ.xpm"
14 #include "pixmaps/gnomeicu-ffc.xpm"
16 #define USEROPT_NICK 0
24 static guint ack_timer
= 0;
26 static char *icq_name() {
30 static void icq_do_log(icq_Link
*link
, time_t time
, unsigned char level
, const char *log
) {
31 debug_printf("ICQ debug %d: %s", level
, log
);
34 GList
*sockets
= NULL
;
41 static void gaim_icq_handler(gpointer data
, gint source
, GaimInputCondition cond
) {
42 if (cond
& GAIM_INPUT_READ
)
43 icq_HandleReadySocket(source
, ICQ_SOCKET_READ
);
44 if (cond
& GAIM_INPUT_WRITE
)
45 icq_HandleReadySocket(source
, ICQ_SOCKET_WRITE
);
48 static void icq_sock_notify(int socket
, int type
, int status
) {
49 struct gaim_sock
*gs
= NULL
;
51 GaimInputCondition cond
;
52 if (type
== ICQ_SOCKET_READ
)
53 cond
= GAIM_INPUT_READ
;
55 cond
= GAIM_INPUT_WRITE
;
56 gs
= g_new0(struct gaim_sock
, 1);
59 gs
->inpa
= gaim_input_add(socket
, cond
, gaim_icq_handler
, NULL
);
60 sockets
= g_list_append(sockets
, gs
);
61 debug_printf("Adding socket notifier: %d %d (%d)\n", socket
, type
, gs
->inpa
);
66 if ((gs
->socket
== socket
) && (gs
->type
== type
))
71 gaim_input_remove(gs
->inpa
);
72 sockets
= g_list_remove(sockets
, gs
);
73 debug_printf("Removing socket notifier: %d %d (%d)\n", socket
, type
, gs
->inpa
);
79 static void icq_online(icq_Link
*link
) {
80 struct gaim_connection
*gc
= link
->icq_UserData
;
81 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
82 debug_printf("%s is now online.\n", gc
->username
);
85 serv_finish_login(gc
);
86 icq_ChangeStatus(id
->link
, STATUS_ONLINE
);
91 static void icq_logged_off(icq_Link
*link
) {
92 struct gaim_connection
*gc
= link
->icq_UserData
;
93 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
96 hide_login_progress(gc
, "Unable to connect");
101 if (icq_Connect(link
, "icq.mirabilis.com", 4000) < 1) {
102 hide_login_progress(gc
, "Unable to connect");
107 icq_Login(link
, id
->cur_status
);
110 static void icq_msg_incoming(icq_Link
*link
, unsigned long uin
, unsigned char hour
, unsigned char minute
,
111 unsigned char day
, unsigned char month
, unsigned short year
, const char *data
) {
112 struct gaim_connection
*gc
= link
->icq_UserData
;
113 char buf
[256], *tmp
= g_malloc(BUF_LONG
);
114 g_snprintf(tmp
, BUF_LONG
, "%s", data
);
115 g_snprintf(buf
, sizeof buf
, "%lu", uin
);
117 serv_got_im(gc
, buf
, tmp
, 0, time(NULL
), -1);
121 static void icq_user_online(icq_Link
*link
, unsigned long uin
, unsigned long st
,
122 unsigned long ip
, unsigned short port
, unsigned long real_ip
,
123 unsigned char tcp_flags
) {
124 struct gaim_connection
*gc
= link
->icq_UserData
;
128 g_snprintf(buf
, sizeof buf
, "%lu", uin
);
129 status
= (st
== STATUS_ONLINE
) ? 0 : UC_UNAVAILABLE
| (st
<< 1);
130 serv_got_update(gc
, buf
, 1, 0, 0, 0, status
, 0);
133 static void icq_user_offline(icq_Link
*link
, unsigned long uin
) {
134 struct gaim_connection
*gc
= link
->icq_UserData
;
135 char buf
[256]; g_snprintf(buf
, sizeof buf
, "%lu", uin
);
136 serv_got_update(gc
, buf
, 0, 0, 0, 0, 0, 0);
139 static void icq_user_status(icq_Link
*link
, unsigned long uin
, unsigned long st
) {
140 struct gaim_connection
*gc
= link
->icq_UserData
;
144 g_snprintf(buf
, sizeof buf
, "%lu", uin
);
145 status
= (st
== STATUS_ONLINE
) ? 0 : UC_UNAVAILABLE
| (st
<< 1);
146 serv_got_update(gc
, buf
, 1, 0, 0, 0, status
, 0);
149 static gboolean
icq_set_timeout_cb(gpointer data
) {
155 static void icq_set_timeout(long interval
) {
156 debug_printf("icq_SetTimeout: %ld\n", interval
);
157 if (interval
> 0 && ack_timer
== 0)
158 ack_timer
= g_timeout_add(interval
* 1000, icq_set_timeout_cb
, NULL
);
159 else if (ack_timer
> 0) {
160 g_source_remove(ack_timer
);
165 static void icq_url_incoming(icq_Link
*link
, unsigned long uin
, unsigned char hour
,
166 unsigned char minute
, unsigned char day
, unsigned char month
,
167 unsigned short year
, const char *url
, const char *descr
) {
168 struct gaim_connection
*gc
= link
->icq_UserData
;
169 char *msg
= g_malloc(BUF_LONG
), buf
[256];
170 g_snprintf(msg
, BUF_LONG
, "<A HREF=\"%s\">%s</A>", url
, descr
);
171 g_snprintf(buf
, 256, "%lu", uin
);
172 serv_got_im(gc
, buf
, msg
, 0, time(NULL
), -1);
176 static void icq_wrong_passwd(icq_Link
*link
) {
177 struct gaim_connection
*gc
= link
->icq_UserData
;
178 hide_login_progress(gc
, "Invalid password.");
182 static void icq_invalid_uin(icq_Link
*link
) {
183 struct gaim_connection
*gc
= link
->icq_UserData
;
184 hide_login_progress(gc
, "Invalid UIN.");
188 static void icq_info_reply(icq_Link
*link
, unsigned long uin
, const char *nick
,
189 const char *first
, const char *last
, const char *email
, char auth
) {
190 struct gaim_connection
*gc
= link
->icq_UserData
;
194 g_snprintf(who
, sizeof who
, "%lu", uin
);
195 g_snprintf(buf
, sizeof buf
,
196 "<B>UIN:</B> %lu<BR>"
197 "<B>Nick:</B> %s<BR>"
198 "<B>Name:</B> %s %s<BR>"
199 "<B>Email:</B> %s\n",
204 g_show_info_text(gc
, who
, 2, buf
, NULL
);
207 static void icq_web_pager(icq_Link
*link
, unsigned char hour
, unsigned char minute
,
208 unsigned char day
, unsigned char month
, unsigned short year
, const char *nick
,
209 const char *email
, const char *msg
) {
210 struct gaim_connection
*gc
= link
->icq_UserData
;
211 char *who
= g_strdup_printf("ICQ Web Pager: %s (%s)", nick
, email
);
212 char *what
= g_malloc(BUF_LONG
);
213 g_snprintf(what
, BUF_LONG
, "%s", msg
);
214 serv_got_im(gc
, who
, what
, 0, time(NULL
), -1);
219 static void icq_mail_express(icq_Link
*link
, unsigned char hour
, unsigned char minute
,
220 unsigned char day
, unsigned char month
, unsigned short year
, const char *nick
,
221 const char *email
, const char *msg
) {
222 struct gaim_connection
*gc
= link
->icq_UserData
;
223 char *who
= g_strdup_printf("ICQ Mail Express: %s (%s)", nick
, email
);
224 char *what
= g_malloc(BUF_LONG
);
225 g_snprintf(what
, BUF_LONG
, "%s", msg
);
226 serv_got_im(gc
, who
, what
, 0, time(NULL
), -1);
231 static void icq_req_not(icq_Link
*link
, unsigned long id
, int type
, int arg
, void *data
) {
232 if (type
== ICQ_NOTIFY_FAILED
)
233 do_error_dialog("Failure in sending packet", "ICQ error");
237 static void icq_recv_add(icq_Link
*link
, unsigned long id
, unsigned char hour
, unsigned char minute
,
238 unsigned char day
, unsigned char month
, unsigned short year
, const char *nick
,
239 const char *first
, const char *last
, const char *email
)
242 g_snprintf(uin
, sizeof(uin
), "%ld", id
);
243 show_got_added(link
->icq_UserData
, NULL
, uin
, nick
, NULL
);
250 struct gaim_connection
*gc
;
253 static void icq_den_auth(gpointer x
, struct icq_auth
*iq
)
259 static void icq_add_after_auth(gpointer x
, struct icq_auth
*iq
)
262 g_snprintf(uin
, sizeof(uin
), "%ld", iq
->uin
);
263 show_add_buddy(iq
->gc
, uin
, NULL
, iq
->nick
);
266 static void icq_acc_auth(gpointer x
, struct icq_auth
*iq
)
270 struct icq_auth
*iqnew
;
272 icq_SendAuthMsg(iq
->link
, iq
->uin
);
274 g_snprintf(uin
, sizeof(uin
), "%ld", iq
->uin
);
275 if (find_buddy(iq
->gc
, uin
))
278 iqnew
= g_memdup(iq
, sizeof(struct icq_auth
));
279 iqnew
->nick
= g_strdup(iq
->nick
);
281 g_snprintf(msg
, sizeof(msg
), "Add %ld to your buddy list?", iq
->uin
);
282 do_ask_dialog(msg
, iqnew
, icq_add_after_auth
, icq_den_auth
);
285 static void icq_auth_req(icq_Link
*link
, unsigned long uin
, unsigned char hour
, unsigned char minute
,
286 unsigned char day
, unsigned char month
, unsigned short year
, const char *nick
,
287 const char *first
, const char *last
, const char *email
, const char *reason
)
290 struct icq_auth
*iq
= g_new0(struct icq_auth
, 1);
292 iq
->nick
= g_strdup(nick
);
294 iq
->gc
= link
->icq_UserData
;
296 g_snprintf(msg
, sizeof(msg
), "The user %s (%s%s%s%s%s) wants you to authorize them.",
297 nick
, first
? first
: "", first
&& last
? " " : "", last
? last
: "",
298 (first
|| last
) && email
? ", " : "", email
? email
: "");
299 do_ask_dialog(msg
, iq
, icq_acc_auth
, icq_den_auth
);
302 static void icq_login(struct aim_user
*user
) {
303 struct gaim_connection
*gc
= new_gaim_conn(user
);
304 struct icq_data
*id
= gc
->proto_data
= g_new0(struct icq_data
, 1);
308 gc
->checkbox
= _("Send message through server");
310 icq_LogLevel
= ICQ_LOG_MESSAGE
;
312 g_snprintf(ps
, sizeof(ps
), "%s", user
->password
);
313 link
= id
->link
= icq_ICQLINKNew(atol(user
->username
), ps
,
314 user
->proto_opt
[USEROPT_NICK
][0] ? user
->proto_opt
[USEROPT_NICK
] : "gaim user",
316 g_snprintf(gc
->displayname
, sizeof(gc
->displayname
), "%s", user
->proto_opt
[USEROPT_NICK
]);
318 link
->icq_Logged
= icq_online
;
319 link
->icq_Disconnected
= icq_logged_off
;
320 link
->icq_RecvMessage
= icq_msg_incoming
;
321 link
->icq_RecvURL
= icq_url_incoming
;
322 link
->icq_RecvWebPager
= icq_web_pager
;
323 link
->icq_RecvMailExpress
= icq_mail_express
;
324 link
->icq_RecvAdded
= icq_recv_add
;
325 link
->icq_RecvAuthReq
= icq_auth_req
;
326 link
->icq_UserOnline
= icq_user_online
;
327 link
->icq_UserOffline
= icq_user_offline
;
328 link
->icq_UserStatusUpdate
= icq_user_status
;
329 link
->icq_InfoReply
= icq_info_reply
;
330 link
->icq_WrongPassword
= icq_wrong_passwd
;
331 link
->icq_InvalidUIN
= icq_invalid_uin
;
332 link
->icq_Log
= icq_do_log
;
333 link
->icq_RequestNotify
= icq_req_not
;
334 link
->icq_UserData
= gc
;
336 if (proxytype
== PROXY_SOCKS5
)
337 icq_SetProxy(link
, proxyhost
, proxyport
, proxyuser
[0], proxyuser
, proxypass
);
339 icq_ContactClear(id
->link
);
340 if (bud_list_cache_exists(gc
))
343 if (icq_Connect(link
, "icq.mirabilis.com", 4000) < 1) {
344 hide_login_progress(gc
, "Unable to connect");
349 id
->cur_status
= STATUS_ONLINE
;
350 icq_Login(link
, STATUS_ONLINE
);
352 set_login_progress(gc
, 0, "Connecting...");
355 static void icq_close(struct gaim_connection
*gc
) {
356 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
358 icq_Logout(id
->link
);
359 icq_Disconnect(id
->link
);
360 icq_ICQLINKDelete(id
->link
);
364 static int icq_send_msg(struct gaim_connection
*gc
, char *who
, char *msg
, int len
, int flags
) {
365 if (!(flags
& IM_FLAG_AWAY
) && (strlen(msg
) > 0)) {
366 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
368 icq_SendMessage(id
->link
, w
, msg
,
369 (flags
& IM_FLAG_CHECKBOX
) ? ICQ_SEND_THRUSERVER
: ICQ_SEND_BESTWAY
);
374 static void icq_keepalive(struct gaim_connection
*gc
) {
375 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
376 icq_KeepAlive(id
->link
);
379 static void icq_add_buddy(struct gaim_connection
*gc
, char *who
) {
380 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
381 icq_ContactAdd(id
->link
, atol(who
));
382 icq_ContactSetVis(id
->link
, atol(who
), TRUE
);
385 static void icq_add_buddies(struct gaim_connection
*gc
, GList
*whos
) {
386 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
388 icq_ContactAdd(id
->link
, atol(whos
->data
));
389 icq_ContactSetVis(id
->link
, atol(whos
->data
), TRUE
);
394 static void icq_rem_buddy(struct gaim_connection
*gc
, char *who
, char *group
) {
395 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
396 icq_ContactRemove(id
->link
, atol(who
));
399 static void icq_set_away(struct gaim_connection
*gc
, char *state
, char *msg
) {
400 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
405 if (!strcmp(state
, "Online"))
406 icq_ChangeStatus(id
->link
, STATUS_ONLINE
);
407 else if (!strcmp(state
, "Away")) {
408 icq_ChangeStatus(id
->link
, STATUS_AWAY
);
410 } else if (!strcmp(state
, "Do Not Disturb")) {
411 icq_ChangeStatus(id
->link
, STATUS_DND
);
413 } else if (!strcmp(state
, "Not Available")) {
414 icq_ChangeStatus(id
->link
, STATUS_NA
);
416 } else if (!strcmp(state
, "Occupied")) {
417 icq_ChangeStatus(id
->link
, STATUS_OCCUPIED
);
419 } else if (!strcmp(state
, "Free For Chat")) {
420 icq_ChangeStatus(id
->link
, STATUS_FREE_CHAT
);
422 } else if (!strcmp(state
, "Invisible")) {
423 icq_ChangeStatus(id
->link
, STATUS_INVISIBLE
);
425 } else if (!strcmp(state
, GAIM_AWAY_CUSTOM
)) {
427 icq_ChangeStatus(id
->link
, STATUS_NA
);
430 icq_ChangeStatus(id
->link
, STATUS_ONLINE
);
435 static char **icq_list_icon(int uc
) {
438 return icon_online_xpm
;
440 if (status
& STATUS_NA
)
442 if (status
& STATUS_DND
)
444 if (status
& STATUS_OCCUPIED
)
446 if (status
& STATUS_AWAY
)
447 return icon_away_xpm
;
448 if (status
& STATUS_FREE_CHAT
)
450 if (status
& STATUS_INVISIBLE
)
452 return icon_online_xpm
;
455 static void icq_get_info(struct gaim_connection
*gc
, char *who
) {
456 struct icq_data
*id
= (struct icq_data
*)gc
->proto_data
;
457 icq_SendInfoReq(id
->link
, atol(who
));
460 static void icq_info(struct gaim_connection
*gc
, char *who
) {
461 serv_get_info(gc
, who
);
464 static GList
*icq_buddy_menu(struct gaim_connection
*gc
, char *who
) {
466 struct proto_buddy_menu
*pbm
;
468 pbm
= g_new0(struct proto_buddy_menu
, 1);
469 pbm
->label
= _("Get Info");
470 pbm
->callback
= icq_info
;
472 m
= g_list_append(m
, pbm
);
477 static GList
*icq_user_opts() {
479 struct proto_user_opt
*puo
;
481 puo
= g_new0(struct proto_user_opt
, 1);
482 puo
->label
= "Nick:";
483 puo
->def
= "Gaim User";
484 puo
->pos
= USEROPT_NICK
;
485 m
= g_list_append(m
, puo
);
490 static GList
*icq_away_states(struct gaim_connection
*gc
) {
493 m
= g_list_append(m
, "Online");
494 m
= g_list_append(m
, "Away");
495 m
= g_list_append(m
, "Do Not Disturb");
496 m
= g_list_append(m
, "Not Available");
497 m
= g_list_append(m
, "Occupied");
498 m
= g_list_append(m
, "Free For Chat");
499 m
= g_list_append(m
, "Invisible");
504 static struct prpl
*my_protocol
= NULL
;
506 void icq_init(struct prpl
*ret
) {
507 ret
->protocol
= PROTO_ICQ
;
508 ret
->name
= icq_name
;
509 ret
->list_icon
= icq_list_icon
;
510 ret
->away_states
= icq_away_states
;
511 ret
->buddy_menu
= icq_buddy_menu
;
512 ret
->user_opts
= icq_user_opts
;
513 ret
->login
= icq_login
;
514 ret
->close
= icq_close
;
515 ret
->send_im
= icq_send_msg
;
516 ret
->add_buddy
= icq_add_buddy
;
517 ret
->add_buddies
= icq_add_buddies
;
518 ret
->remove_buddy
= icq_rem_buddy
;
519 ret
->get_info
= icq_get_info
;
520 ret
->set_away
= icq_set_away
;
521 ret
->keepalive
= icq_keepalive
;
525 icq_SocketNotify
= icq_sock_notify
;
526 icq_SetTimeout
= icq_set_timeout
;
531 char *gaim_plugin_init(GModule
*handle
)
533 load_protocol(icq_init
, sizeof(struct prpl
));
537 void gaim_plugin_remove()
539 struct prpl
*p
= find_prpl(PROTO_ICQ
);
540 if (p
== my_protocol
)
551 return PRPL_DESC("ICQ");