source: zephyr.c @ 7655e08

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