source: zephyr.c @ cd28517

Last change on this file since cd28517 was cd28517, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Add a zephyr GSource This may actually have some use as a GSource instead of g_idle_add since we queue messages up and only process so many at a time. The use of ZQLength isn't strictly necessary, but we may as well be fancy and wait for the poll() to tell us if there's any point in reading before doing so.
  • Property mode set to 100644
File size: 37.8 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  char *exposure, *eset;
1052  Code_t ret;
1053
1054  ZResetAuthentication();
1055
1056  eset = EXPOSE_REALMVIS;
1057  exposure = ZGetVariable(zstr("exposure"));
1058  if (exposure)
1059    exposure = ZParseExposureLevel(exposure);
1060  if (exposure)
1061    eset = exposure;
1062   
1063  ret = ZSetLocation(eset);
1064  if (ret != ZERR_NONE)
1065    owl_function_error("Error setting location: %s", error_message(ret));
1066#endif
1067}
1068
1069void owl_zephyr_zlog_out(void)
1070{
1071#ifdef HAVE_LIBZEPHYR
1072  Code_t ret;
1073
1074  ZResetAuthentication();
1075  ret = ZUnsetLocation();
1076  if (ret != ZERR_NONE)
1077    owl_function_error("Error unsetting location: %s", error_message(ret));
1078#endif
1079}
1080
1081void owl_zephyr_addbuddy(const char *name)
1082{
1083  char *filename;
1084  FILE *file;
1085 
1086  filename = owl_zephyr_dotfile(".anyone", NULL);
1087  file = fopen(filename, "a");
1088  g_free(filename);
1089  if (!file) {
1090    owl_function_error("Error opening zephyr buddy file for append");
1091    return;
1092  }
1093  fprintf(file, "%s\n", name);
1094  fclose(file);
1095}
1096
1097void owl_zephyr_delbuddy(const char *name)
1098{
1099  char *filename;
1100
1101  filename = owl_zephyr_dotfile(".anyone", NULL);
1102  owl_util_file_deleteline(filename, name, 0);
1103  g_free(filename);
1104}
1105
1106/* return auth string */
1107#ifdef HAVE_LIBZEPHYR
1108const char *owl_zephyr_get_authstr(const ZNotice_t *n)
1109{
1110
1111  if (!n) return("UNKNOWN");
1112
1113  if (n->z_auth == ZAUTH_FAILED) {
1114    return ("FAILED");
1115  } else if (n->z_auth == ZAUTH_NO) {
1116    return ("NO");
1117  } else if (n->z_auth == ZAUTH_YES) {
1118    return ("YES");
1119  } else {
1120    return ("UNKNOWN");
1121  }           
1122}
1123#else
1124const char *owl_zephyr_get_authstr(const void *n)
1125{
1126  return("");
1127}
1128#endif
1129
1130/* Returns a buffer of subscriptions or an error message.  Caller must
1131 * free the return.
1132 */
1133char *owl_zephyr_getsubs(void)
1134{
1135#ifdef HAVE_LIBZEPHYR
1136  Code_t ret;
1137  int num, i, one;
1138  ZSubscription_t sub;
1139  GString *buf;
1140
1141  ret = ZRetrieveSubscriptions(0, &num);
1142  if (ret != ZERR_NONE)
1143    return g_strdup_printf("Zephyr: Requesting subscriptions: %s\n", error_message(ret));
1144  if (num == 0)
1145    return g_strdup("Zephyr: No subscriptions retrieved\n");
1146
1147  buf = g_string_new("");
1148  for (i=0; i<num; i++) {
1149    one = 1;
1150    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1151      ZFlushSubscriptions();
1152      g_string_free(buf, true);
1153      return g_strdup_printf("Zephyr: Getting subscriptions: %s\n", error_message(ret));
1154    } else {
1155      /* g_string_append_printf would be backwards. */
1156      char *tmp = g_strdup_printf("<%s,%s,%s>\n",
1157                                  sub.zsub_class,
1158                                  sub.zsub_classinst,
1159                                  sub.zsub_recipient);
1160      g_string_prepend(buf, tmp);
1161      g_free(tmp);
1162    }
1163  }
1164
1165  ZFlushSubscriptions();
1166  return g_string_free(buf, false);
1167#else
1168  return(g_strdup("Zephyr not available"));
1169#endif
1170}
1171
1172const char *owl_zephyr_get_variable(const char *var)
1173{
1174#ifdef HAVE_LIBZEPHYR
1175  return(ZGetVariable(zstr(var)));
1176#else
1177  return("");
1178#endif
1179}
1180
1181void owl_zephyr_set_locationinfo(const char *host, const char *val)
1182{
1183#ifdef HAVE_LIBZEPHYR
1184  ZInitLocationInfo(zstr(host), zstr(val));
1185#endif
1186}
1187 
1188/* Strip a local realm fron the zephyr user name.
1189 * The caller must free the return
1190 */
1191char *short_zuser(const char *in)
1192{
1193  char *ptr = strrchr(in, '@');
1194  if (ptr && (ptr[1] == '\0' || !strcasecmp(ptr+1, owl_zephyr_get_realm()))) {
1195    return g_strndup(in, ptr - in);
1196  }
1197  return g_strdup(in);
1198}
1199
1200/* Append a local realm to the zephyr user name if necessary.
1201 * The caller must free the return.
1202 */
1203char *long_zuser(const char *in)
1204{
1205  char *ptr = strrchr(in, '@');
1206  if (ptr) {
1207    if (ptr[1])
1208      return g_strdup(in);
1209    /* Ends in @, so assume default realm. */
1210    return g_strdup_printf("%s%s", in, owl_zephyr_get_realm());
1211  }
1212  return g_strdup_printf("%s@%s", in, owl_zephyr_get_realm());
1213}
1214
1215/* Return the realm of the zephyr user name. Caller does /not/ free the return.
1216 * The string is valid at least as long as the input is.
1217 */
1218const char *zuser_realm(const char *in)
1219{
1220  char *ptr = strrchr(in, '@');
1221  /* If the name has an @ and does not end with @, use that. Otherwise, take
1222   * the default realm. */
1223  return (ptr && ptr[1]) ? (ptr+1) : owl_zephyr_get_realm();
1224}
1225
1226/* strip out the instance from a zsender's principal.  Preserves the
1227 * realm if present.  Leave host/ and daemon/ krb5 principals
1228 * alone. Also leave rcmd. and daemon. krb4 principals alone. The
1229 * caller must free the return.
1230 */
1231char *owl_zephyr_smartstripped_user(const char *in)
1232{
1233  char *slash, *dot, *realm, *out;
1234
1235  out = g_strdup(in);
1236
1237  /* bail immeaditly if we don't have to do any work */
1238  slash = strchr(out, '/');
1239  dot = strchr(out, '.');
1240  if (!slash && !dot) {
1241    return(out);
1242  }
1243
1244  if (!strncasecmp(out, OWL_ZEPHYR_NOSTRIP_HOST, strlen(OWL_ZEPHYR_NOSTRIP_HOST)) ||
1245      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_RCMD, strlen(OWL_ZEPHYR_NOSTRIP_RCMD)) ||
1246      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON5, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON5)) ||
1247      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON4, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON4))) {
1248    return(out);
1249  }
1250
1251  realm = strchr(out, '@');
1252  if (!slash && dot && realm && (dot > realm)) {
1253    /* There's no '/', and the first '.' is in the realm */
1254    return(out);
1255  }
1256
1257  /* remove the realm from out, but hold on to it */
1258  if (realm) realm[0]='\0';
1259
1260  /* strip */
1261  if (slash) slash[0] = '\0';  /* krb5 style user/instance */
1262  else if (dot) dot[0] = '\0'; /* krb4 style user.instance */
1263
1264  /* reattach the realm if we had one */
1265  if (realm) {
1266    strcat(out, "@");
1267    strcat(out, realm+1);
1268  }
1269
1270  return(out);
1271}
1272
1273/* read the list of users in 'filename' as a .anyone file, and put the
1274 * names of the zephyr users in the list 'in'.  If 'filename' is NULL,
1275 * use the default .anyone file in the users home directory.  Returns
1276 * -1 on failure, 0 on success.
1277 */
1278int owl_zephyr_get_anyone_list(owl_list *in, const char *filename)
1279{
1280#ifdef HAVE_LIBZEPHYR
1281  char *ourfile, *tmp, *s = NULL;
1282  FILE *f;
1283
1284  ourfile = owl_zephyr_dotfile(".anyone", filename);
1285
1286  f = fopen(ourfile, "r");
1287  if (!f) {
1288    owl_function_error("Error opening file %s: %s", ourfile, strerror(errno) ? strerror(errno) : "");
1289    g_free(ourfile);
1290    return -1;
1291  }
1292  g_free(ourfile);
1293
1294  while (owl_getline_chomp(&s, f)) {
1295    /* ignore comments, blank lines etc. */
1296    if (s[0] == '#' || s[0] == '\0')
1297      continue;
1298
1299    /* ignore from # on */
1300    tmp = strchr(s, '#');
1301    if (tmp)
1302      tmp[0] = '\0';
1303
1304    /* ignore from SPC */
1305    tmp = strchr(s, ' ');
1306    if (tmp)
1307      tmp[0] = '\0';
1308
1309    owl_list_append_element(in, long_zuser(s));
1310  }
1311  g_free(s);
1312  fclose(f);
1313  return 0;
1314#else
1315  return -1;
1316#endif
1317}
1318
1319#ifdef HAVE_LIBZEPHYR
1320void owl_zephyr_process_pseudologin(ZNotice_t *n)
1321{
1322  owl_message *m;
1323  owl_zbuddylist *zbl;
1324  GList **zaldlist;
1325  GList *zaldptr;
1326  ZAsyncLocateData_t *zald = NULL;
1327  ZLocations_t location;
1328  int numlocs, ret, notify;
1329
1330  /* Find a ZALD to match this notice. */
1331  zaldlist = owl_global_get_zaldlist(&g);
1332  zaldptr = g_list_first(*zaldlist);
1333  while (zaldptr) {
1334    if (ZCompareALDPred(n, zaldptr->data)) {
1335      zald = zaldptr->data;
1336      *zaldlist = g_list_remove(*zaldlist, zaldptr->data);
1337      break;
1338    }
1339    zaldptr = g_list_next(zaldptr);
1340  }
1341  if (zald) {
1342    /* Deal with notice. */
1343    notify = owl_global_get_pseudologin_notify(&g);
1344    zbl = owl_global_get_zephyr_buddylist(&g);
1345    ret = ZParseLocations(n, zald, &numlocs, NULL);
1346    if (ret == ZERR_NONE) {
1347      if (numlocs > 0 && !owl_zbuddylist_contains_user(zbl, zald->user)) {
1348        if (notify) {
1349          numlocs = 1;
1350          ret = ZGetLocations(&location, &numlocs);
1351          if (ret == ZERR_NONE) {
1352            /* Send a PSEUDO LOGIN! */
1353            m = g_new(owl_message, 1);
1354            owl_message_create_pseudo_zlogin(m, 0, zald->user,
1355                                             location.host,
1356                                             location.time,
1357                                             location.tty);
1358            owl_global_messagequeue_addmsg(&g, m);
1359          }
1360          owl_zbuddylist_adduser(zbl, zald->user);
1361          owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", zald->user);
1362        }
1363      } else if (numlocs == 0 && owl_zbuddylist_contains_user(zbl, zald->user)) {
1364        /* Send a PSEUDO LOGOUT! */
1365        if (notify) {
1366          m = g_new(owl_message, 1);
1367          owl_message_create_pseudo_zlogin(m, 1, zald->user, "", "", "");
1368          owl_global_messagequeue_addmsg(&g, m);
1369        }
1370        owl_zbuddylist_deluser(zbl, zald->user);
1371        owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ", zald->user);
1372      }
1373    }
1374    ZFreeALD(zald);
1375    g_free(zald);
1376  }
1377}
1378#else
1379void owl_zephyr_process_pseudologin(void *n)
1380{
1381}
1382#endif
1383
1384void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
1385{
1386  if (owl_global_is_pseudologins(&g)) {
1387    owl_function_debugmsg("Doing zephyr buddy check");
1388    owl_function_zephyr_buddy_check(1);
1389  } else {
1390    owl_function_debugmsg("Warning: owl_zephyr_buddycheck_timer call pointless; timer should have been disabled");
1391  }
1392}
1393
1394/*
1395 * Process zephyrgrams from libzephyr's queue. To prevent starvation,
1396 * process a maximum of OWL_MAX_ZEPHYRGRAMS_TO_PROCESS.
1397 *
1398 * Returns the number of zephyrgrams processed.
1399 */
1400
1401#define OWL_MAX_ZEPHYRGRAMS_TO_PROCESS 20
1402
1403static int _owl_zephyr_process_events(void)
1404{
1405  int zpendcount=0;
1406#ifdef HAVE_LIBZEPHYR
1407  ZNotice_t notice;
1408  Code_t code;
1409  owl_message *m=NULL;
1410
1411  while(owl_zephyr_zpending() && zpendcount < OWL_MAX_ZEPHYRGRAMS_TO_PROCESS) {
1412    if (owl_zephyr_zpending()) {
1413      if ((code = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
1414        owl_function_debugmsg("Error: %s while calling ZReceiveNotice\n",
1415                              error_message(code));
1416        continue;
1417      }
1418      zpendcount++;
1419
1420      /* is this an ack from a zephyr we sent? */
1421      if (owl_zephyr_notice_is_ack(&notice)) {
1422        owl_zephyr_handle_ack(&notice);
1423        ZFreeNotice(&notice);
1424        continue;
1425      }
1426
1427      /* if it's a ping and we're not viewing pings then skip it */
1428      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
1429        ZFreeNotice(&notice);
1430        continue;
1431      }
1432
1433      /* if it is a LOCATE message, it's for pseudologins. */
1434      if (strcmp(notice.z_opcode, LOCATE_LOCATE) == 0) {
1435        owl_zephyr_process_pseudologin(&notice);
1436        ZFreeNotice(&notice);
1437        continue;
1438      }
1439
1440      /* create the new message */
1441      m=g_new(owl_message, 1);
1442      owl_message_create_from_znotice(m, &notice);
1443
1444      owl_global_messagequeue_addmsg(&g, m);
1445    }
1446  }
1447#endif
1448  return zpendcount;
1449}
1450
1451typedef struct { /*noproto*/
1452  GSource source;
1453  GPollFD poll_fd;
1454} owl_zephyr_event_source;
1455
1456static GSource *owl_zephyr_event_source_new(int fd) {
1457  GSource *source;
1458  owl_zephyr_event_source *event_source;
1459
1460  source = g_source_new(&zephyr_event_funcs, sizeof(owl_zephyr_event_source));
1461  event_source = (owl_zephyr_event_source*) source;
1462  event_source->poll_fd.fd = fd;
1463  event_source->poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR;
1464  g_source_add_poll(source, &event_source->poll_fd);
1465
1466  return source;
1467}
1468
1469static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout) {
1470  *timeout = -1;
1471  return owl_zephyr_zqlength() > 0;
1472}
1473
1474static gboolean owl_zephyr_event_check(GSource *source) {
1475  owl_zephyr_event_source *event_source = (owl_zephyr_event_source*)source;
1476  if (event_source->poll_fd.revents & event_source->poll_fd.events)
1477    return owl_zephyr_zpending() > 0;
1478  return FALSE;
1479}
1480
1481static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
1482  _owl_zephyr_process_events();
1483  return TRUE;
1484}
Note: See TracBrowser for help on using the repository browser.