source: zephyr.c @ 32ad44d

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