source: zephyr.c @ b343c2c

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