plugins/zephyr/zephyr.c

changeset 1726
a3710e1b3667
parent 1719
faf919a930fb
child 1764
d8c1affb29fe
equal deleted inserted replaced
1725:bb10398450f8 1726:a3710e1b3667
31 #include <string.h> 31 #include <string.h>
32 #include "gaim.h" 32 #include "gaim.h"
33 #include "prpl.h" 33 #include "prpl.h"
34 #include "zephyr/zephyr.h" 34 #include "zephyr/zephyr.h"
35 35
36 typedef struct _zframe zframe;
37
38 /* struct I need for zephyr_to_html */
39 struct _zframe {
40 /* true for everything but @color, since inside the parens of that one is
41 * the color. */
42 gboolean has_closer;
43 /* </i>, </font>, </b>, etc. */
44 char *closing;
45 /* text including the opening html thingie. */
46 GString *text;
47 struct _zframe *enclosing;
48 };
49
36 char *name() 50 char *name()
37 { 51 {
38 return "Zephyr"; 52 return "Zephyr";
39 } 53 }
40 54
55 #define z_call_s(func, err) if (func != ZERR_NONE) {\ 69 #define z_call_s(func, err) if (func != ZERR_NONE) {\
56 hide_login_progress(zgc, err);\ 70 hide_login_progress(zgc, err);\
57 signoff(zgc);\ 71 signoff(zgc);\
58 return;\ 72 return;\
59 } 73 }
74
75 static char *zephyr_normalize(const char *);
60 76
61 /* this is so bad, and if Zephyr weren't so fucked up to begin with I 77 /* this is so bad, and if Zephyr weren't so fucked up to begin with I
62 * wouldn't do this. but it is so i will. */ 78 * wouldn't do this. but it is so i will. */
63 static guint32 nottimer = 0; 79 static guint32 nottimer = 0;
64 static guint32 loctimer = 0; 80 static guint32 loctimer = 0;
80 g_print("z_message_len: %d\n", notice.z_message_len); 96 g_print("z_message_len: %d\n", notice.z_message_len);
81 g_print("\n"); 97 g_print("\n");
82 } 98 }
83 */ 99 */
84 100
85 static char *zephyr_normalize(const char *orig) 101 /* utility macros that are useful for zephyr_to_html */
86 { 102
87 static char buf[80]; 103 #define IS_OPENER(c) ((c == '{') || (c == '[') || (c == '(') || (c == '<'))
88 if (strchr(orig, '@')) { 104 #define IS_CLOSER(c) ((c == '}') || (c == ']') || (c == ')') || (c == '>'))
89 g_snprintf(buf, 80, "%s", orig); 105
90 } else { 106 /* this parses zephyr formatting and converts it to html. For example, if
91 g_snprintf(buf, 80, "%s@%s", orig, ZGetRealm()); 107 * you pass in "@{@color(blue)@i(hello)}" you should get out
92 } 108 * "<font color=blue><i>hello</i></font>". */
93 return buf; 109 static char *zephyr_to_html(char *message)
110 {
111 int len, cnt;
112 zframe *frames, *curr;
113 char *ret;
114
115 frames = g_new(zframe, 1);
116 frames->text = g_string_new("");
117 frames->enclosing = NULL;
118 frames->closing = "";
119 frames->has_closer = FALSE;
120
121 len = strlen(message);
122 cnt = 0;
123 while (cnt <= len) {
124 if (message[cnt] == '@') {
125 zframe *new_f;
126 char *buf;
127 int end;
128 for (end=1; (cnt+end) <= len &&
129 !IS_OPENER(message[cnt+end]); end++);
130 buf = g_new0(char, end);
131 if (end) {
132 g_snprintf(buf, end, "%s", message+cnt+1);
133 }
134 if (!g_strcasecmp(buf, "italic") ||
135 !g_strcasecmp(buf, "i")) {
136 new_f = g_new(zframe, 1);
137 new_f->enclosing = frames;
138 new_f->text = g_string_new("<i>");
139 new_f->closing = "</i>";
140 new_f->has_closer = TRUE;
141 frames = new_f;
142 cnt += end+1; /* cnt points to char after opener */
143 } else if (!g_strcasecmp(buf, "bold")
144 || !g_strcasecmp(buf, "b")) {
145 new_f = g_new(zframe, 1);
146 new_f->enclosing = frames;
147 new_f->text = g_string_new("<b>");
148 new_f->closing = "</b>";
149 new_f->has_closer = TRUE;
150 frames = new_f;
151 cnt += end+1;
152 } else if (!g_strcasecmp(buf, "color")) {
153 cnt += end+1;
154 new_f = g_new(zframe, 1);
155 new_f->enclosing = frames;
156 new_f->text = g_string_new("<font color=");
157 for (; (cnt <= len) && !IS_CLOSER(message[cnt]); cnt++) {
158 g_string_append_c(new_f->text, message[cnt]);
159 }
160 cnt++; /* point to char after closer */
161 g_string_append_c(new_f->text, '>');
162 new_f->closing = "</font>";
163 new_f->has_closer = FALSE;
164 frames = new_f;
165 } else if (!g_strcasecmp(buf, "")) {
166 new_f = g_new(zframe, 1);
167 new_f->enclosing = frames;
168 new_f->text = g_string_new("");
169 new_f->closing = "";
170 new_f->has_closer = TRUE;
171 frames = new_f;
172 cnt += end+1; /* cnt points to char after opener */
173 } else {
174 if ((cnt+end) > len) {
175 g_string_append_c(frames->text, '@');
176 cnt++;
177 } else {
178 /* unrecognized thingie. act like it's not there, but we
179 * still need to take care of the corresponding closer,
180 * make a frame that does nothing. */
181 new_f = g_new(zframe, 1);
182 new_f->enclosing = frames;
183 new_f->text = g_string_new("");
184 new_f->closing = "";
185 new_f->has_closer = TRUE;
186 frames = new_f;
187 cnt += end+1; /* cnt points to char after opener */
188 }
189 }
190 } else if (IS_CLOSER(message[cnt])) {
191 zframe *popped;
192 gboolean last_had_closer;
193 if (frames->enclosing) {
194 do {
195 popped = frames;
196 frames = frames->enclosing;
197 g_string_append(frames->text, popped->text->str);
198 g_string_append(frames->text, popped->closing);
199 g_string_free(popped->text, TRUE);
200 last_had_closer = popped->has_closer;
201 g_free(popped);
202 } while (frames && frames->enclosing && !last_had_closer);
203 } else {
204 g_string_append_c(frames->text, message[cnt]);
205 }
206 cnt++;
207 } else if (message[cnt] == '\n') {
208 g_string_append(frames->text, "<br>");
209 cnt++;
210 } else {
211 g_string_append_c(frames->text, message[cnt++]);
212 }
213 }
214 /* go through all the stuff that they didn't close */
215 while (frames->enclosing) {
216 curr = frames;
217 g_string_append(frames->enclosing->text, frames->text->str);
218 g_string_append(frames->enclosing->text, frames->closing);
219 g_string_free(frames->text, TRUE);
220 frames = frames->enclosing;
221 g_free(curr);
222 }
223 ret = frames->text->str;
224 g_string_free(frames->text, FALSE);
225 g_free(frames);
226 return ret;
94 } 227 }
95 228
96 static gboolean pending_zloc(char *who) 229 static gboolean pending_zloc(char *who)
97 { 230 {
98 GList *curr; 231 GList *curr;
102 pending_zloc_names = g_list_remove(pending_zloc_names, curr->data); 235 pending_zloc_names = g_list_remove(pending_zloc_names, curr->data);
103 return TRUE; 236 return TRUE;
104 } 237 }
105 } 238 }
106 return FALSE; 239 return FALSE;
107 }
108
109 static void zephyr_zloc(struct gaim_connection *gc, char *who)
110 {
111 ZAsyncLocateData_t ald;
112
113 if (ZRequestLocations(zephyr_normalize(who), &ald, UNACKED, ZAUTH)
114 != ZERR_NONE) {
115 return;
116 }
117 pending_zloc_names = g_list_append(pending_zloc_names,
118 g_strdup(zephyr_normalize(who)));
119 }
120
121 static void info_callback(GtkObject *obj, char *who)
122 {
123 zephyr_zloc(gtk_object_get_user_data(obj), who);
124 }
125
126 static void zephyr_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who)
127 {
128 GtkWidget *button;
129
130 button = gtk_menu_item_new_with_label(_("ZLocate"));
131 gtk_signal_connect(GTK_OBJECT(button), "activate",
132 GTK_SIGNAL_FUNC(info_callback), who);
133 gtk_object_set_user_data(GTK_OBJECT(button), gc);
134 gtk_menu_append(GTK_MENU(menu), button);
135 gtk_widget_show(button);
136 } 240 }
137 241
138 static void handle_message(ZNotice_t notice, struct sockaddr_in from) 242 static void handle_message(ZNotice_t notice, struct sockaddr_in from)
139 { 243 {
140 if (!g_strcasecmp(notice.z_class, LOGIN_CLASS)) { 244 if (!g_strcasecmp(notice.z_class, LOGIN_CLASS)) {
171 g_string_sprintfa(str, "<br>At %s since %s", locs.host, 275 g_string_sprintfa(str, "<br>At %s since %s", locs.host,
172 locs.time); 276 locs.time);
173 } 277 }
174 g_show_info_text(str->str); 278 g_show_info_text(str->str);
175 g_string_free(str, TRUE); 279 g_string_free(str, TRUE);
176 } 280 } else
177 serv_got_update(zgc, b->name, nlocs, 0, 0, 0, 0, 0); 281 serv_got_update(zgc, b->name, nlocs, 0, 0, 0, 0, 0);
178 282
179 free(user); 283 free(user);
180 } 284 }
181 } else if (!g_strcasecmp(notice.z_class, "MESSAGE")) { 285 } else {
182 char buf[BUF_LONG]; 286 char *buf, *buf2;
183 char *ptr = notice.z_message + strlen(notice.z_message) + 1; 287 char *ptr = notice.z_message + strlen(notice.z_message) + 1;
184 int len = notice.z_message_len - (ptr - notice.z_message); 288 int len = notice.z_message_len - (ptr - notice.z_message);
289 int away;
185 if (len > 0) { 290 if (len > 0) {
291 buf = g_malloc(len + 1);
186 g_snprintf(buf, len + 1, "%s", ptr); 292 g_snprintf(buf, len + 1, "%s", ptr);
187 g_strchomp(buf); 293 g_strchomp(buf);
188 serv_got_im(zgc, notice.z_sender, buf, 0); 294 buf2 = zephyr_to_html(buf);
189 } 295 g_free(buf);
190 } else { 296 if (!g_strcasecmp(notice.z_class, "MESSAGE") &&
191 /* yes. */ 297 !g_strcasecmp(notice.z_class_inst, "PERSONAL")) {
298 if (!g_strcasecmp(notice.z_message, "Automated reply:"))
299 away = TRUE;
300 else
301 away = FALSE;
302 len = MAX(BUF_LONG, strlen(buf2));
303 buf = g_malloc(len + 1);
304 g_snprintf(buf, len + 1, "%s", buf2);
305 serv_got_im(zgc, notice.z_sender, buf, 0);
306 g_free(buf);
307 }
308 g_free(buf2);
309 }
192 } 310 }
193 } 311 }
194 312
195 static gint check_notify(gpointer data) 313 static gint check_notify(gpointer data)
196 { 314 {
231 struct group *g = gr->data; 349 struct group *g = gr->data;
232 m = g->members; 350 m = g->members;
233 while (m) { 351 while (m) {
234 struct buddy *b = m->data; 352 struct buddy *b = m->data;
235 char *chk; 353 char *chk;
236 chk = g_strdup(zephyr_normalize(b->name)); 354 chk = zephyr_normalize(b->name);
237 /* doesn't matter if this fails or not; we'll just move on to the next one */ 355 /* doesn't matter if this fails or not; we'll just move on to the next one */
238 ZRequestLocations(chk, &ald, UNACKED, ZAUTH); 356 ZRequestLocations(chk, &ald, UNACKED, ZAUTH);
239 g_free(chk);
240 m = m->next; 357 m = m->next;
241 } 358 }
242 gr = gr->next; 359 gr = gr->next;
243 } 360 }
244 361
370 487
371 nottimer = gtk_timeout_add(100, check_notify, NULL); 488 nottimer = gtk_timeout_add(100, check_notify, NULL);
372 loctimer = gtk_timeout_add(2000, check_loc, NULL); 489 loctimer = gtk_timeout_add(2000, check_loc, NULL);
373 } 490 }
374 491
492 static void write_anyone()
493 {
494 GSList *gr, *m;
495 struct group *g;
496 struct buddy *b;
497 char *ptr, *fname;
498 FILE *fd;
499
500 fname = g_strdup_printf("%s/.anyone", g_get_home_dir());
501 fd = fopen(fname, "w");
502 if (!fd) {
503 g_free(fname);
504 return;
505 }
506
507 gr = zgc->groups;
508 while (gr) {
509 g = gr->data;
510 m = g->members;
511 while (m) {
512 b = m->data;
513 if ((ptr = strchr(b->name, '@')) != NULL)
514 *ptr = '\0';
515 fprintf(fd, "%s\n", b->name);
516 if (ptr)
517 *ptr = '@';
518 m = m->next;
519 }
520 gr = gr->next;
521 }
522
523 fclose(fd);
524 g_free(fname);
525 }
526
375 static void zephyr_close(struct gaim_connection *gc) 527 static void zephyr_close(struct gaim_connection *gc)
376 { 528 {
377 g_list_foreach(pending_zloc_names, (GFunc)g_free, NULL); 529 g_list_foreach(pending_zloc_names, (GFunc)g_free, NULL);
378 g_list_free(pending_zloc_names); 530 g_list_free(pending_zloc_names);
379 /* should probably write .anyone, but eh. we all use gaim exclusively, right? :-P */ 531 write_anyone();
380 if (nottimer) 532 if (nottimer)
381 gtk_timeout_remove(nottimer); 533 gtk_timeout_remove(nottimer);
382 nottimer = 0; 534 nottimer = 0;
383 if (loctimer) 535 if (loctimer)
384 gtk_timeout_remove(loctimer); 536 gtk_timeout_remove(loctimer);
395 static void zephyr_send_im(struct gaim_connection *gc, char *who, char *im, int away) { 547 static void zephyr_send_im(struct gaim_connection *gc, char *who, char *im, int away) {
396 ZNotice_t notice; 548 ZNotice_t notice;
397 char *buf; 549 char *buf;
398 char *sig; 550 char *sig;
399 551
400 sig = ZGetVariable("zwrite-signature"); 552 if (away)
401 if (!sig) { 553 sig = "Automated reply:";
402 sig = g_get_real_name(); 554 else {
555 sig = ZGetVariable("zwrite-signature");
556 if (!sig) {
557 sig = g_get_real_name();
558 }
403 } 559 }
404 buf = g_strdup_printf("%s%c%s", sig, '\0', im); 560 buf = g_strdup_printf("%s%c%s", sig, '\0', im);
405 561
406 bzero((char *)&notice, sizeof(notice)); 562 bzero((char *)&notice, sizeof(notice));
407 notice.z_kind = ACKED; 563 notice.z_kind = ACKED;
419 notice.z_message = buf; 575 notice.z_message = buf;
420 ZSendNotice(&notice, ZAUTH); 576 ZSendNotice(&notice, ZAUTH);
421 g_free(buf); 577 g_free(buf);
422 } 578 }
423 579
580 static char *zephyr_normalize(const char *orig)
581 {
582 static char buf[80];
583 if (strchr(orig, '@')) {
584 g_snprintf(buf, 80, "%s", orig);
585 } else {
586 g_snprintf(buf, 80, "%s@%s", orig, ZGetRealm());
587 }
588 return buf;
589 }
590
591 static void zephyr_zloc(struct gaim_connection *gc, char *who)
592 {
593 ZAsyncLocateData_t ald;
594
595 if (ZRequestLocations(zephyr_normalize(who), &ald, UNACKED, ZAUTH)
596 != ZERR_NONE) {
597 return;
598 }
599 pending_zloc_names = g_list_append(pending_zloc_names,
600 g_strdup(zephyr_normalize(who)));
601 }
602
603 static void info_callback(GtkObject *obj, char *who)
604 {
605 zephyr_zloc(gtk_object_get_user_data(obj), who);
606 }
607
608 static void zephyr_buddy_menu(GtkWidget *menu, struct gaim_connection *gc, char *who)
609 {
610 GtkWidget *button;
611
612 button = gtk_menu_item_new_with_label(_("ZLocate"));
613 gtk_signal_connect(GTK_OBJECT(button), "activate",
614 GTK_SIGNAL_FUNC(info_callback), who);
615 gtk_object_set_user_data(GTK_OBJECT(button), gc);
616 gtk_menu_append(GTK_MENU(menu), button);
617 gtk_widget_show(button);
618 }
619
620 static void zephyr_set_away(struct gaim_connection *gc, char *state, char *msg)
621 {
622 if (gc->away)
623 g_free(gc->away);
624 gc->away = NULL;
625 if (!g_strcasecmp(state, "Hidden"))
626 ZSetLocation(EXPOSE_OPSTAFF);
627 else if (!g_strcasecmp(state, "Online"))
628 ZSetLocation(get_exposure_level());
629 else /* state is GAIM_AWAY_CUSTOM */ if (msg)
630 gc->away = g_strdup(msg);
631 }
632
633 static GList *zephyr_away_states()
634 {
635 GList *m = NULL;
636
637 m = g_list_append(m, "Online");
638 m = g_list_append(m, GAIM_AWAY_CUSTOM);
639 m = g_list_append(m, "Hidden");
640
641 return m;
642 }
643
424 static struct prpl *my_protocol = NULL; 644 static struct prpl *my_protocol = NULL;
425 645
426 void zephyr_init(struct prpl *ret) 646 void zephyr_init(struct prpl *ret)
427 { 647 {
428 ret->protocol = PROTO_ZEPHYR; 648 ret->protocol = PROTO_ZEPHYR;
433 ret->remove_buddy = zephyr_remove_buddy; 653 ret->remove_buddy = zephyr_remove_buddy;
434 ret->send_im = zephyr_send_im; 654 ret->send_im = zephyr_send_im;
435 ret->get_info = zephyr_zloc; 655 ret->get_info = zephyr_zloc;
436 ret->normalize = zephyr_normalize; 656 ret->normalize = zephyr_normalize;
437 ret->buddy_menu = zephyr_buddy_menu; 657 ret->buddy_menu = zephyr_buddy_menu;
658 ret->away_states = zephyr_away_states;
659 ret->set_away = zephyr_set_away;
438 660
439 my_protocol = ret; 661 my_protocol = ret;
440 } 662 }
441 663
442 char *gaim_plugin_init(GModule *handle) 664 char *gaim_plugin_init(GModule *handle)

mercurial