source: zephyr.c @ f7c0730

release-1.9
Last change on this file since f7c0730 was f7c0730, checked in by Anders Kaseorg <andersk@mit.edu>, 10 years ago
Append the realm to the zsender if missing This works around the problem where setting zsender to your username makes outgoing zephyrs become unauthenticated. It will also make things less confusing on cross-realm classes with the next commit. Signed-off-by: Anders Kaseorg <andersk@mit.edu> Reviewed-by: David Benjamin <davidben@mit.edu>
  • Property mode set to 100644
File size: 39.5 KB
Line 
1#include "owl.h"
2#include <stdio.h>
3#include <sys/stat.h>
4
5#ifdef HAVE_LIBZEPHYR
6static GSource *owl_zephyr_event_source_new(int fd);
7
8static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout);
9static gboolean owl_zephyr_event_check(GSource *source);
10static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
11
12static GList *deferred_subs = NULL;
13
14typedef struct _owl_sub_list {                            /* noproto */
15  ZSubscription_t *subs;
16  int nsubs;
17} owl_sub_list;
18
19Code_t ZResetAuthentication(void);
20
21static GSourceFuncs zephyr_event_funcs = {
22  owl_zephyr_event_prepare,
23  owl_zephyr_event_check,
24  owl_zephyr_event_dispatch,
25  NULL
26};
27#endif
28
29#define HM_SVC_FALLBACK         htons((unsigned short) 2104)
30
31static char *owl_zephyr_dotfile(const char *name, const char *input)
32{
33  if (input != NULL)
34    return g_strdup(input);
35  else
36    return g_build_filename(owl_global_get_homedir(&g), name, NULL);
37}
38
39#ifdef HAVE_LIBZEPHYR
40void owl_zephyr_initialize(void)
41{
42  Code_t ret;
43  struct servent *sp;
44  struct sockaddr_in sin;
45  ZNotice_t req;
46  GIOChannel *channel;
47
48  /*
49   * Code modified from libzephyr's ZhmStat.c
50   *
51   * Modified to add the fd to our select loop, rather than hanging
52   * until we get an ack.
53   */
54
55  if ((ret = ZOpenPort(NULL)) != ZERR_NONE) {
56    owl_function_error("Error opening Zephyr port: %s", error_message(ret));
57    return;
58  }
59
60  (void) memset(&sin, 0, sizeof(struct sockaddr_in));
61
62  sp = getservbyname(HM_SVCNAME, "udp");
63
64  sin.sin_port = (sp) ? sp->s_port : HM_SVC_FALLBACK;
65  sin.sin_family = AF_INET;
66
67  sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
68
69  (void) memset(&req, 0, sizeof(req));
70  req.z_kind = STAT;
71  req.z_port = 0;
72  req.z_class = zstr(HM_STAT_CLASS);
73  req.z_class_inst = zstr(HM_STAT_CLIENT);
74  req.z_opcode = zstr(HM_GIMMESTATS);
75  req.z_sender = zstr("");
76  req.z_recipient = zstr("");
77  req.z_default_format = zstr("");
78  req.z_message_len = 0;
79
80  if ((ret = ZSetDestAddr(&sin)) != ZERR_NONE) {
81    owl_function_error("Initializing Zephyr: %s", error_message(ret));
82    return;
83  }
84
85  if ((ret = ZSendNotice(&req, ZNOAUTH)) != ZERR_NONE) {
86    owl_function_error("Initializing Zephyr: %s", error_message(ret));
87    return;
88  }
89
90  channel = g_io_channel_unix_new(ZGetFD());
91  g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
92                 &owl_zephyr_finish_initialization, NULL);
93  g_io_channel_unref(channel);
94}
95
96gboolean owl_zephyr_finish_initialization(GIOChannel *source, GIOCondition condition, void *data) {
97  Code_t code;
98  char *perl;
99  GSource *event_source;
100
101  ZClosePort();
102
103  if ((code = ZInitialize()) != ZERR_NONE) {
104    owl_function_error("Initializing Zephyr: %s", error_message(code));
105    return FALSE;
106  }
107
108  if ((code = ZOpenPort(NULL)) != ZERR_NONE) {
109    owl_function_error("Initializing Zephyr: %s", error_message(code));
110    return FALSE;
111  }
112
113  event_source = owl_zephyr_event_source_new(ZGetFD());
114  g_source_attach(event_source, NULL);
115  g_source_unref(event_source);
116
117  owl_global_set_havezephyr(&g);
118
119  if(g.load_initial_subs) {
120    owl_zephyr_load_initial_subs();
121  }
122  while(deferred_subs != NULL) {
123    owl_sub_list *subs = deferred_subs->data;
124    owl_function_debugmsg("Loading %d deferred subs.", subs->nsubs);
125    owl_zephyr_loadsubs_helper(subs->subs, subs->nsubs);
126    deferred_subs = g_list_delete_link(deferred_subs, deferred_subs);
127    g_free(subs);
128  }
129
130  /* zlog in if we need to */
131  if (owl_global_is_startuplogin(&g)) {
132    owl_function_debugmsg("startup: doing zlog in");
133    owl_zephyr_zlog_in();
134  }
135  /* check pseudo-logins if we need to */
136  if (owl_global_is_pseudologins(&g)) {
137    owl_function_debugmsg("startup: checking pseudo-logins");
138    owl_function_zephyr_buddy_check(0);
139  }
140
141  perl = owl_perlconfig_execute("BarnOwl::Zephyr::_zephyr_startup()");
142  g_free(perl);
143  return FALSE;
144}
145
146void owl_zephyr_load_initial_subs(void) {
147  int ret_sd, ret_bd, ret_u;
148
149  owl_function_debugmsg("startup: loading initial zephyr subs");
150
151  /* load default subscriptions */
152  ret_sd = owl_zephyr_loaddefaultsubs();
153
154  /* load Barnowl default subscriptions */
155  ret_bd = owl_zephyr_loadbarnowldefaultsubs();
156
157  /* load subscriptions from subs file */
158  ret_u = owl_zephyr_loadsubs(NULL, 0);
159
160  if (ret_sd || ret_bd || ret_u) {
161    owl_function_error("Error loading zephyr subscriptions");
162  }
163
164  /* load login subscriptions */
165  if (owl_global_is_loginsubs(&g)) {
166    owl_function_debugmsg("startup: loading login subs");
167    owl_function_loadloginsubs(NULL);
168  }
169}
170#else
171void owl_zephyr_initialize(void)
172{
173}
174#endif
175
176
177int owl_zephyr_shutdown(void)
178{
179#ifdef HAVE_LIBZEPHYR
180  if(owl_global_is_havezephyr(&g)) {
181    unsuball();
182    ZClosePort();
183  }
184#endif
185  return 0;
186}
187
188int owl_zephyr_zpending(void)
189{
190#ifdef HAVE_LIBZEPHYR
191  Code_t code;
192  if(owl_global_is_havezephyr(&g)) {
193    if((code = ZPending()) < 0) {
194      owl_function_debugmsg("Error (%s) in ZPending()\n",
195                            error_message(code));
196      return 0;
197    }
198    return code;
199  }
200#endif
201  return 0;
202}
203
204int owl_zephyr_zqlength(void)
205{
206#ifdef HAVE_LIBZEPHYR
207  Code_t code;
208  if(owl_global_is_havezephyr(&g)) {
209    if((code = ZQLength()) < 0) {
210      owl_function_debugmsg("Error (%s) in ZQLength()\n",
211                            error_message(code));
212      return 0;
213    }
214    return code;
215  }
216#endif
217  return 0;
218}
219
220const char *owl_zephyr_get_realm(void)
221{
222#ifdef HAVE_LIBZEPHYR
223  if (owl_global_is_havezephyr(&g))
224    return(ZGetRealm());
225#endif
226  return "";
227}
228
229const char *owl_zephyr_get_sender(void)
230{
231#ifdef HAVE_LIBZEPHYR
232  if (owl_global_is_havezephyr(&g))
233    return(ZGetSender());
234#endif
235  return "";
236}
237
238#ifdef HAVE_LIBZEPHYR
239int owl_zephyr_loadsubs_helper(ZSubscription_t subs[], int count)
240{
241  int ret = 0;
242  Code_t code;
243
244  if (owl_global_is_havezephyr(&g)) {
245    int i;
246    /* sub without defaults */
247    code = ZSubscribeToSansDefaults(subs, count, 0);
248    if (code != ZERR_NONE) {
249      owl_function_error("Error subscribing to zephyr notifications: %s",
250                         error_message(code));
251      ret=-2;
252    }
253
254    /* free stuff */
255    for (i=0; i<count; i++) {
256      g_free(subs[i].zsub_class);
257      g_free(subs[i].zsub_classinst);
258      g_free(subs[i].zsub_recipient);
259    }
260
261    g_free(subs);
262  } else {
263    owl_sub_list *s = g_new(owl_sub_list, 1);
264    s->subs = subs;
265    s->nsubs = count;
266    deferred_subs = g_list_append(deferred_subs, s);
267  }
268
269  return ret;
270}
271#endif
272
273/* Load zephyr subscriptions from 'filename'.  If 'filename' is NULL,
274 * the default file $HOME/.zephyr.subs will be used.
275 *
276 * Returns 0 on success.  If the file does not exist, return -1 if
277 * 'error_on_nofile' is 1, otherwise return 0.  Return -1 if the file
278 * exists but can not be read.  Return -2 if there is a failure from
279 * zephyr to load the subscriptions.
280 */
281int owl_zephyr_loadsubs(const char *filename, int error_on_nofile)
282{
283#ifdef HAVE_LIBZEPHYR
284  FILE *file;
285  char *tmp, *start;
286  char *buffer = NULL;
287  char *subsfile;
288  ZSubscription_t *subs;
289  int subSize = 1024;
290  int count;
291  struct stat statbuff;
292
293  subs = g_new(ZSubscription_t, subSize);
294  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
295
296  if (stat(subsfile, &statbuff) != 0) {
297    g_free(subsfile);
298    if (error_on_nofile == 1)
299      return -1;
300    return 0;
301  }
302
303  ZResetAuthentication();
304  count = 0;
305  file = fopen(subsfile, "r");
306  g_free(subsfile);
307  if (!file)
308    return -1;
309  while (owl_getline(&buffer, file)) {
310    if (buffer[0] == '#' || buffer[0] == '\n')
311        continue;
312
313    if (buffer[0] == '-')
314      start = buffer + 1;
315    else
316      start = buffer;
317
318    if (count >= subSize) {
319      subSize *= 2;
320      subs = g_renew(ZSubscription_t, subs, subSize);
321    }
322   
323    /* add it to the list of subs */
324    if ((tmp = strtok(start, ",\n\r")) == NULL)
325      continue;
326    subs[count].zsub_class = g_strdup(tmp);
327    if ((tmp=strtok(NULL, ",\n\r")) == NULL)
328      continue;
329    subs[count].zsub_classinst = g_strdup(tmp);
330    if ((tmp = strtok(NULL, " \t\n\r")) == NULL)
331      continue;
332    subs[count].zsub_recipient = g_strdup(tmp);
333
334    /* if it started with '-' then add it to the global punt list, and
335     * remove it from the list of subs. */
336    if (buffer[0] == '-') {
337      owl_function_zpunt(subs[count].zsub_class, subs[count].zsub_classinst, subs[count].zsub_recipient, 0);
338      g_free(subs[count].zsub_class);
339      g_free(subs[count].zsub_classinst);
340      g_free(subs[count].zsub_recipient);
341    } else {
342      count++;
343    }
344  }
345  fclose(file);
346  if (buffer)
347    g_free(buffer);
348
349  return owl_zephyr_loadsubs_helper(subs, count);
350#else
351  return 0;
352#endif
353}
354
355/* Load default Barnowl subscriptions
356 *
357 * Returns 0 on success.
358 * Return -2 if there is a failure from zephyr to load the subscriptions.
359 */
360int owl_zephyr_loadbarnowldefaultsubs(void)
361{
362#ifdef HAVE_LIBZEPHYR
363  ZSubscription_t *subs;
364  int subSize = 10; /* Max Barnowl default subs we allow */
365  int count, ret;
366
367  subs = g_new(ZSubscription_t, subSize);
368  ZResetAuthentication();
369  count=0;
370
371  subs[count].zsub_class=g_strdup("message");
372  subs[count].zsub_classinst=g_strdup("*");
373  subs[count].zsub_recipient=g_strdup("%me%");
374  count++;
375
376  ret = owl_zephyr_loadsubs_helper(subs, count);
377  return(ret);
378#else
379  return(0);
380#endif
381}
382
383int owl_zephyr_loaddefaultsubs(void)
384{
385#ifdef HAVE_LIBZEPHYR
386  Code_t ret;
387
388  if (owl_global_is_havezephyr(&g)) {
389    ZSubscription_t subs[10];
390
391    ret = ZSubscribeTo(subs, 0, 0);
392    if (ret != ZERR_NONE) {
393      owl_function_error("Error subscribing to default zephyr notifications: %s.",
394                           error_message(ret));
395      return(-1);
396    }
397  }
398  return(0);
399#else
400  return(0);
401#endif
402}
403
404int owl_zephyr_loadloginsubs(const char *filename)
405{
406#ifdef HAVE_LIBZEPHYR
407  FILE *file;
408  ZSubscription_t *subs;
409  int numSubs = 100;
410  char *subsfile;
411  char *buffer = NULL;
412  int count;
413  struct stat statbuff;
414
415  subs = g_new(ZSubscription_t, numSubs);
416  subsfile = owl_zephyr_dotfile(".anyone", filename);
417
418  if (stat(subsfile, &statbuff) == -1) {
419    g_free(subs);
420    g_free(subsfile);
421    return 0;
422  }
423
424  ZResetAuthentication();
425  count = 0;
426  file = fopen(subsfile, "r");
427  g_free(subsfile);
428  if (file) {
429    while (owl_getline_chomp(&buffer, file)) {
430      if (buffer[0] == '\0' || buffer[0] == '#')
431        continue;
432
433      if (count == numSubs) {
434        numSubs *= 2;
435        subs = g_renew(ZSubscription_t, subs, numSubs);
436      }
437
438      subs[count].zsub_class = g_strdup("login");
439      subs[count].zsub_recipient = g_strdup("*");
440      subs[count].zsub_classinst = long_zuser(buffer);
441
442      count++;
443    }
444    fclose(file);
445  } else {
446    return 0;
447  }
448  g_free(buffer);
449
450  return owl_zephyr_loadsubs_helper(subs, count);
451#else
452  return 0;
453#endif
454}
455
456void unsuball(void)
457{
458#if HAVE_LIBZEPHYR
459  Code_t ret;
460
461  ZResetAuthentication();
462  ret = ZCancelSubscriptions(0);
463  if (ret != ZERR_NONE)
464    owl_function_error("Zephyr: Cancelling subscriptions: %s",
465                       error_message(ret));
466#endif
467}
468
469int owl_zephyr_sub(const char *class, const char *inst, const char *recip)
470{
471#ifdef HAVE_LIBZEPHYR
472  ZSubscription_t subs[5];
473  Code_t ret;
474
475  subs[0].zsub_class=zstr(class);
476  subs[0].zsub_classinst=zstr(inst);
477  subs[0].zsub_recipient=zstr(recip);
478
479  ZResetAuthentication();
480  ret = ZSubscribeTo(subs, 1, 0);
481  if (ret != ZERR_NONE) {
482    owl_function_error("Error subbing to <%s,%s,%s>: %s",
483                       class, inst, recip,
484                       error_message(ret));
485    return(-2);
486  }
487  return(0);
488#else
489  return(0);
490#endif
491}
492
493
494int owl_zephyr_unsub(const char *class, const char *inst, const char *recip)
495{
496#ifdef HAVE_LIBZEPHYR
497  ZSubscription_t subs[5];
498  Code_t ret;
499
500  subs[0].zsub_class=zstr(class);
501  subs[0].zsub_classinst=zstr(inst);
502  subs[0].zsub_recipient=zstr(recip);
503
504  ZResetAuthentication();
505  ret = ZUnsubscribeTo(subs, 1, 0);
506  if (ret != ZERR_NONE) {
507    owl_function_error("Error unsubbing from <%s,%s,%s>: %s",
508                       class, inst, recip,
509                       error_message(ret));
510    return(-2);
511  }
512  return(0);
513#else
514  return(0);
515#endif
516}
517
518/* return a pointer to the data in the Jth field, (NULL terminated by
519 * definition).  Caller must free the return.
520 */
521#ifdef HAVE_LIBZEPHYR
522CALLER_OWN char *owl_zephyr_get_field(const ZNotice_t *n, int j)
523{
524  int i, count, save;
525
526  /* If there's no message here, just run along now */
527  if (n->z_message_len == 0)
528    return(g_strdup(""));
529
530  count=save=0;
531  for (i=0; i<n->z_message_len; i++) {
532    if (n->z_message[i]=='\0') {
533      count++;
534      if (count==j) {
535        /* just found the end of the field we're looking for */
536        return(g_strdup(n->z_message+save));
537      } else {
538        save=i+1;
539      }
540    }
541  }
542  /* catch the last field, which might not be null terminated */
543  if (count==j-1) {
544    return g_strndup(n->z_message + save, n->z_message_len - save);
545  }
546
547  return(g_strdup(""));
548}
549
550CALLER_OWN char *owl_zephyr_get_field_as_utf8(const ZNotice_t *n, int j)
551{
552  int i, count, save;
553
554  /* If there's no message here, just run along now */
555  if (n->z_message_len == 0)
556    return(g_strdup(""));
557
558  count=save=0;
559  for (i = 0; i < n->z_message_len; i++) {
560    if (n->z_message[i]=='\0') {
561      count++;
562      if (count == j) {
563        /* just found the end of the field we're looking for */
564        return(owl_validate_or_convert(n->z_message + save));
565      } else {
566        save = i + 1;
567      }
568    }
569  }
570  /* catch the last field, which might not be null terminated */
571  if (count == j - 1) {
572    char *tmp, *out;
573    tmp = g_strndup(n->z_message + save, n->z_message_len - save);
574    out = owl_validate_or_convert(tmp);
575    g_free(tmp);
576    return out;
577  }
578
579  return(g_strdup(""));
580}
581#else
582CALLER_OWN char *owl_zephyr_get_field(void *n, int j)
583{
584  return(g_strdup(""));
585}
586CALLER_OWN char *owl_zephyr_get_field_as_utf8(void *n, int j)
587{
588  return owl_zephyr_get_field(n, j);
589}
590#endif
591
592
593#ifdef HAVE_LIBZEPHYR
594int owl_zephyr_get_num_fields(const ZNotice_t *n)
595{
596  int i, fields;
597
598  if(n->z_message_len == 0)
599    return 0;
600
601  fields=1;
602  for (i=0; i<n->z_message_len; i++) {
603    if (n->z_message[i]=='\0') fields++;
604  }
605 
606  return(fields);
607}
608#else
609int owl_zephyr_get_num_fields(const void *n)
610{
611  return(0);
612}
613#endif
614
615#ifdef HAVE_LIBZEPHYR
616/* return a pointer to the message, place the message length in k
617 * caller must free the return
618 */
619CALLER_OWN char *owl_zephyr_get_message(const ZNotice_t *n, const owl_message *m)
620{
621#define OWL_NFIELDS     5
622  int i;
623  char *fields[OWL_NFIELDS + 1];
624  char *msg = NULL;
625
626  /* don't let ping messages have a body */
627  if (!strcasecmp(n->z_opcode, "ping")) {
628    return(g_strdup(""));
629  }
630
631  for(i = 0; i < OWL_NFIELDS; i++)
632    fields[i + 1] = owl_zephyr_get_field(n, i + 1);
633
634  /* deal with MIT NOC messages */
635  if (!strcasecmp(n->z_default_format, "@center(@bold(NOC Message))\n\n@bold(Sender:) $1 <$sender>\n@bold(Time:  ) $time\n\n@italic($opcode service on $instance $3.) $4\n")) {
636
637    msg = g_strdup_printf("%s service on %s %s\n%s", n->z_opcode, n->z_class_inst, fields[3], fields[4]);
638  }
639  /* deal with MIT Discuss messages */
640  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4") ||
641           !strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4")) {
642   
643    msg = g_strdup_printf("New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s",
644                          fields[1], fields[2], fields[3], fields[5], fields[4]);
645  }
646  /* deal with MIT Moira messages */
647  else if (!strcasecmp(n->z_default_format, "MOIRA $instance on $fromhost:\n $message\n")) {
648    msg = g_strdup_printf("MOIRA %s on %s: %s",
649                          n->z_class_inst,
650                          owl_message_get_hostname(m),
651                          fields[1]);
652  } else {
653    if (owl_zephyr_get_num_fields(n) == 1)
654      msg = g_strdup(fields[1]);
655    else
656      msg = g_strdup(fields[2]);
657  }
658
659  for (i = 0; i < OWL_NFIELDS; i++)
660    g_free(fields[i + 1]);
661
662  return msg;
663}
664#endif
665
666#ifdef HAVE_LIBZEPHYR
667const char *owl_zephyr_get_zsig(const ZNotice_t *n, int *k)
668{
669  /* return a pointer to the zsig if there is one */
670
671  /* message length 0? No zsig */
672  if (n->z_message_len==0) {
673    *k=0;
674    return("");
675  }
676
677  /* If there's only one field, no zsig */
678  if (owl_zephyr_get_num_fields(n) == 1) {
679    *k=0;
680    return("");
681  }
682
683  /* Everything else is field 1 */
684  *k=strlen(n->z_message);
685  return(n->z_message);
686}
687#else
688const char *owl_zephyr_get_zsig(const void *n, int *k)
689{
690  return("");
691}
692#endif
693
694int send_zephyr(const char *opcode, const char *zsig, const char *class, const char *instance, const char *recipient, const char *message)
695{
696#ifdef HAVE_LIBZEPHYR
697  Code_t ret;
698  ZNotice_t notice;
699  char *zsender = NULL;
700   
701  memset(&notice, 0, sizeof(notice));
702
703  ZResetAuthentication();
704
705  if (!zsig) zsig="";
706 
707  notice.z_kind=ACKED;
708  notice.z_port=0;
709  notice.z_class=zstr(class);
710  notice.z_class_inst=zstr(instance);
711  if (!strcmp(recipient, "@")) {
712    notice.z_recipient=zstr("");
713    if (*owl_global_get_zsender(&g))
714      notice.z_sender = zsender = long_zuser(owl_global_get_zsender(&g));
715  } else {
716    notice.z_recipient=zstr(recipient);
717  }
718  notice.z_default_format=zstr("Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold{$1 <$sender>}\n\n$2");
719  if (opcode) notice.z_opcode=zstr(opcode);
720
721  notice.z_message_len=strlen(zsig)+1+strlen(message);
722  notice.z_message=g_new(char, notice.z_message_len+10);
723  strcpy(notice.z_message, zsig);
724  memcpy(notice.z_message+strlen(zsig)+1, message, strlen(message));
725
726  /* ret=ZSendNotice(&notice, ZAUTH); */
727  ret=ZSrvSendNotice(&notice, ZAUTH, send_zephyr_helper);
728 
729  /* free then check the return */
730  g_free(notice.z_message);
731  ZFreeNotice(&notice);
732  g_free(zsender);
733  if (ret != ZERR_NONE) {
734    owl_function_error("Error sending zephyr: %s", error_message(ret));
735    return(ret);
736  }
737  return(0);
738#else
739  return(0);
740#endif
741}
742
743#ifdef HAVE_LIBZEPHYR
744Code_t send_zephyr_helper(ZNotice_t *notice, char *buf, int len, int wait)
745{
746  return(ZSendPacket(buf, len, 0));
747}
748#endif
749
750void send_ping(const char *to, const char *zclass, const char *zinstance)
751{
752#ifdef HAVE_LIBZEPHYR
753  send_zephyr("PING", "", zclass, zinstance, to, "");
754#endif
755}
756
757#ifdef HAVE_LIBZEPHYR
758void owl_zephyr_handle_ack(const ZNotice_t *retnotice)
759{
760  char *tmp;
761 
762  /* if it's an HMACK ignore it */
763  if (retnotice->z_kind == HMACK) return;
764
765  if (retnotice->z_kind == SERVNAK) {
766    owl_function_error("Authorization failure sending zephyr");
767  } else if ((retnotice->z_kind != SERVACK) || !retnotice->z_message_len) {
768    owl_function_error("Detected server failure while receiving acknowledgement");
769  } else if (!strcmp(retnotice->z_message, ZSRVACK_SENT)) {
770    if (!strcasecmp(retnotice->z_opcode, "ping")) {
771      return;
772    } else {
773      if (strcasecmp(retnotice->z_recipient, ""))
774      { /* personal */
775        tmp=short_zuser(retnotice->z_recipient);
776        if(!strcasecmp(retnotice->z_class, "message") &&
777           !strcasecmp(retnotice->z_class_inst, "personal")) {
778          owl_function_makemsg("Message sent to %s.", tmp);
779        } else if(!strcasecmp(retnotice->z_class, "message")) { /* instanced, but not classed, personal */
780          owl_function_makemsg("Message sent to %s on -i %s\n", tmp, retnotice->z_class_inst);
781        } else { /* classed personal */
782          owl_function_makemsg("Message sent to %s on -c %s -i %s\n", tmp, retnotice->z_class, retnotice->z_class_inst);
783        }
784        g_free(tmp);
785      } else {
786        /* class / instance message */
787          owl_function_makemsg("Message sent to -c %s -i %s\n", retnotice->z_class, retnotice->z_class_inst);
788      }
789    }
790  } else if (!strcmp(retnotice->z_message, ZSRVACK_NOTSENT)) {
791    if (retnotice->z_recipient == NULL
792        || !owl_zwrite_recip_is_personal(retnotice->z_recipient)) {
793      char *buff;
794      owl_function_error("No one subscribed to class %s", retnotice->z_class);
795      buff = g_strdup_printf("Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
796      owl_function_adminmsg("", buff);
797      g_free(buff);
798    } else {
799      char *buff;
800      owl_zwrite zw;
801
802      tmp = short_zuser(retnotice->z_recipient);
803      owl_function_error("%s: Not logged in or subscribing.", tmp);
804      /*
805       * These error messages are often over 80 chars, but users who want to
806       * see the whole thing can scroll to the side, and for those with wide
807       * terminals or who don't care, not splitting saves a line in the UI
808       */
809      if(strcasecmp(retnotice->z_class, "message")) {
810        buff = g_strdup_printf(
811                 "Could not send message to %s: "
812                 "not logged in or subscribing to class %s, instance %s.\n",
813                 tmp,
814                 retnotice->z_class,
815                 retnotice->z_class_inst);
816      } else if(strcasecmp(retnotice->z_class_inst, "personal")) {
817        buff = g_strdup_printf(
818                 "Could not send message to %s: "
819                 "not logged in or subscribing to instance %s.\n",
820                 tmp,
821                 retnotice->z_class_inst);
822      } else {
823        buff = g_strdup_printf(
824                 "Could not send message to %s: "
825                 "not logged in or subscribing to messages.\n",
826                 tmp);
827      }
828      owl_function_adminmsg("", buff);
829
830      memset(&zw, 0, sizeof(zw));
831      zw.class = g_strdup(retnotice->z_class);
832      zw.inst  = g_strdup(retnotice->z_class_inst);
833      zw.realm = g_strdup("");
834      zw.opcode = g_strdup(retnotice->z_opcode);
835      zw.zsig   = g_strdup("");
836      zw.recips = g_ptr_array_new();
837      g_ptr_array_add(zw.recips, g_strdup(retnotice->z_recipient));
838
839      owl_log_outgoing_zephyr_error(&zw, buff);
840
841      owl_zwrite_cleanup(&zw);
842      g_free(buff);
843      g_free(tmp);
844    }
845  } else {
846    owl_function_error("Internal error on ack (%s)", retnotice->z_message);
847  }
848}
849#else
850void owl_zephyr_handle_ack(const void *retnotice)
851{
852}
853#endif
854
855#ifdef HAVE_LIBZEPHYR
856int owl_zephyr_notice_is_ack(const ZNotice_t *n)
857{
858  if (n->z_kind == SERVNAK || n->z_kind == SERVACK || n->z_kind == HMACK) {
859    if (!strcasecmp(n->z_class, LOGIN_CLASS)) return(0);
860    return(1);
861  }
862  return(0);
863}
864#else
865int owl_zephyr_notice_is_ack(const void *n)
866{
867  return(0);
868}
869#endif
870 
871void owl_zephyr_zaway(const owl_message *m)
872{
873#ifdef HAVE_LIBZEPHYR
874  char *tmpbuff, *myuser, *to;
875  owl_zwrite *z;
876 
877  /* bail if it doesn't look like a message we should reply to.  Some
878   * of this defined by the way zaway(1) works
879   */
880  if (strcasecmp(owl_message_get_class(m), "message")) return;
881  if (strcasecmp(owl_message_get_recipient(m), ZGetSender())) return;
882  if (!strcasecmp(owl_message_get_sender(m), "")) return;
883  if (!strcasecmp(owl_message_get_opcode(m), "ping")) return;
884  if (!strcasecmp(owl_message_get_opcode(m), "auto")) return;
885  if (!strcasecmp(owl_message_get_zsig(m), "Automated reply:")) return;
886  if (!strcasecmp(owl_message_get_sender(m), ZGetSender())) return;
887  if (owl_message_get_attribute_value(m, "isauto")) return;
888
889  if (owl_global_is_smartstrip(&g)) {
890    to=owl_zephyr_smartstripped_user(owl_message_get_sender(m));
891  } else {
892    to=g_strdup(owl_message_get_sender(m));
893  }
894
895  send_zephyr("",
896              "Automated reply:",
897              owl_message_get_class(m),
898              owl_message_get_instance(m),
899              to,
900              owl_global_get_zaway_msg(&g));
901
902  myuser=short_zuser(to);
903  if (!strcasecmp(owl_message_get_instance(m), "personal")) {
904    tmpbuff = owl_string_build_quoted("zwrite %q", myuser);
905  } else {
906    tmpbuff = owl_string_build_quoted("zwrite -i %q %q", owl_message_get_instance(m), myuser);
907  }
908  g_free(myuser);
909  g_free(to);
910
911  z = owl_zwrite_new_from_line(tmpbuff);
912  g_free(tmpbuff);
913  if (z == NULL) {
914    owl_function_error("Error creating outgoing zephyr.");
915    return;
916  }
917  owl_zwrite_set_message(z, owl_global_get_zaway_msg(&g));
918  owl_zwrite_set_zsig(z, "Automated reply:");
919
920  /* display the message as an admin message in the receive window */
921  owl_function_add_outgoing_zephyrs(z);
922  owl_zwrite_delete(z);
923#endif
924}
925
926#ifdef HAVE_LIBZEPHYR
927void owl_zephyr_hackaway_cr(ZNotice_t *n)
928{
929  /* replace \r's with ' '.  Gross-ish */
930  int i;
931
932  for (i=0; i<n->z_message_len; i++) {
933    if (n->z_message[i]=='\r') {
934      n->z_message[i]=' ';
935    }
936  }
937}
938#endif
939
940CALLER_OWN char *owl_zephyr_zlocate(const char *user, int auth)
941{
942#ifdef HAVE_LIBZEPHYR
943  int ret, numlocs;
944  int one = 1;
945  ZLocations_t locations;
946  char *myuser;
947  char *p, *result;
948
949  ZResetAuthentication();
950  ret = ZLocateUser(zstr(user), &numlocs, auth ? ZAUTH : ZNOAUTH);
951  if (ret != ZERR_NONE)
952    return g_strdup_printf("Error locating user %s: %s\n",
953                           user, error_message(ret));
954
955  myuser = short_zuser(user);
956  if (numlocs == 0) {
957    result = g_strdup_printf("%s: Hidden or not logged in\n", myuser);
958  } else {
959    result = g_strdup("");
960    for (; numlocs; numlocs--) {
961      ZGetLocations(&locations, &one);
962      p = g_strdup_printf("%s%s: %s\t%s\t%s\n",
963                          result, myuser,
964                          locations.host ? locations.host : "?",
965                          locations.tty ? locations.tty : "?",
966                          locations.time ? locations.time : "?");
967      g_free(result);
968      result = p;
969    }
970  }
971  g_free(myuser);
972
973  return result;
974#else
975  return g_strdup("");
976#endif
977}
978
979void owl_zephyr_addsub(const char *filename, const char *class, const char *inst, const char *recip)
980{
981#ifdef HAVE_LIBZEPHYR
982  char *line, *subsfile, *s = NULL;
983  FILE *file;
984  int duplicate = 0;
985
986  line = owl_zephyr_makesubline(class, inst, recip);
987  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
988
989  /* if the file already exists, check to see if the sub is already there */
990  file = fopen(subsfile, "r");
991  if (file) {
992    while (owl_getline(&s, file)) {
993      if (strcasecmp(s, line) == 0) {
994        owl_function_error("Subscription already present in %s", subsfile);
995        duplicate++;
996      }
997    }
998    fclose(file);
999    g_free(s);
1000  }
1001
1002  if (!duplicate) {
1003    file = fopen(subsfile, "a");
1004    if (file) {
1005      fputs(line, file);
1006      fclose(file);
1007      owl_function_makemsg("Subscription added");
1008    } else {
1009      owl_function_error("Error opening file %s for writing", subsfile);
1010    }
1011  }
1012
1013  g_free(line);
1014#endif
1015}
1016
1017void owl_zephyr_delsub(const char *filename, const char *class, const char *inst, const char *recip)
1018{
1019#ifdef HAVE_LIBZEPHYR
1020  char *line, *subsfile;
1021  int linesdeleted;
1022 
1023  line=owl_zephyr_makesubline(class, inst, recip);
1024  line[strlen(line)-1]='\0';
1025
1026  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
1027 
1028  linesdeleted = owl_util_file_deleteline(subsfile, line, 1);
1029  if (linesdeleted > 0) {
1030    owl_function_makemsg("Subscription removed");
1031  } else if (linesdeleted == 0) {
1032    owl_function_error("No subscription present in %s", subsfile);
1033  }
1034  g_free(subsfile);
1035  g_free(line);
1036#endif
1037}
1038
1039/* caller must free the return */
1040CALLER_OWN char *owl_zephyr_makesubline(const char *class, const char *inst, const char *recip)
1041{
1042  return g_strdup_printf("%s,%s,%s\n", class, inst, !strcmp(recip, "") ? "*" : recip);
1043}
1044
1045
1046void owl_zephyr_zlog_in(void)
1047{
1048#ifdef HAVE_LIBZEPHYR
1049  ZResetAuthentication();
1050
1051  /* ZSetLocation, and store the default value as the current value */
1052  owl_global_set_exposure(&g, owl_global_get_default_exposure(&g));
1053#endif
1054}
1055
1056void owl_zephyr_zlog_out(void)
1057{
1058#ifdef HAVE_LIBZEPHYR
1059  Code_t ret;
1060
1061  ZResetAuthentication();
1062  ret = ZUnsetLocation();
1063  if (ret != ZERR_NONE)
1064    owl_function_error("Error unsetting location: %s", error_message(ret));
1065#endif
1066}
1067
1068void owl_zephyr_addbuddy(const char *name)
1069{
1070  char *filename;
1071  FILE *file;
1072 
1073  filename = owl_zephyr_dotfile(".anyone", NULL);
1074  file = fopen(filename, "a");
1075  g_free(filename);
1076  if (!file) {
1077    owl_function_error("Error opening zephyr buddy file for append");
1078    return;
1079  }
1080  fprintf(file, "%s\n", name);
1081  fclose(file);
1082}
1083
1084void owl_zephyr_delbuddy(const char *name)
1085{
1086  char *filename;
1087
1088  filename = owl_zephyr_dotfile(".anyone", NULL);
1089  owl_util_file_deleteline(filename, name, 0);
1090  g_free(filename);
1091}
1092
1093/* return auth string */
1094#ifdef HAVE_LIBZEPHYR
1095const char *owl_zephyr_get_authstr(const ZNotice_t *n)
1096{
1097
1098  if (!n) return("UNKNOWN");
1099
1100  if (n->z_auth == ZAUTH_FAILED) {
1101    return ("FAILED");
1102  } else if (n->z_auth == ZAUTH_NO) {
1103    return ("NO");
1104  } else if (n->z_auth == ZAUTH_YES) {
1105    return ("YES");
1106  } else {
1107    return ("UNKNOWN");
1108  }           
1109}
1110#else
1111const char *owl_zephyr_get_authstr(const void *n)
1112{
1113  return("");
1114}
1115#endif
1116
1117/* Returns a buffer of subscriptions or an error message.  Caller must
1118 * free the return.
1119 */
1120CALLER_OWN char *owl_zephyr_getsubs(void)
1121{
1122#ifdef HAVE_LIBZEPHYR
1123  Code_t ret;
1124  int num, i, one;
1125  ZSubscription_t sub;
1126  GString *buf;
1127
1128  ret = ZRetrieveSubscriptions(0, &num);
1129  if (ret != ZERR_NONE)
1130    return g_strdup_printf("Zephyr: Requesting subscriptions: %s\n", error_message(ret));
1131  if (num == 0)
1132    return g_strdup("Zephyr: No subscriptions retrieved\n");
1133
1134  buf = g_string_new("");
1135  for (i=0; i<num; i++) {
1136    one = 1;
1137    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1138      ZFlushSubscriptions();
1139      g_string_free(buf, true);
1140      return g_strdup_printf("Zephyr: Getting subscriptions: %s\n", error_message(ret));
1141    } else {
1142      /* g_string_append_printf would be backwards. */
1143      char *tmp = g_strdup_printf("<%s,%s,%s>\n",
1144                                  sub.zsub_class,
1145                                  sub.zsub_classinst,
1146                                  sub.zsub_recipient);
1147      g_string_prepend(buf, tmp);
1148      g_free(tmp);
1149    }
1150  }
1151
1152  ZFlushSubscriptions();
1153  return g_string_free(buf, false);
1154#else
1155  return(g_strdup("Zephyr not available"));
1156#endif
1157}
1158
1159const char *owl_zephyr_get_variable(const char *var)
1160{
1161#ifdef HAVE_LIBZEPHYR
1162  return(ZGetVariable(zstr(var)));
1163#else
1164  return("");
1165#endif
1166}
1167
1168void owl_zephyr_set_locationinfo(const char *host, const char *val)
1169{
1170#ifdef HAVE_LIBZEPHYR
1171  ZInitLocationInfo(zstr(host), zstr(val));
1172#endif
1173}
1174
1175const char *owl_zephyr_normalize_exposure(const char *exposure)
1176{
1177  if (exposure == NULL)
1178    return NULL;
1179#ifdef HAVE_LIBZEPHYR
1180  return ZParseExposureLevel(zstr(exposure));
1181#else
1182  return exposure;
1183#endif
1184}
1185
1186int owl_zephyr_set_default_exposure(const char *exposure)
1187{
1188#ifdef HAVE_LIBZEPHYR
1189  Code_t ret;
1190  if (exposure == NULL)
1191    return -1;
1192  exposure = ZParseExposureLevel(zstr(exposure));
1193  if (exposure == NULL)
1194    return -1;
1195  ret = ZSetVariable(zstr("exposure"), zstr(exposure)); /* ZSetVariable does file I/O */
1196  if (ret != ZERR_NONE) {
1197    owl_function_error("Unable to set default exposure location: %s", error_message(ret));
1198    return -1;
1199  }
1200#endif
1201  return 0;
1202}
1203
1204const char *owl_zephyr_get_default_exposure(void)
1205{
1206#ifdef HAVE_LIBZEPHYR
1207  const char *exposure = ZGetVariable(zstr("exposure")); /* ZGetVariable does file I/O */
1208  if (exposure == NULL)
1209    return EXPOSE_REALMVIS;
1210  exposure = ZParseExposureLevel(zstr(exposure));
1211  if (exposure == NULL) /* The user manually entered an invalid value in ~/.zephyr.vars, or something weird happened. */
1212    return EXPOSE_REALMVIS;
1213  return exposure;
1214#else
1215  return "";
1216#endif
1217}
1218
1219int owl_zephyr_set_exposure(const char *exposure)
1220{
1221#ifdef HAVE_LIBZEPHYR
1222  Code_t ret;
1223  if (exposure == NULL)
1224    return -1;
1225  exposure = ZParseExposureLevel(zstr(exposure));
1226  if (exposure == NULL)
1227    return -1;
1228  ret = ZSetLocation(zstr(exposure));
1229  if (ret != ZERR_NONE
1230#ifdef ZCONST
1231      /* Before zephyr 3.0, ZSetLocation had a bug where, if you were subscribed
1232       * to your own logins, it could wait for the wrong notice and return
1233       * ZERR_INTERNAL when found neither SERVACK nor SERVNAK. Suppress it when
1234       * building against the old ABI. */
1235      && ret != ZERR_INTERNAL
1236#endif
1237     ) {
1238    owl_function_error("Unable to set exposure level: %s.", error_message(ret));
1239    return -1;
1240  }
1241#endif
1242  return 0;
1243}
1244 
1245/* Strip a local realm fron the zephyr user name.
1246 * The caller must free the return
1247 */
1248CALLER_OWN char *short_zuser(const char *in)
1249{
1250  char *ptr = strrchr(in, '@');
1251  if (ptr && (ptr[1] == '\0' || !strcasecmp(ptr+1, owl_zephyr_get_realm()))) {
1252    return g_strndup(in, ptr - in);
1253  }
1254  return g_strdup(in);
1255}
1256
1257/* Append a local realm to the zephyr user name if necessary.
1258 * The caller must free the return.
1259 */
1260CALLER_OWN char *long_zuser(const char *in)
1261{
1262  char *ptr = strrchr(in, '@');
1263  if (ptr) {
1264    if (ptr[1])
1265      return g_strdup(in);
1266    /* Ends in @, so assume default realm. */
1267    return g_strdup_printf("%s%s", in, owl_zephyr_get_realm());
1268  }
1269  return g_strdup_printf("%s@%s", in, owl_zephyr_get_realm());
1270}
1271
1272/* Return the realm of the zephyr user name. Caller does /not/ free the return.
1273 * The string is valid at least as long as the input is.
1274 */
1275const char *zuser_realm(const char *in)
1276{
1277  char *ptr = strrchr(in, '@');
1278  /* If the name has an @ and does not end with @, use that. Otherwise, take
1279   * the default realm. */
1280  return (ptr && ptr[1]) ? (ptr+1) : owl_zephyr_get_realm();
1281}
1282
1283/* strip out the instance from a zsender's principal.  Preserves the
1284 * realm if present.  Leave host/ and daemon/ krb5 principals
1285 * alone. Also leave rcmd. and daemon. krb4 principals alone. The
1286 * caller must free the return.
1287 */
1288CALLER_OWN char *owl_zephyr_smartstripped_user(const char *in)
1289{
1290  char *slash, *dot, *realm, *out;
1291
1292  out = g_strdup(in);
1293
1294  /* bail immeaditly if we don't have to do any work */
1295  slash = strchr(out, '/');
1296  dot = strchr(out, '.');
1297  if (!slash && !dot) {
1298    return(out);
1299  }
1300
1301  if (!strncasecmp(out, OWL_ZEPHYR_NOSTRIP_HOST, strlen(OWL_ZEPHYR_NOSTRIP_HOST)) ||
1302      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_RCMD, strlen(OWL_ZEPHYR_NOSTRIP_RCMD)) ||
1303      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON5, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON5)) ||
1304      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON4, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON4))) {
1305    return(out);
1306  }
1307
1308  realm = strchr(out, '@');
1309  if (!slash && dot && realm && (dot > realm)) {
1310    /* There's no '/', and the first '.' is in the realm */
1311    return(out);
1312  }
1313
1314  /* remove the realm from out, but hold on to it */
1315  if (realm) realm[0]='\0';
1316
1317  /* strip */
1318  if (slash) slash[0] = '\0';  /* krb5 style user/instance */
1319  else if (dot) dot[0] = '\0'; /* krb4 style user.instance */
1320
1321  /* reattach the realm if we had one */
1322  if (realm) {
1323    strcat(out, "@");
1324    strcat(out, realm+1);
1325  }
1326
1327  return(out);
1328}
1329
1330/* Read the list of users in 'filename' as a .anyone file, and return as a
1331 * GPtrArray of strings.  If 'filename' is NULL, use the default .anyone file
1332 * in the users home directory.  Returns NULL on failure.
1333 */
1334GPtrArray *owl_zephyr_get_anyone_list(const char *filename)
1335{
1336#ifdef HAVE_LIBZEPHYR
1337  char *ourfile, *tmp, *s = NULL;
1338  FILE *f;
1339  GPtrArray *list;
1340
1341  ourfile = owl_zephyr_dotfile(".anyone", filename);
1342
1343  f = fopen(ourfile, "r");
1344  if (!f) {
1345    owl_function_error("Error opening file %s: %s", ourfile, strerror(errno) ? strerror(errno) : "");
1346    g_free(ourfile);
1347    return NULL;
1348  }
1349  g_free(ourfile);
1350
1351  list = g_ptr_array_new();
1352  while (owl_getline_chomp(&s, f)) {
1353    /* ignore comments, blank lines etc. */
1354    if (s[0] == '#' || s[0] == '\0')
1355      continue;
1356
1357    /* ignore from # on */
1358    tmp = strchr(s, '#');
1359    if (tmp)
1360      tmp[0] = '\0';
1361
1362    /* ignore from SPC */
1363    tmp = strchr(s, ' ');
1364    if (tmp)
1365      tmp[0] = '\0';
1366
1367    g_ptr_array_add(list, long_zuser(s));
1368  }
1369  g_free(s);
1370  fclose(f);
1371  return list;
1372#else
1373  return NULL;
1374#endif
1375}
1376
1377#ifdef HAVE_LIBZEPHYR
1378void owl_zephyr_process_pseudologin(ZNotice_t *n)
1379{
1380  owl_message *m;
1381  owl_zbuddylist *zbl;
1382  GList **zaldlist;
1383  GList *zaldptr;
1384  ZAsyncLocateData_t *zald = NULL;
1385  ZLocations_t location;
1386  int numlocs, ret, notify;
1387
1388  /* Find a ZALD to match this notice. */
1389  zaldlist = owl_global_get_zaldlist(&g);
1390  zaldptr = g_list_first(*zaldlist);
1391  while (zaldptr) {
1392    if (ZCompareALDPred(n, zaldptr->data)) {
1393      zald = zaldptr->data;
1394      *zaldlist = g_list_remove(*zaldlist, zaldptr->data);
1395      break;
1396    }
1397    zaldptr = g_list_next(zaldptr);
1398  }
1399  if (zald) {
1400    /* Deal with notice. */
1401    notify = owl_global_get_pseudologin_notify(&g);
1402    zbl = owl_global_get_zephyr_buddylist(&g);
1403    ret = ZParseLocations(n, zald, &numlocs, NULL);
1404    if (ret == ZERR_NONE) {
1405      if (numlocs > 0 && !owl_zbuddylist_contains_user(zbl, zald->user)) {
1406        if (notify) {
1407          numlocs = 1;
1408          ret = ZGetLocations(&location, &numlocs);
1409          if (ret == ZERR_NONE) {
1410            /* Send a PSEUDO LOGIN! */
1411            m = g_new(owl_message, 1);
1412            owl_message_create_pseudo_zlogin(m, 0, zald->user,
1413                                             location.host,
1414                                             location.time,
1415                                             location.tty);
1416            owl_global_messagequeue_addmsg(&g, m);
1417          }
1418          owl_zbuddylist_adduser(zbl, zald->user);
1419          owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", zald->user);
1420        }
1421      } else if (numlocs == 0 && owl_zbuddylist_contains_user(zbl, zald->user)) {
1422        /* Send a PSEUDO LOGOUT! */
1423        if (notify) {
1424          m = g_new(owl_message, 1);
1425          owl_message_create_pseudo_zlogin(m, 1, zald->user, "", "", "");
1426          owl_global_messagequeue_addmsg(&g, m);
1427        }
1428        owl_zbuddylist_deluser(zbl, zald->user);
1429        owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ", zald->user);
1430      }
1431    }
1432    ZFreeALD(zald);
1433    g_free(zald);
1434  }
1435}
1436#else
1437void owl_zephyr_process_pseudologin(void *n)
1438{
1439}
1440#endif
1441
1442gboolean owl_zephyr_buddycheck_timer(void *data)
1443{
1444  if (owl_global_is_pseudologins(&g)) {
1445    owl_function_debugmsg("Doing zephyr buddy check");
1446    owl_function_zephyr_buddy_check(1);
1447  } else {
1448    owl_function_debugmsg("Warning: owl_zephyr_buddycheck_timer call pointless; timer should have been disabled");
1449  }
1450  return TRUE;
1451}
1452
1453/*
1454 * Process zephyrgrams from libzephyr's queue. To prevent starvation,
1455 * process a maximum of OWL_MAX_ZEPHYRGRAMS_TO_PROCESS.
1456 *
1457 * Returns the number of zephyrgrams processed.
1458 */
1459
1460#define OWL_MAX_ZEPHYRGRAMS_TO_PROCESS 20
1461
1462#ifdef HAVE_LIBZEPHYR
1463static int _owl_zephyr_process_events(void)
1464{
1465  int zpendcount=0;
1466  ZNotice_t notice;
1467  Code_t code;
1468  owl_message *m=NULL;
1469
1470  while(owl_zephyr_zpending() && zpendcount < OWL_MAX_ZEPHYRGRAMS_TO_PROCESS) {
1471    if (owl_zephyr_zpending()) {
1472      if ((code = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
1473        owl_function_debugmsg("Error: %s while calling ZReceiveNotice\n",
1474                              error_message(code));
1475        continue;
1476      }
1477      zpendcount++;
1478
1479      /* is this an ack from a zephyr we sent? */
1480      if (owl_zephyr_notice_is_ack(&notice)) {
1481        owl_zephyr_handle_ack(&notice);
1482        ZFreeNotice(&notice);
1483        continue;
1484      }
1485
1486      /* if it's a ping and we're not viewing pings then skip it */
1487      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
1488        ZFreeNotice(&notice);
1489        continue;
1490      }
1491
1492      /* if it is a LOCATE message, it's for pseudologins. */
1493      if (strcmp(notice.z_opcode, LOCATE_LOCATE) == 0) {
1494        owl_zephyr_process_pseudologin(&notice);
1495        ZFreeNotice(&notice);
1496        continue;
1497      }
1498
1499      /* create the new message */
1500      m=g_new(owl_message, 1);
1501      owl_message_create_from_znotice(m, &notice);
1502
1503      owl_global_messagequeue_addmsg(&g, m);
1504    }
1505  }
1506  return zpendcount;
1507}
1508
1509typedef struct { /*noproto*/
1510  GSource source;
1511  GPollFD poll_fd;
1512} owl_zephyr_event_source;
1513
1514static GSource *owl_zephyr_event_source_new(int fd) {
1515  GSource *source;
1516  owl_zephyr_event_source *event_source;
1517
1518  source = g_source_new(&zephyr_event_funcs, sizeof(owl_zephyr_event_source));
1519  event_source = (owl_zephyr_event_source*) source;
1520  event_source->poll_fd.fd = fd;
1521  event_source->poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
1522  g_source_add_poll(source, &event_source->poll_fd);
1523
1524  return source;
1525}
1526
1527static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout) {
1528  *timeout = -1;
1529  return owl_zephyr_zqlength() > 0;
1530}
1531
1532static gboolean owl_zephyr_event_check(GSource *source) {
1533  owl_zephyr_event_source *event_source = (owl_zephyr_event_source*)source;
1534  if (event_source->poll_fd.revents & event_source->poll_fd.events)
1535    return owl_zephyr_zpending() > 0;
1536  return FALSE;
1537}
1538
1539static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
1540  _owl_zephyr_process_events();
1541  return TRUE;
1542}
1543#endif
Note: See TracBrowser for help on using the repository browser.