| 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 { |
| 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); |
| 419 notice.z_message = buf; |
575 notice.z_message = buf; |
| 420 ZSendNotice(¬ice, ZAUTH); |
576 ZSendNotice(¬ice, 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; |