source: zephyr.c @ ea68035

release-1.10release-1.8release-1.9
Last change on this file since ea68035 was b848e30, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Fix the build on libzephyr-less machines Just don't compile the event source functions at all. There's no good reason to use them without libzephyr support. We should really move towards not building zephyr.c in that case anyway.
  • 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
9#ifdef HAVE_LIBZEPHYR
10static GSource *owl_zephyr_event_source_new(int fd);
11
12static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout);
13static gboolean owl_zephyr_event_check(GSource *source);
14static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
15
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  g_free(buffer);
450
451  return owl_zephyr_loadsubs_helper(subs, count);
452#else
453  return 0;
454#endif
455}
456
457void unsuball(void)
458{
459#if HAVE_LIBZEPHYR
460  Code_t ret;
461
462  ZResetAuthentication();
463  ret = ZCancelSubscriptions(0);
464  if (ret != ZERR_NONE)
465    owl_function_error("Zephyr: Cancelling subscriptions: %s",
466                       error_message(ret));
467#endif
468}
469
470int owl_zephyr_sub(const char *class, const char *inst, const char *recip)
471{
472#ifdef HAVE_LIBZEPHYR
473  ZSubscription_t subs[5];
474  Code_t ret;
475
476  subs[0].zsub_class=zstr(class);
477  subs[0].zsub_classinst=zstr(inst);
478  subs[0].zsub_recipient=zstr(recip);
479
480  ZResetAuthentication();
481  ret = ZSubscribeTo(subs, 1, 0);
482  if (ret != ZERR_NONE) {
483    owl_function_error("Error subbing to <%s,%s,%s>: %s",
484                       class, inst, recip,
485                       error_message(ret));
486    return(-2);
487  }
488  return(0);
489#else
490  return(0);
491#endif
492}
493
494
495int owl_zephyr_unsub(const char *class, const char *inst, const char *recip)
496{
497#ifdef HAVE_LIBZEPHYR
498  ZSubscription_t subs[5];
499  Code_t ret;
500
501  subs[0].zsub_class=zstr(class);
502  subs[0].zsub_classinst=zstr(inst);
503  subs[0].zsub_recipient=zstr(recip);
504
505  ZResetAuthentication();
506  ret = ZUnsubscribeTo(subs, 1, 0);
507  if (ret != ZERR_NONE) {
508    owl_function_error("Error unsubbing from <%s,%s,%s>: %s",
509                       class, inst, recip,
510                       error_message(ret));
511    return(-2);
512  }
513  return(0);
514#else
515  return(0);
516#endif
517}
518
519/* return a pointer to the data in the Jth field, (NULL terminated by
520 * definition).  Caller must free the return.
521 */
522#ifdef HAVE_LIBZEPHYR
523char *owl_zephyr_get_field(const ZNotice_t *n, int j)
524{
525  int i, count, save;
526
527  /* If there's no message here, just run along now */
528  if (n->z_message_len == 0)
529    return(g_strdup(""));
530
531  count=save=0;
532  for (i=0; i<n->z_message_len; i++) {
533    if (n->z_message[i]=='\0') {
534      count++;
535      if (count==j) {
536        /* just found the end of the field we're looking for */
537        return(g_strdup(n->z_message+save));
538      } else {
539        save=i+1;
540      }
541    }
542  }
543  /* catch the last field, which might not be null terminated */
544  if (count==j-1) {
545    return g_strndup(n->z_message + save, n->z_message_len - save);
546  }
547
548  return(g_strdup(""));
549}
550
551char *owl_zephyr_get_field_as_utf8(const ZNotice_t *n, int j)
552{
553  int i, count, save;
554
555  /* If there's no message here, just run along now */
556  if (n->z_message_len == 0)
557    return(g_strdup(""));
558
559  count=save=0;
560  for (i = 0; i < n->z_message_len; i++) {
561    if (n->z_message[i]=='\0') {
562      count++;
563      if (count == j) {
564        /* just found the end of the field we're looking for */
565        return(owl_validate_or_convert(n->z_message + save));
566      } else {
567        save = i + 1;
568      }
569    }
570  }
571  /* catch the last field, which might not be null terminated */
572  if (count == j - 1) {
573    char *tmp, *out;
574    tmp = g_strndup(n->z_message + save, n->z_message_len - save);
575    out = owl_validate_or_convert(tmp);
576    g_free(tmp);
577    return out;
578  }
579
580  return(g_strdup(""));
581}
582#else
583char *owl_zephyr_get_field(void *n, int j)
584{
585  return(g_strdup(""));
586}
587char *owl_zephyr_get_field_as_utf8(void *n, int j)
588{
589  return owl_zephyr_get_field(n, j);
590}
591#endif
592
593
594#ifdef HAVE_LIBZEPHYR
595int owl_zephyr_get_num_fields(const ZNotice_t *n)
596{
597  int i, fields;
598
599  if(n->z_message_len == 0)
600    return 0;
601
602  fields=1;
603  for (i=0; i<n->z_message_len; i++) {
604    if (n->z_message[i]=='\0') fields++;
605  }
606 
607  return(fields);
608}
609#else
610int owl_zephyr_get_num_fields(const void *n)
611{
612  return(0);
613}
614#endif
615
616#ifdef HAVE_LIBZEPHYR
617/* return a pointer to the message, place the message length in k
618 * caller must free the return
619 */
620char *owl_zephyr_get_message(const ZNotice_t *n, const owl_message *m)
621{
622#define OWL_NFIELDS     5
623  int i;
624  char *fields[OWL_NFIELDS + 1];
625  char *msg = NULL;
626
627  /* don't let ping messages have a body */
628  if (!strcasecmp(n->z_opcode, "ping")) {
629    return(g_strdup(""));
630  }
631
632  for(i = 0; i < OWL_NFIELDS; i++)
633    fields[i + 1] = owl_zephyr_get_field(n, i + 1);
634
635  /* deal with MIT NOC messages */
636  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")) {
637
638    msg = g_strdup_printf("%s service on %s %s\n%s", n->z_opcode, n->z_class_inst, fields[3], fields[4]);
639  }
640  /* deal with MIT Discuss messages */
641  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4") ||
642           !strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4")) {
643   
644    msg = g_strdup_printf("New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s",
645                          fields[1], fields[2], fields[3], fields[5], fields[4]);
646  }
647  /* deal with MIT Moira messages */
648  else if (!strcasecmp(n->z_default_format, "MOIRA $instance on $fromhost:\n $message\n")) {
649    msg = g_strdup_printf("MOIRA %s on %s: %s",
650                          n->z_class_inst,
651                          owl_message_get_hostname(m),
652                          fields[1]);
653  } else {
654    if (owl_zephyr_get_num_fields(n) == 1)
655      msg = g_strdup(fields[1]);
656    else
657      msg = g_strdup(fields[2]);
658  }
659
660  for (i = 0; i < OWL_NFIELDS; i++)
661    g_free(fields[i + 1]);
662
663  return msg;
664}
665#endif
666
667#ifdef HAVE_LIBZEPHYR
668const char *owl_zephyr_get_zsig(const ZNotice_t *n, int *k)
669{
670  /* return a pointer to the zsig if there is one */
671
672  /* message length 0? No zsig */
673  if (n->z_message_len==0) {
674    *k=0;
675    return("");
676  }
677
678  /* If there's only one field, no zsig */
679  if (owl_zephyr_get_num_fields(n) == 1) {
680    *k=0;
681    return("");
682  }
683
684  /* Everything else is field 1 */
685  *k=strlen(n->z_message);
686  return(n->z_message);
687}
688#else
689const char *owl_zephyr_get_zsig(const void *n, int *k)
690{
691  return("");
692}
693#endif
694
695int send_zephyr(const char *opcode, const char *zsig, const char *class, const char *instance, const char *recipient, const char *message)
696{
697#ifdef HAVE_LIBZEPHYR
698  Code_t ret;
699  ZNotice_t notice;
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  notice.z_sender=NULL;
712  if (!strcmp(recipient, "*") || !strcmp(recipient, "@")) {
713    notice.z_recipient=zstr("");
714    if (*owl_global_get_zsender(&g))
715        notice.z_sender=zstr(owl_global_get_zsender(&g));
716  } else {
717    notice.z_recipient=zstr(recipient);
718  }
719  notice.z_default_format=zstr("Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold{$1 <$sender>}\n\n$2");
720  if (opcode) notice.z_opcode=zstr(opcode);
721
722  notice.z_message_len=strlen(zsig)+1+strlen(message);
723  notice.z_message=g_new(char, notice.z_message_len+10);
724  strcpy(notice.z_message, zsig);
725  memcpy(notice.z_message+strlen(zsig)+1, message, strlen(message));
726
727  /* ret=ZSendNotice(&notice, ZAUTH); */
728  ret=ZSrvSendNotice(&notice, ZAUTH, send_zephyr_helper);
729 
730  /* free then check the return */
731  g_free(notice.z_message);
732  ZFreeNotice(&notice);
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        || *retnotice->z_recipient == 0
793        || *retnotice->z_recipient == '@') {
794      char *buff;
795      owl_function_error("No one subscribed to class %s", retnotice->z_class);
796      buff = g_strdup_printf("Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
797      owl_function_adminmsg("", buff);
798      g_free(buff);
799    } else {
800      char *buff;
801      owl_zwrite zw;
802
803      tmp = short_zuser(retnotice->z_recipient);
804      owl_function_error("%s: Not logged in or subscribing.", tmp);
805      /*
806       * These error messages are often over 80 chars, but users who want to
807       * see the whole thing can scroll to the side, and for those with wide
808       * terminals or who don't care, not splitting saves a line in the UI
809       */
810      if(strcasecmp(retnotice->z_class, "message")) {
811        buff = g_strdup_printf(
812                 "Could not send message to %s: "
813                 "not logged in or subscribing to class %s, instance %s.\n",
814                 tmp,
815                 retnotice->z_class,
816                 retnotice->z_class_inst);
817      } else if(strcasecmp(retnotice->z_class_inst, "personal")) {
818        buff = g_strdup_printf(
819                 "Could not send message to %s: "
820                 "not logged in or subscribing to instance %s.\n",
821                 tmp,
822                 retnotice->z_class_inst);
823      } else {
824        buff = g_strdup_printf(
825                 "Could not send message to %s: "
826                 "not logged in or subscribing to messages.\n",
827                 tmp);
828      }
829      owl_function_adminmsg("", buff);
830
831      memset(&zw, 0, sizeof(zw));
832      zw.class = g_strdup(retnotice->z_class);
833      zw.inst  = g_strdup(retnotice->z_class_inst);
834      zw.realm = g_strdup("");
835      zw.opcode = g_strdup(retnotice->z_opcode);
836      zw.zsig   = g_strdup("");
837      owl_list_create(&(zw.recips));
838      owl_list_append_element(&(zw.recips), g_strdup(retnotice->z_recipient));
839
840      owl_log_outgoing_zephyr_error(&zw, buff);
841
842      owl_zwrite_cleanup(&zw);
843      g_free(buff);
844      g_free(tmp);
845    }
846  } else {
847    owl_function_error("Internal error on ack (%s)", retnotice->z_message);
848  }
849}
850#else
851void owl_zephyr_handle_ack(const void *retnotice)
852{
853}
854#endif
855
856#ifdef HAVE_LIBZEPHYR
857int owl_zephyr_notice_is_ack(const ZNotice_t *n)
858{
859  if (n->z_kind == SERVNAK || n->z_kind == SERVACK || n->z_kind == HMACK) {
860    if (!strcasecmp(n->z_class, LOGIN_CLASS)) return(0);
861    return(1);
862  }
863  return(0);
864}
865#else
866int owl_zephyr_notice_is_ack(const void *n)
867{
868  return(0);
869}
870#endif
871 
872void owl_zephyr_zaway(const owl_message *m)
873{
874#ifdef HAVE_LIBZEPHYR
875  char *tmpbuff, *myuser, *to;
876  owl_zwrite *z;
877 
878  /* bail if it doesn't look like a message we should reply to.  Some
879   * of this defined by the way zaway(1) works
880   */
881  if (strcasecmp(owl_message_get_class(m), "message")) return;
882  if (strcasecmp(owl_message_get_recipient(m), ZGetSender())) return;
883  if (!strcasecmp(owl_message_get_sender(m), "")) return;
884  if (!strcasecmp(owl_message_get_opcode(m), "ping")) return;
885  if (!strcasecmp(owl_message_get_opcode(m), "auto")) return;
886  if (!strcasecmp(owl_message_get_zsig(m), "Automated reply:")) return;
887  if (!strcasecmp(owl_message_get_sender(m), ZGetSender())) return;
888  if (owl_message_get_attribute_value(m, "isauto")) return;
889
890  if (owl_global_is_smartstrip(&g)) {
891    to=owl_zephyr_smartstripped_user(owl_message_get_sender(m));
892  } else {
893    to=g_strdup(owl_message_get_sender(m));
894  }
895
896  send_zephyr("",
897              "Automated reply:",
898              owl_message_get_class(m),
899              owl_message_get_instance(m),
900              to,
901              owl_global_get_zaway_msg(&g));
902
903  myuser=short_zuser(to);
904  if (!strcasecmp(owl_message_get_instance(m), "personal")) {
905    tmpbuff = owl_string_build_quoted("zwrite %q", myuser);
906  } else {
907    tmpbuff = owl_string_build_quoted("zwrite -i %q %q", owl_message_get_instance(m), myuser);
908  }
909  g_free(myuser);
910  g_free(to);
911
912  z = owl_zwrite_new(tmpbuff);
913  g_free(tmpbuff);
914  if (z == NULL) {
915    owl_function_error("Error creating outgoing zephyr.");
916    return;
917  }
918  owl_zwrite_set_message(z, owl_global_get_zaway_msg(&g));
919  owl_zwrite_set_zsig(z, "Automated reply:");
920
921  /* display the message as an admin message in the receive window */
922  owl_function_add_outgoing_zephyrs(z);
923  owl_zwrite_delete(z);
924#endif
925}
926
927#ifdef HAVE_LIBZEPHYR
928void owl_zephyr_hackaway_cr(ZNotice_t *n)
929{
930  /* replace \r's with ' '.  Gross-ish */
931  int i;
932
933  for (i=0; i<n->z_message_len; i++) {
934    if (n->z_message[i]=='\r') {
935      n->z_message[i]=' ';
936    }
937  }
938}
939#endif
940
941char *owl_zephyr_zlocate(const char *user, int auth)
942{
943#ifdef HAVE_LIBZEPHYR
944  int ret, numlocs;
945  int one = 1;
946  ZLocations_t locations;
947  char *myuser;
948  char *p, *result;
949
950  ZResetAuthentication();
951  ret = ZLocateUser(zstr(user), &numlocs, auth ? ZAUTH : ZNOAUTH);
952  if (ret != ZERR_NONE)
953    return g_strdup_printf("Error locating user %s: %s\n",
954                           user, error_message(ret));
955
956  myuser = short_zuser(user);
957  if (numlocs == 0) {
958    result = g_strdup_printf("%s: Hidden or not logged in\n", myuser);
959  } else {
960    result = g_strdup("");
961    for (; numlocs; numlocs--) {
962      ZGetLocations(&locations, &one);
963      p = g_strdup_printf("%s%s: %s\t%s\t%s\n",
964                          result, myuser,
965                          locations.host ? locations.host : "?",
966                          locations.tty ? locations.tty : "?",
967                          locations.time ? locations.time : "?");
968      g_free(result);
969      result = p;
970    }
971  }
972  g_free(myuser);
973
974  return result;
975#else
976  return g_strdup("");
977#endif
978}
979
980void owl_zephyr_addsub(const char *filename, const char *class, const char *inst, const char *recip)
981{
982#ifdef HAVE_LIBZEPHYR
983  char *line, *subsfile, *s = NULL;
984  FILE *file;
985  int duplicate = 0;
986
987  line = owl_zephyr_makesubline(class, inst, recip);
988  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
989
990  /* if the file already exists, check to see if the sub is already there */
991  file = fopen(subsfile, "r");
992  if (file) {
993    while (owl_getline(&s, file)) {
994      if (strcasecmp(s, line) == 0) {
995        owl_function_error("Subscription already present in %s", subsfile);
996        duplicate++;
997      }
998    }
999    fclose(file);
1000    g_free(s);
1001  }
1002
1003  if (!duplicate) {
1004    file = fopen(subsfile, "a");
1005    if (file) {
1006      fputs(line, file);
1007      fclose(file);
1008      owl_function_makemsg("Subscription added");
1009    } else {
1010      owl_function_error("Error opening file %s for writing", subsfile);
1011    }
1012  }
1013
1014  g_free(line);
1015#endif
1016}
1017
1018void owl_zephyr_delsub(const char *filename, const char *class, const char *inst, const char *recip)
1019{
1020#ifdef HAVE_LIBZEPHYR
1021  char *line, *subsfile;
1022  int linesdeleted;
1023 
1024  line=owl_zephyr_makesubline(class, inst, recip);
1025  line[strlen(line)-1]='\0';
1026
1027  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
1028 
1029  linesdeleted = owl_util_file_deleteline(subsfile, line, 1);
1030  if (linesdeleted > 0) {
1031    owl_function_makemsg("Subscription removed");
1032  } else if (linesdeleted == 0) {
1033    owl_function_error("No subscription present in %s", subsfile);
1034  }
1035  g_free(subsfile);
1036  g_free(line);
1037#endif
1038}
1039
1040/* caller must free the return */
1041char *owl_zephyr_makesubline(const char *class, const char *inst, const char *recip)
1042{
1043  return g_strdup_printf("%s,%s,%s\n", class, inst, !strcmp(recip, "") ? "*" : recip);
1044}
1045
1046
1047void owl_zephyr_zlog_in(void)
1048{
1049#ifdef HAVE_LIBZEPHYR
1050  ZResetAuthentication();
1051
1052  /* ZSetLocation, and store the default value as the current value */
1053  owl_global_set_exposure(&g, owl_global_get_default_exposure(&g));
1054#endif
1055}
1056
1057void owl_zephyr_zlog_out(void)
1058{
1059#ifdef HAVE_LIBZEPHYR
1060  Code_t ret;
1061
1062  ZResetAuthentication();
1063  ret = ZUnsetLocation();
1064  if (ret != ZERR_NONE)
1065    owl_function_error("Error unsetting location: %s", error_message(ret));
1066#endif
1067}
1068
1069void owl_zephyr_addbuddy(const char *name)
1070{
1071  char *filename;
1072  FILE *file;
1073 
1074  filename = owl_zephyr_dotfile(".anyone", NULL);
1075  file = fopen(filename, "a");
1076  g_free(filename);
1077  if (!file) {
1078    owl_function_error("Error opening zephyr buddy file for append");
1079    return;
1080  }
1081  fprintf(file, "%s\n", name);
1082  fclose(file);
1083}
1084
1085void owl_zephyr_delbuddy(const char *name)
1086{
1087  char *filename;
1088
1089  filename = owl_zephyr_dotfile(".anyone", NULL);
1090  owl_util_file_deleteline(filename, name, 0);
1091  g_free(filename);
1092}
1093
1094/* return auth string */
1095#ifdef HAVE_LIBZEPHYR
1096const char *owl_zephyr_get_authstr(const ZNotice_t *n)
1097{
1098
1099  if (!n) return("UNKNOWN");
1100
1101  if (n->z_auth == ZAUTH_FAILED) {
1102    return ("FAILED");
1103  } else if (n->z_auth == ZAUTH_NO) {
1104    return ("NO");
1105  } else if (n->z_auth == ZAUTH_YES) {
1106    return ("YES");
1107  } else {
1108    return ("UNKNOWN");
1109  }           
1110}
1111#else
1112const char *owl_zephyr_get_authstr(const void *n)
1113{
1114  return("");
1115}
1116#endif
1117
1118/* Returns a buffer of subscriptions or an error message.  Caller must
1119 * free the return.
1120 */
1121char *owl_zephyr_getsubs(void)
1122{
1123#ifdef HAVE_LIBZEPHYR
1124  Code_t ret;
1125  int num, i, one;
1126  ZSubscription_t sub;
1127  GString *buf;
1128
1129  ret = ZRetrieveSubscriptions(0, &num);
1130  if (ret != ZERR_NONE)
1131    return g_strdup_printf("Zephyr: Requesting subscriptions: %s\n", error_message(ret));
1132  if (num == 0)
1133    return g_strdup("Zephyr: No subscriptions retrieved\n");
1134
1135  buf = g_string_new("");
1136  for (i=0; i<num; i++) {
1137    one = 1;
1138    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1139      ZFlushSubscriptions();
1140      g_string_free(buf, true);
1141      return g_strdup_printf("Zephyr: Getting subscriptions: %s\n", error_message(ret));
1142    } else {
1143      /* g_string_append_printf would be backwards. */
1144      char *tmp = g_strdup_printf("<%s,%s,%s>\n",
1145                                  sub.zsub_class,
1146                                  sub.zsub_classinst,
1147                                  sub.zsub_recipient);
1148      g_string_prepend(buf, tmp);
1149      g_free(tmp);
1150    }
1151  }
1152
1153  ZFlushSubscriptions();
1154  return g_string_free(buf, false);
1155#else
1156  return(g_strdup("Zephyr not available"));
1157#endif
1158}
1159
1160const char *owl_zephyr_get_variable(const char *var)
1161{
1162#ifdef HAVE_LIBZEPHYR
1163  return(ZGetVariable(zstr(var)));
1164#else
1165  return("");
1166#endif
1167}
1168
1169void owl_zephyr_set_locationinfo(const char *host, const char *val)
1170{
1171#ifdef HAVE_LIBZEPHYR
1172  ZInitLocationInfo(zstr(host), zstr(val));
1173#endif
1174}
1175
1176const char *owl_zephyr_normalize_exposure(const char *exposure)
1177{
1178  if (exposure == NULL)
1179    return NULL;
1180#ifdef HAVE_LIBZEPHYR
1181  return ZParseExposureLevel(zstr(exposure));
1182#else
1183  return exposure;
1184#endif
1185}
1186
1187int owl_zephyr_set_default_exposure(const char *exposure)
1188{
1189#ifdef HAVE_LIBZEPHYR
1190  Code_t ret;
1191  if (exposure == NULL)
1192    return -1;
1193  exposure = ZParseExposureLevel(zstr(exposure));
1194  if (exposure == NULL)
1195    return -1;
1196  ret = ZSetVariable(zstr("exposure"), zstr(exposure)); /* ZSetVariable does file I/O */
1197  if (ret != ZERR_NONE) {
1198    owl_function_error("Unable to set default exposure location: %s", error_message(ret));
1199    return -1;
1200  }
1201#endif
1202  return 0;
1203}
1204
1205const char *owl_zephyr_get_default_exposure(void)
1206{
1207#ifdef HAVE_LIBZEPHYR
1208  const char *exposure = ZGetVariable(zstr("exposure")); /* ZGetVariable does file I/O */
1209  if (exposure == NULL)
1210    return EXPOSE_REALMVIS;
1211  exposure = ZParseExposureLevel(zstr(exposure));
1212  if (exposure == NULL) /* The user manually entered an invalid value in ~/.zephyr.vars, or something weird happened. */
1213    return EXPOSE_REALMVIS;
1214  return exposure;
1215#else
1216  return "";
1217#endif
1218}
1219
1220int owl_zephyr_set_exposure(const char *exposure)
1221{
1222#ifdef HAVE_LIBZEPHYR
1223  Code_t ret;
1224  if (exposure == NULL)
1225    return -1;
1226  exposure = ZParseExposureLevel(zstr(exposure));
1227  if (exposure == NULL)
1228    return -1;
1229  ret = ZSetLocation(zstr(exposure));
1230  if (ret != ZERR_NONE) {
1231    owl_function_error("Unable to set exposure level: %s.", error_message(ret));
1232    return -1;
1233  }
1234#endif
1235  return 0;
1236}
1237 
1238/* Strip a local realm fron the zephyr user name.
1239 * The caller must free the return
1240 */
1241char *short_zuser(const char *in)
1242{
1243  char *ptr = strrchr(in, '@');
1244  if (ptr && (ptr[1] == '\0' || !strcasecmp(ptr+1, owl_zephyr_get_realm()))) {
1245    return g_strndup(in, ptr - in);
1246  }
1247  return g_strdup(in);
1248}
1249
1250/* Append a local realm to the zephyr user name if necessary.
1251 * The caller must free the return.
1252 */
1253char *long_zuser(const char *in)
1254{
1255  char *ptr = strrchr(in, '@');
1256  if (ptr) {
1257    if (ptr[1])
1258      return g_strdup(in);
1259    /* Ends in @, so assume default realm. */
1260    return g_strdup_printf("%s%s", in, owl_zephyr_get_realm());
1261  }
1262  return g_strdup_printf("%s@%s", in, owl_zephyr_get_realm());
1263}
1264
1265/* Return the realm of the zephyr user name. Caller does /not/ free the return.
1266 * The string is valid at least as long as the input is.
1267 */
1268const char *zuser_realm(const char *in)
1269{
1270  char *ptr = strrchr(in, '@');
1271  /* If the name has an @ and does not end with @, use that. Otherwise, take
1272   * the default realm. */
1273  return (ptr && ptr[1]) ? (ptr+1) : owl_zephyr_get_realm();
1274}
1275
1276/* strip out the instance from a zsender's principal.  Preserves the
1277 * realm if present.  Leave host/ and daemon/ krb5 principals
1278 * alone. Also leave rcmd. and daemon. krb4 principals alone. The
1279 * caller must free the return.
1280 */
1281char *owl_zephyr_smartstripped_user(const char *in)
1282{
1283  char *slash, *dot, *realm, *out;
1284
1285  out = g_strdup(in);
1286
1287  /* bail immeaditly if we don't have to do any work */
1288  slash = strchr(out, '/');
1289  dot = strchr(out, '.');
1290  if (!slash && !dot) {
1291    return(out);
1292  }
1293
1294  if (!strncasecmp(out, OWL_ZEPHYR_NOSTRIP_HOST, strlen(OWL_ZEPHYR_NOSTRIP_HOST)) ||
1295      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_RCMD, strlen(OWL_ZEPHYR_NOSTRIP_RCMD)) ||
1296      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON5, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON5)) ||
1297      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON4, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON4))) {
1298    return(out);
1299  }
1300
1301  realm = strchr(out, '@');
1302  if (!slash && dot && realm && (dot > realm)) {
1303    /* There's no '/', and the first '.' is in the realm */
1304    return(out);
1305  }
1306
1307  /* remove the realm from out, but hold on to it */
1308  if (realm) realm[0]='\0';
1309
1310  /* strip */
1311  if (slash) slash[0] = '\0';  /* krb5 style user/instance */
1312  else if (dot) dot[0] = '\0'; /* krb4 style user.instance */
1313
1314  /* reattach the realm if we had one */
1315  if (realm) {
1316    strcat(out, "@");
1317    strcat(out, realm+1);
1318  }
1319
1320  return(out);
1321}
1322
1323/* read the list of users in 'filename' as a .anyone file, and put the
1324 * names of the zephyr users in the list 'in'.  If 'filename' is NULL,
1325 * use the default .anyone file in the users home directory.  Returns
1326 * -1 on failure, 0 on success.
1327 */
1328int owl_zephyr_get_anyone_list(owl_list *in, const char *filename)
1329{
1330#ifdef HAVE_LIBZEPHYR
1331  char *ourfile, *tmp, *s = NULL;
1332  FILE *f;
1333
1334  ourfile = owl_zephyr_dotfile(".anyone", filename);
1335
1336  f = fopen(ourfile, "r");
1337  if (!f) {
1338    owl_function_error("Error opening file %s: %s", ourfile, strerror(errno) ? strerror(errno) : "");
1339    g_free(ourfile);
1340    return -1;
1341  }
1342  g_free(ourfile);
1343
1344  while (owl_getline_chomp(&s, f)) {
1345    /* ignore comments, blank lines etc. */
1346    if (s[0] == '#' || s[0] == '\0')
1347      continue;
1348
1349    /* ignore from # on */
1350    tmp = strchr(s, '#');
1351    if (tmp)
1352      tmp[0] = '\0';
1353
1354    /* ignore from SPC */
1355    tmp = strchr(s, ' ');
1356    if (tmp)
1357      tmp[0] = '\0';
1358
1359    owl_list_append_element(in, long_zuser(s));
1360  }
1361  g_free(s);
1362  fclose(f);
1363  return 0;
1364#else
1365  return -1;
1366#endif
1367}
1368
1369#ifdef HAVE_LIBZEPHYR
1370void owl_zephyr_process_pseudologin(ZNotice_t *n)
1371{
1372  owl_message *m;
1373  owl_zbuddylist *zbl;
1374  GList **zaldlist;
1375  GList *zaldptr;
1376  ZAsyncLocateData_t *zald = NULL;
1377  ZLocations_t location;
1378  int numlocs, ret, notify;
1379
1380  /* Find a ZALD to match this notice. */
1381  zaldlist = owl_global_get_zaldlist(&g);
1382  zaldptr = g_list_first(*zaldlist);
1383  while (zaldptr) {
1384    if (ZCompareALDPred(n, zaldptr->data)) {
1385      zald = zaldptr->data;
1386      *zaldlist = g_list_remove(*zaldlist, zaldptr->data);
1387      break;
1388    }
1389    zaldptr = g_list_next(zaldptr);
1390  }
1391  if (zald) {
1392    /* Deal with notice. */
1393    notify = owl_global_get_pseudologin_notify(&g);
1394    zbl = owl_global_get_zephyr_buddylist(&g);
1395    ret = ZParseLocations(n, zald, &numlocs, NULL);
1396    if (ret == ZERR_NONE) {
1397      if (numlocs > 0 && !owl_zbuddylist_contains_user(zbl, zald->user)) {
1398        if (notify) {
1399          numlocs = 1;
1400          ret = ZGetLocations(&location, &numlocs);
1401          if (ret == ZERR_NONE) {
1402            /* Send a PSEUDO LOGIN! */
1403            m = g_new(owl_message, 1);
1404            owl_message_create_pseudo_zlogin(m, 0, zald->user,
1405                                             location.host,
1406                                             location.time,
1407                                             location.tty);
1408            owl_global_messagequeue_addmsg(&g, m);
1409          }
1410          owl_zbuddylist_adduser(zbl, zald->user);
1411          owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", zald->user);
1412        }
1413      } else if (numlocs == 0 && owl_zbuddylist_contains_user(zbl, zald->user)) {
1414        /* Send a PSEUDO LOGOUT! */
1415        if (notify) {
1416          m = g_new(owl_message, 1);
1417          owl_message_create_pseudo_zlogin(m, 1, zald->user, "", "", "");
1418          owl_global_messagequeue_addmsg(&g, m);
1419        }
1420        owl_zbuddylist_deluser(zbl, zald->user);
1421        owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ", zald->user);
1422      }
1423    }
1424    ZFreeALD(zald);
1425    g_free(zald);
1426  }
1427}
1428#else
1429void owl_zephyr_process_pseudologin(void *n)
1430{
1431}
1432#endif
1433
1434void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
1435{
1436  if (owl_global_is_pseudologins(&g)) {
1437    owl_function_debugmsg("Doing zephyr buddy check");
1438    owl_function_zephyr_buddy_check(1);
1439  } else {
1440    owl_function_debugmsg("Warning: owl_zephyr_buddycheck_timer call pointless; timer should have been disabled");
1441  }
1442}
1443
1444/*
1445 * Process zephyrgrams from libzephyr's queue. To prevent starvation,
1446 * process a maximum of OWL_MAX_ZEPHYRGRAMS_TO_PROCESS.
1447 *
1448 * Returns the number of zephyrgrams processed.
1449 */
1450
1451#define OWL_MAX_ZEPHYRGRAMS_TO_PROCESS 20
1452
1453#ifdef HAVE_LIBZEPHYR
1454static int _owl_zephyr_process_events(void)
1455{
1456  int zpendcount=0;
1457  ZNotice_t notice;
1458  Code_t code;
1459  owl_message *m=NULL;
1460
1461  while(owl_zephyr_zpending() && zpendcount < OWL_MAX_ZEPHYRGRAMS_TO_PROCESS) {
1462    if (owl_zephyr_zpending()) {
1463      if ((code = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
1464        owl_function_debugmsg("Error: %s while calling ZReceiveNotice\n",
1465                              error_message(code));
1466        continue;
1467      }
1468      zpendcount++;
1469
1470      /* is this an ack from a zephyr we sent? */
1471      if (owl_zephyr_notice_is_ack(&notice)) {
1472        owl_zephyr_handle_ack(&notice);
1473        ZFreeNotice(&notice);
1474        continue;
1475      }
1476
1477      /* if it's a ping and we're not viewing pings then skip it */
1478      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
1479        ZFreeNotice(&notice);
1480        continue;
1481      }
1482
1483      /* if it is a LOCATE message, it's for pseudologins. */
1484      if (strcmp(notice.z_opcode, LOCATE_LOCATE) == 0) {
1485        owl_zephyr_process_pseudologin(&notice);
1486        ZFreeNotice(&notice);
1487        continue;
1488      }
1489
1490      /* create the new message */
1491      m=g_new(owl_message, 1);
1492      owl_message_create_from_znotice(m, &notice);
1493
1494      owl_global_messagequeue_addmsg(&g, m);
1495    }
1496  }
1497  return zpendcount;
1498}
1499
1500typedef struct { /*noproto*/
1501  GSource source;
1502  GPollFD poll_fd;
1503} owl_zephyr_event_source;
1504
1505static GSource *owl_zephyr_event_source_new(int fd) {
1506  GSource *source;
1507  owl_zephyr_event_source *event_source;
1508
1509  source = g_source_new(&zephyr_event_funcs, sizeof(owl_zephyr_event_source));
1510  event_source = (owl_zephyr_event_source*) source;
1511  event_source->poll_fd.fd = fd;
1512  event_source->poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR;
1513  g_source_add_poll(source, &event_source->poll_fd);
1514
1515  return source;
1516}
1517
1518static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout) {
1519  *timeout = -1;
1520  return owl_zephyr_zqlength() > 0;
1521}
1522
1523static gboolean owl_zephyr_event_check(GSource *source) {
1524  owl_zephyr_event_source *event_source = (owl_zephyr_event_source*)source;
1525  if (event_source->poll_fd.revents & event_source->poll_fd.events)
1526    return owl_zephyr_zpending() > 0;
1527  return FALSE;
1528}
1529
1530static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
1531  _owl_zephyr_process_events();
1532  return TRUE;
1533}
1534#endif
Note: See TracBrowser for help on using the repository browser.