1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
5 * Copyright (C) 1998-2001, Mark Spencer <markster@marko.net>
6 * Some code borrowed from GtkZephyr, by
7 * Jag/Sean Dilda <agrajag@linuxpower.org>/<smdilda@unity.ncsu.edu>
8 * http://gtkzephyr.linuxpower.org/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include "zephyr/zephyr.h"
37 extern Code_t
ZGetLocations(ZLocations_t
*, int *);
38 extern Code_t
ZSetLocation(char *);
39 extern Code_t
ZUnsetLocation();
41 typedef struct _zframe zframe
;
42 typedef struct _zephyr_triple zephyr_triple
;
44 /* struct I need for zephyr_to_html */
46 /* true for everything but @color, since inside the parens of that one is
49 /* </i>, </font>, </b>, etc. */
51 /* text including the opening html thingie. */
53 struct _zframe
*enclosing
;
56 struct _zephyr_triple
{
65 #define z_call(func) if (func != ZERR_NONE)\
67 #define z_call_r(func) if (func != ZERR_NONE)\
69 #define z_call_s(func, err) if (func != ZERR_NONE) {\
70 hide_login_progress(zgc, err);\
75 static char *zephyr_normalize(const char *);
77 /* this is so bad, and if Zephyr weren't so fucked up to begin with I
78 * wouldn't do this. but it is so i will. */
79 static guint32 nottimer
= 0;
80 static guint32 loctimer
= 0;
81 struct gaim_connection
*zgc
= NULL
;
82 static GList
*pending_zloc_names
= NULL
;
83 static GSList
*subscrips
= NULL
;
84 static int last_id
= 0;
87 static void handle_unknown(ZNotice_t notice)
89 debug_printf("z_packet: %s\n", notice.z_packet);
90 debug_printf("z_version: %s\n", notice.z_version);
91 debug_printf("z_kind: %d\n", notice.z_kind);
92 debug_printf("z_class: %s\n", notice.z_class);
93 debug_printf("z_class_inst: %s\n", notice.z_class_inst);
94 debug_printf("z_opcode: %s\n", notice.z_opcode);
95 debug_printf("z_sender: %s\n", notice.z_sender);
96 debug_printf("z_recipient: %s\n", notice.z_recipient);
97 debug_printf("z_message: %s\n", notice.z_message);
98 debug_printf("z_message_len: %d\n", notice.z_message_len);
103 static zephyr_triple
*new_triple(const char *c
, const char *i
, const char *r
)
106 zt
= g_new0(zephyr_triple
, 1);
107 zt
->class = g_strdup(c
);
108 zt
->instance
= g_strdup(i
);
109 zt
->recipient
= g_strdup(r
);
110 zt
->name
= g_strdup_printf("%s,%s,%s", c
, i
, r
);
116 static void free_triple(zephyr_triple
*zt
)
119 g_free(zt
->instance
);
120 g_free(zt
->recipient
);
125 /* returns true if zt1 is a subset of zt2, i.e. zt2 has the same thing or
126 * wildcards in each field of zt1. */
127 static gboolean
triple_subset(zephyr_triple
*zt1
, zephyr_triple
*zt2
)
129 if (g_ascii_strcasecmp(zt2
->class, zt1
->class) &&
130 g_ascii_strcasecmp(zt2
->class, "*")) {
133 if (g_ascii_strcasecmp(zt2
->instance
, zt1
->instance
) &&
134 g_ascii_strcasecmp(zt2
->instance
, "*")) {
137 if (g_ascii_strcasecmp(zt2
->recipient
, zt1
->recipient
) &&
138 g_ascii_strcasecmp(zt2
->recipient
, "*")) {
144 static zephyr_triple
*find_sub_by_triple(zephyr_triple
*zt
)
146 zephyr_triple
*curr_t
;
147 GSList
*curr
= subscrips
;
150 if (triple_subset(zt
, curr_t
))
157 static zephyr_triple
*find_sub_by_id(int id
)
160 GSList
*curr
= subscrips
;
170 /* utility macros that are useful for zephyr_to_html */
172 #define IS_OPENER(c) ((c == '{') || (c == '[') || (c == '(') || (c == '<'))
173 #define IS_CLOSER(c) ((c == '}') || (c == ']') || (c == ')') || (c == '>'))
175 /* this parses zephyr formatting and converts it to html. For example, if
176 * you pass in "@{@color(blue)@i(hello)}" you should get out
177 * "<font color=blue><i>hello</i></font>". */
178 static char *zephyr_to_html(char *message
)
181 zframe
*frames
, *curr
;
184 frames
= g_new(zframe
, 1);
185 frames
->text
= g_string_new("");
186 frames
->enclosing
= NULL
;
187 frames
->closing
= "";
188 frames
->has_closer
= FALSE
;
190 len
= strlen(message
);
193 if (message
[cnt
] == '@') {
197 for (end
=1; (cnt
+end
) <= len
&&
198 !IS_OPENER(message
[cnt
+end
]); end
++);
199 buf
= g_new0(char, end
);
201 g_snprintf(buf
, end
, "%s", message
+cnt
+1);
203 if (!g_ascii_strcasecmp(buf
, "italic") ||
204 !g_ascii_strcasecmp(buf
, "i")) {
205 new_f
= g_new(zframe
, 1);
206 new_f
->enclosing
= frames
;
207 new_f
->text
= g_string_new("<i>");
208 new_f
->closing
= "</i>";
209 new_f
->has_closer
= TRUE
;
211 cnt
+= end
+1; /* cnt points to char after opener */
212 } else if (!g_ascii_strcasecmp(buf
, "bold")
213 || !g_ascii_strcasecmp(buf
, "b")) {
214 new_f
= g_new(zframe
, 1);
215 new_f
->enclosing
= frames
;
216 new_f
->text
= g_string_new("<b>");
217 new_f
->closing
= "</b>";
218 new_f
->has_closer
= TRUE
;
221 } else if (!g_ascii_strcasecmp(buf
, "color")) {
223 new_f
= g_new(zframe
, 1);
224 new_f
->enclosing
= frames
;
225 new_f
->text
= g_string_new("<font color=");
226 for (; (cnt
<= len
) && !IS_CLOSER(message
[cnt
]); cnt
++) {
227 g_string_append_c(new_f
->text
, message
[cnt
]);
229 cnt
++; /* point to char after closer */
230 g_string_append_c(new_f
->text
, '>');
231 new_f
->closing
= "</font>";
232 new_f
->has_closer
= FALSE
;
234 } else if (!g_ascii_strcasecmp(buf
, "")) {
235 new_f
= g_new(zframe
, 1);
236 new_f
->enclosing
= frames
;
237 new_f
->text
= g_string_new("");
239 new_f
->has_closer
= TRUE
;
241 cnt
+= end
+1; /* cnt points to char after opener */
243 if ((cnt
+end
) > len
) {
244 g_string_append_c(frames
->text
, '@');
247 /* unrecognized thingie. act like it's not there, but we
248 * still need to take care of the corresponding closer,
249 * make a frame that does nothing. */
250 new_f
= g_new(zframe
, 1);
251 new_f
->enclosing
= frames
;
252 new_f
->text
= g_string_new("");
254 new_f
->has_closer
= TRUE
;
256 cnt
+= end
+1; /* cnt points to char after opener */
259 } else if (IS_CLOSER(message
[cnt
])) {
261 gboolean last_had_closer
;
262 if (frames
->enclosing
) {
265 frames
= frames
->enclosing
;
266 g_string_append(frames
->text
, popped
->text
->str
);
267 g_string_append(frames
->text
, popped
->closing
);
268 g_string_free(popped
->text
, TRUE
);
269 last_had_closer
= popped
->has_closer
;
271 } while (frames
&& frames
->enclosing
&& !last_had_closer
);
273 g_string_append_c(frames
->text
, message
[cnt
]);
276 } else if (message
[cnt
] == '\n') {
277 g_string_append(frames
->text
, "<br>");
280 g_string_append_c(frames
->text
, message
[cnt
++]);
283 /* go through all the stuff that they didn't close */
284 while (frames
->enclosing
) {
286 g_string_append(frames
->enclosing
->text
, frames
->text
->str
);
287 g_string_append(frames
->enclosing
->text
, frames
->closing
);
288 g_string_free(frames
->text
, TRUE
);
289 frames
= frames
->enclosing
;
292 ret
= frames
->text
->str
;
293 g_string_free(frames
->text
, FALSE
);
298 static gboolean
pending_zloc(char *who
)
301 for (curr
= pending_zloc_names
; curr
!= NULL
; curr
= curr
->next
) {
302 if (!g_ascii_strcasecmp(who
, (char*)curr
->data
)) {
303 g_free((char*)curr
->data
);
304 pending_zloc_names
= g_list_remove(pending_zloc_names
, curr
->data
);
311 static void handle_message(ZNotice_t notice
, struct sockaddr_in from
)
313 if (!g_ascii_strcasecmp(notice
.z_class
, LOGIN_CLASS
)) {
314 /* well, we'll be updating in 20 seconds anyway, might as well ignore this. */
315 } else if (!g_ascii_strcasecmp(notice
.z_class
, LOCATE_CLASS
)) {
316 if (!g_ascii_strcasecmp(notice
.z_opcode
, LOCATE_LOCATE
)) {
321 if (ZParseLocations(¬ice
, NULL
, &nlocs
, &user
) != ZERR_NONE
)
323 if ((b
= gaim_find_buddy(zgc
->account
, user
)) == NULL
) {
324 char *e
= strchr(user
, '@');
326 b
= gaim_find_buddy(zgc
->account
, user
);
332 if (pending_zloc(b
->name
)) {
335 GString
*str
= g_string_new("");
336 g_string_append_printf(str
, "<b>User:</b> %s<br>"
337 "<b>Alias:</b> %s<br>",
340 g_string_append_printf(str
, "<br>Hidden or not logged-in");
342 for (; nlocs
> 0; nlocs
--) {
343 ZGetLocations(&locs
, &one
);
344 g_string_append_printf(str
, "<br>At %s since %s", locs
.host
,
347 g_show_info_text(NULL
, NULL
, 2, str
->str
, NULL
);
348 g_string_free(str
, TRUE
);
350 serv_got_update(zgc
, b
->name
, nlocs
, 0, 0, 0, 0);
359 char *ptr
= notice
.z_message
+ strlen(notice
.z_message
) + 1;
360 int len
= notice
.z_message_len
- (ptr
- notice
.z_message
);
363 buf
= g_malloc(len
+ 1);
364 g_snprintf(buf
, len
+ 1, "%s", ptr
);
366 buf2
= zephyr_to_html(buf
);
368 if (!g_ascii_strcasecmp(notice
.z_class
, "MESSAGE") &&
369 !g_ascii_strcasecmp(notice
.z_class_inst
, "PERSONAL")) {
370 if (!g_ascii_strcasecmp(notice
.z_message
, "Automated reply:"))
374 serv_got_im(zgc
, notice
.z_sender
, buf2
, 0, time(NULL
), -1);
376 zephyr_triple
*zt1
, *zt2
;
377 zt1
= new_triple(notice
.z_class
, notice
.z_class_inst
,
379 zt2
= find_sub_by_triple(zt1
);
381 /* we shouldn't be subscribed to this message. ignore. */
385 serv_got_joined_chat(zgc
, zt2
->id
, zt2
->name
);
387 /* If the person is in the default Realm, then strip the
388 Realm from the sender field */
389 sendertmp
= g_strdup_printf("%s",notice
.z_sender
);
390 if ((realmptr
= strchr(sendertmp
,'@')) != NULL
) {
392 if (!g_ascii_strcasecmp(realmptr
,ZGetRealm())) {
394 sprintf(realmptr
,"%c",'\0');
395 send_inst
= g_strdup_printf("%s %s",sendertmp
,
396 notice
.z_class_inst
);
398 send_inst
= g_strdup_printf("%s %s",notice
.z_sender
,
399 notice
.z_class_inst
);
402 send_inst
= g_strdup_printf("%s %s",sendertmp
,notice
.z_class_inst
);
404 serv_got_chat_in(zgc
, zt2
->id
, send_inst
, FALSE
,
416 static gint
check_notify(gpointer data
)
420 struct sockaddr_in from
;
421 z_call_r(ZReceiveNotice(¬ice
, &from
));
423 switch (notice
.z_kind
) {
427 handle_message(notice
, from
);
430 /* we'll just ignore things for now */
431 debug_printf("ZEPHYR: Unhandled Notice\n");
435 ZFreeNotice(¬ice
);
441 static gint
check_loc(gpointer data
)
443 GaimBlistNode
*gnode
,*bnode
;
444 ZAsyncLocateData_t ald
;
447 memset(&(ald
.uid
), 0, sizeof(ZUnique_Id_t
));
450 for(gnode
= gaim_get_blist()->root
; gnode
; gnode
= gnode
->next
) {
451 if(!GAIM_BLIST_NODE_IS_GROUP(gnode
))
453 for(bnode
= gnode
->child
; bnode
; bnode
= bnode
->next
) {
454 struct buddy
*b
= (struct buddy
*)bnode
;
455 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode
))
457 if(b
->account
->gc
== zgc
) {
459 chk
= zephyr_normalize(b
->name
);
460 /* doesn't matter if this fails or not; we'll just move on to the next one */
461 ZRequestLocations(chk
, &ald
, UNACKED
, ZAUTH
);
471 static char *get_exposure_level()
473 char *exposure
= ZGetVariable("exposure");
476 return EXPOSE_REALMVIS
;
477 if (!g_ascii_strcasecmp(exposure
, EXPOSE_NONE
))
479 if (!g_ascii_strcasecmp(exposure
, EXPOSE_OPSTAFF
))
480 return EXPOSE_OPSTAFF
;
481 if (!g_ascii_strcasecmp(exposure
, EXPOSE_REALMANN
))
482 return EXPOSE_REALMANN
;
483 if (!g_ascii_strcasecmp(exposure
, EXPOSE_NETVIS
))
484 return EXPOSE_NETVIS
;
485 if (!g_ascii_strcasecmp(exposure
, EXPOSE_NETANN
))
486 return EXPOSE_NETANN
;
487 return EXPOSE_REALMVIS
;
490 static void strip_comments(char *str
)
492 char *tmp
= strchr(str
, '#');
499 static void process_zsubs()
505 fname
= g_strdup_printf("%s/.zephyr.subs", gaim_home_dir());
506 f
= fopen(fname
, "r");
511 while (fgets(buff
, BUFSIZ
, f
)) {
512 strip_comments(buff
);
514 triple
= g_strsplit(buff
, ",", 3);
515 if (triple
[0] && triple
[1] ) {
516 /* char *tmp = g_strdup_printf("%s@%s", g_getenv("USER"),
518 char *tmp
= g_strdup_printf("%s",ZGetSender());
520 sub
.zsub_class
= triple
[0];
521 sub
.zsub_classinst
= triple
[1];
522 if(triple
[2] == NULL
) {
523 recip
= g_malloc0(1);
524 } else if (!g_ascii_strcasecmp(triple
[2], "%me%")) {
525 recip
= g_strdup_printf("%s",ZGetSender());
526 } else if (!g_ascii_strcasecmp(triple
[2], "*")) {
528 * form of class,instance,* */
529 recip
= g_malloc0(1);
530 } else if (!g_ascii_strcasecmp(triple
[2], tmp
)) {
531 /* form of class,instance,aatharuv@ATHENA.MIT.EDU */
532 recip
= g_strdup(triple
[2]);
533 } else if ((atptr
= strchr(triple
[2], '@')) != NULL
) {
534 /* form of class,instance,*@ANDREW.CMU.EDU
535 * class,instance,@ANDREW.CMU.EDU
536 * If realm is local realm, blank recipient, else
539 char *realmat
= g_strdup_printf("@%s", ZGetRealm());
540 if (!g_ascii_strcasecmp(atptr
, realmat
))
541 recip
= g_malloc0(1);
543 recip
= g_strdup(atptr
);
546 recip
= g_strdup(triple
[2]);
549 sub
.zsub_recipient
= recip
;
550 if (ZSubscribeTo(&sub
, 1, 0) != ZERR_NONE
) {
551 debug_printf("Zephyr: Couldn't subscribe to %s, %s, "
557 subscrips
= g_slist_append(subscrips
,
558 new_triple(triple
[0], triple
[1], recip
));
567 static void process_anyone()
570 gchar buff
[BUFSIZ
], *filename
;
574 if (!(g
= gaim_find_group(_("Anyone")))) {
575 g
= gaim_group_new(_("Anyone"));
576 gaim_blist_add_group(g
, NULL
);
579 filename
= g_strconcat(gaim_home_dir(), "/.anyone", NULL
);
580 if ((fd
= fopen(filename
, "r")) != NULL
) {
581 while (fgets(buff
, BUFSIZ
, fd
)) {
582 strip_comments(buff
);
584 b
= gaim_buddy_new(zgc
->account
, buff
, NULL
);
585 gaim_blist_add_buddy(b
, g
, NULL
);
593 static void zephyr_login(struct gaim_account
*account
)
598 do_error_dialog("Already logged in with Zephyr", "Because Zephyr uses your system username, you are unable to "
599 "have multiple accounts on it when logged in as the same user.", GAIM_ERROR
);
603 zgc
= new_gaim_conn(account
);
605 z_call_s(ZInitialize(), "Couldn't initialize zephyr");
606 z_call_s(ZOpenPort(NULL
), "Couldn't open port");
607 z_call_s(ZSetLocation(get_exposure_level()), "Couldn't set location");
609 sub
.zsub_class
= "MESSAGE";
610 sub
.zsub_classinst
= "PERSONAL";
611 sub
.zsub_recipient
= ZGetSender();
613 /* we don't care if this fails. i'm lying right now. */
614 if (ZSubscribeTo(&sub
, 1, 0) != ZERR_NONE
) {
615 debug_printf("Zephyr: Couldn't subscribe to messages!\n");
619 serv_finish_login(zgc
);
624 nottimer
= g_timeout_add(100, check_notify
, NULL
);
625 loctimer
= g_timeout_add(20000, check_loc
, NULL
);
628 static void write_zsubs()
630 GSList
*s
= subscrips
;
636 fname
= g_strdup_printf("%s/.zephyr.subs", gaim_home_dir());
637 fd
= fopen(fname
, "w");
646 triple
= g_strsplit(zt
->name
,",",3);
647 if (triple
[2] != NULL
) {
648 if (!g_ascii_strcasecmp(triple
[2], "")) {
649 fprintf(fd
, "%s,%s,*\n", triple
[0], triple
[1]);
650 } else if (!g_ascii_strcasecmp(triple
[2], ZGetSender())) {
651 fprintf(fd
, "%s,%s,%%me%%\n",triple
[0],triple
[1]);
653 fprintf(fd
, "%s\n", zt
->name
);
656 fprintf(fd
, "%s,%s,*\n",triple
[0], triple
[1]);
665 static void write_anyone()
667 GaimBlistNode
*gnode
,*bnode
;
669 char *ptr
, *fname
, *ptr2
;
672 fname
= g_strdup_printf("%s/.anyone", gaim_home_dir());
673 fd
= fopen(fname
, "w");
679 for(gnode
= gaim_get_blist()->root
; gnode
; gnode
= gnode
->next
) {
680 if(!GAIM_BLIST_NODE_IS_GROUP(gnode
))
682 for(bnode
= gnode
->child
; bnode
; bnode
= bnode
->next
) {
683 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode
))
685 b
= (struct buddy
*)bnode
;
686 if(b
->account
->gc
== zgc
) {
687 if ((ptr
= strchr(b
->name
, '@')) != NULL
) {
689 /* We should only strip the realm name if the principal
690 is in the user's realm
692 if (!g_ascii_strcasecmp(ptr2
,ZGetRealm())) {
696 fprintf(fd
, "%s\n", b
->name
);
707 static void zephyr_close(struct gaim_connection
*gc
)
711 l
= pending_zloc_names
;
713 g_free((char*)l
->data
);
716 g_list_free(pending_zloc_names
);
723 free_triple((zephyr_triple
*)s
->data
);
726 g_slist_free(subscrips
);
729 g_source_remove(nottimer
);
732 g_source_remove(loctimer
);
735 z_call(ZCancelSubscriptions(0));
736 z_call(ZUnsetLocation());
737 z_call(ZClosePort());
740 static void zephyr_add_buddy(struct gaim_connection
*gc
, const char *buddy
) { }
741 static void zephyr_remove_buddy(struct gaim_connection
*gc
, char *buddy
, char *group
) { }
743 static int zephyr_chat_send(struct gaim_connection
*gc
, int id
, char *im
)
750 zt
= find_sub_by_id(id
);
752 /* this should never happen. */
755 sig
= ZGetVariable("zwrite-signature");
757 sig
= g_get_real_name();
759 buf
= g_strdup_printf("%s%c%s", sig
, '\0', im
);
761 bzero((char *)¬ice
, sizeof(notice
));
762 notice
.z_kind
= ACKED
;
764 notice
.z_opcode
= "";
765 notice
.z_class
= zt
->class;
766 notice
.z_class_inst
= zt
->instance
;
767 if (!g_ascii_strcasecmp(zt
->recipient
, "*"))
768 notice
.z_recipient
= zephyr_normalize("");
770 notice
.z_recipient
= zephyr_normalize(zt
->recipient
);
772 notice
.z_default_format
=
773 "Class $class, Instance $instance:\n"
774 "To: @bold($recipient) at $time $date\n"
775 "From: @bold($1) <$sender>\n\n$2";
776 notice
.z_message_len
= strlen(im
) + strlen(sig
) + 4;
777 notice
.z_message
= buf
;
778 ZSendNotice(¬ice
, ZAUTH
);
783 static int zephyr_send_im(struct gaim_connection
*gc
, char *who
, char *im
, int len
, int flags
) {
788 if (flags
& IM_FLAG_AWAY
)
789 sig
= "Automated reply:";
791 sig
= ZGetVariable("zwrite-signature");
793 sig
= g_get_real_name();
796 buf
= g_strdup_printf("%s%c%s", sig
, '\0', im
);
798 bzero((char *)¬ice
, sizeof(notice
));
799 notice
.z_kind
= ACKED
;
801 notice
.z_opcode
= "";
802 notice
.z_class
= "MESSAGE";
803 notice
.z_class_inst
= "PERSONAL";
805 notice
.z_recipient
= who
;
806 notice
.z_default_format
=
807 "Class $class, Instance $instance:\n"
808 "To: @bold($recipient) at $time $date\n"
809 "From: @bold($1) <$sender>\n\n$2";
810 notice
.z_message_len
= strlen(im
) + strlen(sig
) + 4;
811 notice
.z_message
= buf
;
812 ZSendNotice(¬ice
, ZAUTH
);
817 static char *zephyr_normalize(const char *orig
)
820 if (strchr(orig
, '@')) {
821 g_snprintf(buf
, 80, "%s", orig
);
823 g_snprintf(buf
, 80, "%s@%s", orig
, ZGetRealm());
828 static void zephyr_zloc(struct gaim_connection
*gc
, char *who
)
830 ZAsyncLocateData_t ald
;
832 if (ZRequestLocations(zephyr_normalize(who
), &ald
, UNACKED
, ZAUTH
)
836 pending_zloc_names
= g_list_append(pending_zloc_names
,
837 g_strdup(zephyr_normalize(who
)));
840 static GList
*zephyr_buddy_menu(struct gaim_connection
*gc
, char *who
)
843 struct proto_buddy_menu
*pbm
;
845 pbm
= g_new0(struct proto_buddy_menu
, 1);
846 pbm
->label
= _("ZLocate");
847 pbm
->callback
= zephyr_zloc
;
849 m
= g_list_append(m
, pbm
);
854 static void zephyr_set_away(struct gaim_connection
*gc
, char *state
, char *msg
)
861 if (!g_ascii_strcasecmp(state
, "Hidden")) {
862 ZSetLocation(EXPOSE_OPSTAFF
);
863 gc
->away
= g_strdup("");
864 } else if (!g_ascii_strcasecmp(state
, "Online"))
865 ZSetLocation(get_exposure_level());
866 else /* state is GAIM_AWAY_CUSTOM */ if (msg
)
867 gc
->away
= g_strdup(msg
);
870 static GList
*zephyr_away_states(struct gaim_connection
*gc
)
874 m
= g_list_append(m
, "Online");
875 m
= g_list_append(m
, GAIM_AWAY_CUSTOM
);
876 m
= g_list_append(m
, "Hidden");
881 static GList
*zephyr_chat_info(struct gaim_connection
*gc
) {
883 struct proto_chat_entry
*pce
;
885 pce
= g_new0(struct proto_chat_entry
, 1);
886 pce
->label
= _("Class:");
887 m
= g_list_append(m
, pce
);
889 pce
= g_new0(struct proto_chat_entry
, 1);
890 pce
->label
= _("Instance:");
891 m
= g_list_append(m
, pce
);
893 pce
= g_new0(struct proto_chat_entry
, 1);
894 pce
->label
= _("Recipient:");
895 m
= g_list_append(m
, pce
);
900 static void zephyr_join_chat(struct gaim_connection
*gc
, GList
*data
)
903 zephyr_triple
*zt1
, *zt2
;
904 const char *classname
;
905 const char *instname
;
908 if (!data
|| !data
->next
|| !data
->next
->next
)
911 classname
= data
->data
;
912 instname
= data
->next
->data
;
913 recip
= data
->next
->next
->data
;
914 if (!g_ascii_strcasecmp(recip
, "%me%"))
915 recip
= ZGetSender();
917 zt1
= new_triple(classname
, instname
, recip
);
918 zt2
= find_sub_by_triple(zt1
);
922 serv_got_joined_chat(gc
, zt2
->id
, zt2
->name
);
926 sub
.zsub_class
= zt1
->class;
927 sub
.zsub_classinst
= zt1
->instance
;
928 sub
.zsub_recipient
= zt1
->recipient
;
930 if (ZSubscribeTo(&sub
, 1, 0) != ZERR_NONE
) {
935 subscrips
= g_slist_append(subscrips
, zt1
);
937 serv_got_joined_chat(gc
, zt1
->id
, zt1
->name
);
940 static void zephyr_chat_leave(struct gaim_connection
*gc
, int id
)
943 zt
= find_sub_by_id(id
);
950 static struct prpl
*my_protocol
= NULL
;
952 void zephyr_init(struct prpl
*ret
)
954 ret
->protocol
= PROTO_ZEPHYR
;
955 ret
->options
= OPT_PROTO_NO_PASSWORD
;
956 ret
->name
= g_strdup("Zephyr");
957 ret
->login
= zephyr_login
;
958 ret
->close
= zephyr_close
;
959 ret
->add_buddy
= zephyr_add_buddy
;
960 ret
->remove_buddy
= zephyr_remove_buddy
;
961 ret
->send_im
= zephyr_send_im
;
962 ret
->get_info
= zephyr_zloc
;
963 ret
->normalize
= zephyr_normalize
;
964 ret
->buddy_menu
= zephyr_buddy_menu
;
965 ret
->away_states
= zephyr_away_states
;
966 ret
->set_away
= zephyr_set_away
;
967 ret
->chat_info
= zephyr_chat_info
;
968 ret
->join_chat
= zephyr_join_chat
;
969 ret
->chat_send
= zephyr_chat_send
;
970 ret
->chat_leave
= zephyr_chat_leave
;
977 G_MODULE_EXPORT
void gaim_prpl_init(struct prpl
*prpl
)
980 prpl
->plug
->desc
.api_version
= PLUGIN_API_VERSION
;