Merged pidgin/main into default
[pidgin-git.git] / libpurple / protocols / zephyr / Zinternal.c
blobd87320d4f8d56f6e963f329e995f99940535283c
1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the internal Zephyr routines.
4 * Created by: Robert French
6 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of
7 * Technology.
8 * For copying and distribution information, see the file
9 * "mit-copyright.h".
12 #include "internal.h"
13 #ifdef WIN32
14 #include <winsock2.h>
16 #ifndef ZEPHYR_USES_KERBEROS
17 int gettimeofday(struct timeval* p, struct timezone* tz ){
18 union {
19 long long ns100; /*time since 1 Jan 1601 in 100ns units */
20 FILETIME ft;
21 } _now;
23 GetSystemTimeAsFileTime( &(_now.ft) );
24 p->tv_usec=(long)((_now.ns100 / 10LL) % 1000000LL );
25 p->tv_sec= (long)((_now.ns100-(116444736000000000LL))/10000000LL);
26 return 0;
28 #endif
30 #else
31 #include <arpa/inet.h>
32 #include <sys/socket.h>
33 #endif
35 int __Zephyr_fd = -1;
36 int __Zephyr_open;
37 int __Zephyr_port = -1;
38 struct in_addr __My_addr;
39 int __Q_CompleteLength;
40 int __Q_Size;
41 struct _Z_InputQ *__Q_Head, *__Q_Tail;
42 struct sockaddr_in __HM_addr;
43 struct sockaddr_in __HM_addr_real;
44 int __HM_set;
45 int __Zephyr_server;
46 ZLocations_t *__locate_list;
47 int __locate_num;
48 int __locate_next;
49 ZSubscription_t *__subscriptions_list;
50 int __subscriptions_num;
51 int __subscriptions_next;
52 int Z_discarded_packets = 0;
54 #ifdef ZEPHYR_USES_KERBEROS
55 C_Block __Zephyr_session;
56 #endif
57 char __Zephyr_realm[REALM_SZ];
59 #ifdef Z_DEBUG
60 void (*__Z_debug_print) __P((const char *fmt, va_list args, void *closure));
61 void *__Z_debug_print_closure;
62 #endif
64 #define min(a,b) ((a)<(b)?(a):(b))
66 static int Z_AddField __P((char **ptr, const char *field, char *end));
67 static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind));
69 /* Find or insert uid in the old uids buffer. The buffer is a sorted
70 * circular queue. We make the assumption that most packets arrive in
71 * order, so we can usually search for a uid or insert it into the buffer
72 * by looking back just a few entries from the end. Since this code is
73 * only executed by the client, the implementation isn't microoptimized. */
74 static int find_or_insert_uid(uid, kind)
75 ZUnique_Id_t *uid;
76 ZNotice_Kind_t kind;
78 static struct _filter {
79 ZUnique_Id_t uid;
80 ZNotice_Kind_t kind;
81 time_t t;
82 } *buffer;
83 static long size;
84 static long start;
85 static long num;
87 time_t now;
88 struct _filter *new;
89 long i, j, new_size;
90 int result;
92 /* Initialize the uid buffer if it hasn't been done already. */
93 if (!buffer) {
94 size = Z_INITFILTERSIZE;
95 buffer = (struct _filter *) malloc(size * sizeof(*buffer));
96 if (!buffer)
97 return 0;
100 /* Age the uid buffer, discarding any uids older than the clock skew. */
101 time(&now);
102 while (num && (now - buffer[start % size].t) > CLOCK_SKEW)
103 start++, num--;
104 start %= size;
106 /* Make room for a new uid, since we'll probably have to insert one. */
107 if (num == size) {
108 new_size = size * 2 + 2;
109 new = (struct _filter *) malloc(new_size * sizeof(*new));
110 if (!new)
111 return 0;
112 for (i = 0; i < num; i++)
113 new[i] = buffer[(start + i) % size];
114 free(buffer);
115 buffer = new;
116 size = new_size;
117 start = 0;
120 /* Search for this uid in the buffer, starting from the end. */
121 for (i = start + num - 1; i >= start; i--) {
122 result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid));
123 if (result == 0 && buffer[i % size].kind == kind)
124 return 1;
125 if (result > 0)
126 break;
129 /* We didn't find it; insert the uid into the buffer after i. */
130 i++;
131 for (j = start + num; j > i; j--)
132 buffer[j % size] = buffer[(j - 1) % size];
133 buffer[i % size].uid = *uid;
134 buffer[i % size].kind = kind;
135 buffer[i % size].t = now;
136 num++;
138 return 0;
142 /* Return 1 if there is a packet waiting, 0 otherwise */
144 static int Z_PacketWaiting(void)
146 struct timeval tv;
147 fd_set read;
149 tv.tv_sec = tv.tv_usec = 0;
150 FD_ZERO(&read);
151 FD_SET(ZGetFD(), &read);
152 return (select(ZGetFD() + 1, &read, NULL, NULL, &tv));
156 /* Wait for a complete notice to become available */
158 Code_t Z_WaitForComplete(void)
160 Code_t retval;
162 if (__Q_CompleteLength)
163 return (Z_ReadEnqueue());
165 while (!__Q_CompleteLength)
166 if ((retval = Z_ReadWait()) != ZERR_NONE)
167 return (retval);
169 return (ZERR_NONE);
173 /* Read any available packets and enqueue them */
175 Code_t Z_ReadEnqueue()
177 Code_t retval;
179 if (ZGetFD() < 0)
180 return (ZERR_NOPORT);
182 while (Z_PacketWaiting())
183 if ((retval = Z_ReadWait()) != ZERR_NONE)
184 return (retval);
186 return (ZERR_NONE);
191 * Search the queue for a notice with the proper multiuid - remove any
192 * notices that haven't been touched in a while
195 static struct _Z_InputQ *Z_SearchQueue(ZUnique_Id_t *uid, ZNotice_Kind_t kind)
197 register struct _Z_InputQ *qptr;
198 struct _Z_InputQ *next;
199 struct timeval tv;
201 (void) gettimeofday(&tv, (struct timezone *)0);
203 qptr = __Q_Head;
205 while (qptr) {
206 if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind)
207 return (qptr);
208 next = qptr->next;
209 if (qptr->timep && ((time_t)qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec))
210 Z_RemQueue(qptr);
211 qptr = next;
213 return (NULL);
217 * Now we delve into really convoluted queue handling and
218 * fragmentation reassembly algorithms and other stuff you probably
219 * don't want to look at...
221 * This routine does NOT guarantee a complete packet will be ready when it
222 * returns.
225 Code_t Z_ReadWait()
227 register struct _Z_InputQ *qptr;
228 ZNotice_t notice;
229 ZPacket_t packet;
230 struct sockaddr_in olddest, from;
231 int packet_len, zvlen, part, partof;
232 socklen_t from_len;
233 char *slash;
234 Code_t retval;
235 fd_set fds;
236 struct timeval tv;
238 if (ZGetFD() < 0)
239 return (ZERR_NOPORT);
241 FD_ZERO(&fds);
242 FD_SET(ZGetFD(), &fds);
243 tv.tv_sec = 60;
244 tv.tv_usec = 0;
246 if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
247 return (errno);
248 if (!FD_ISSET(ZGetFD(), &fds))
249 return ETIMEDOUT;
251 from_len = sizeof(struct sockaddr_in);
253 packet_len = recvfrom(ZGetFD(), packet, sizeof(packet) - 1, 0,
254 (struct sockaddr *)&from, &from_len);
256 if (packet_len < 0)
257 return (errno);
259 if (!packet_len)
260 return (ZERR_EOF);
262 packet[packet_len] = '\0';
264 /* Ignore obviously non-Zephyr packets. */
265 zvlen = sizeof(ZVERSIONHDR) - 1;
266 if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) {
267 Z_discarded_packets++;
268 return (ZERR_NONE);
271 /* Parse the notice */
272 if ((retval = ZParseNotice(packet, packet_len, &notice)) != ZERR_NONE)
273 return (retval);
276 * If we're not a server and the notice is of an appropriate kind,
277 * send back a CLIENTACK to whoever sent it to say we got it.
279 if (!__Zephyr_server) {
280 if (notice.z_kind != HMACK && notice.z_kind != SERVACK &&
281 notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) {
282 ZNotice_t tmpnotice;
283 ZPacket_t pkt;
284 int len;
286 tmpnotice = notice;
287 tmpnotice.z_kind = CLIENTACK;
288 tmpnotice.z_message_len = 0;
289 olddest = __HM_addr;
290 __HM_addr = from;
291 if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len))
292 != ZERR_NONE)
293 return(retval);
294 if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE)
295 return (retval);
296 __HM_addr = olddest;
298 if (find_or_insert_uid(&notice.z_uid, notice.z_kind))
299 return(ZERR_NONE);
301 /* Check authentication on the notice. */
302 notice.z_checked_auth = ZCheckAuthentication(&notice, &from);
307 * Parse apart the z_multinotice field - if the field is blank for
308 * some reason, assume this packet stands by itself.
310 slash = strchr(notice.z_multinotice, '/');
311 if (slash) {
312 part = atoi(notice.z_multinotice);
313 partof = atoi(slash+1);
314 if (part > partof || partof == 0) {
315 part = 0;
316 partof = notice.z_message_len;
319 else {
320 part = 0;
321 partof = notice.z_message_len;
324 /* Too big a packet...just ignore it! */
325 if (partof > Z_MAXNOTICESIZE)
326 return (ZERR_NONE);
329 * If we aren't a server and we can find a notice in the queue
330 * with the same multiuid field, insert the current fragment as
331 * appropriate.
333 switch (notice.z_kind) {
334 case SERVACK:
335 case SERVNAK:
336 /* The SERVACK and SERVNAK replies shouldn't be reassembled
337 (they have no parts). Instead, we should hold on to the reply
338 ONLY if it's the first part of a fragmented message, i.e.
339 multi_uid == uid. This allows programs to wait for the uid
340 of the first packet, and get a response when that notice
341 arrives. Acknowledgements of the other fragments are discarded
342 (XXX we assume here that they all carry the same information
343 regarding failure/success)
345 if (!__Zephyr_server &&
346 !ZCompareUID(&notice.z_multiuid, &notice.z_uid))
347 /* they're not the same... throw away this packet. */
348 return(ZERR_NONE);
349 /* fall thru & process it */
350 default:
351 /* for HMACK types, we assume no packet loss (local loopback
352 connections). The other types can be fragmented and MUST
353 run through this code. */
354 if (!__Zephyr_server && (qptr = Z_SearchQueue(&notice.z_multiuid,
355 notice.z_kind))) {
357 * If this is the first fragment, and we haven't already
358 * gotten a first fragment, grab the header from it.
360 if (part == 0 && !qptr->header) {
361 qptr->header_len = packet_len-notice.z_message_len;
362 qptr->header = (char *) malloc((unsigned) qptr->header_len);
363 if (!qptr->header)
364 return (ENOMEM);
365 (void) memcpy(qptr->header, packet, qptr->header_len);
367 return (Z_AddNoticeToEntry(qptr, &notice, part));
372 * We'll have to create a new entry...make sure the queue isn't
373 * going to get too big.
375 if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
376 return (ZERR_NONE);
379 * This is a notice we haven't heard of, so create a new queue
380 * entry for it and zero it out.
382 qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ));
383 if (!qptr)
384 return (ENOMEM);
385 (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ));
387 /* Insert the entry at the end of the queue */
388 qptr->next = NULL;
389 qptr->prev = __Q_Tail;
390 if (__Q_Tail)
391 __Q_Tail->next = qptr;
392 __Q_Tail = qptr;
394 if (!__Q_Head)
395 __Q_Head = qptr;
398 /* Copy the from field, multiuid, kind, and checked authentication. */
399 qptr->from = from;
400 qptr->uid = notice.z_multiuid;
401 qptr->kind = notice.z_kind;
402 qptr->auth = notice.z_checked_auth;
405 * If this is the first part of the notice, we take the header
406 * from it. We only take it if this is the first fragment so that
407 * the Unique ID's will be predictable.
409 * If a Zephyr Server, we always take the header.
411 if (__Zephyr_server || part == 0) {
412 qptr->header_len = packet_len-notice.z_message_len;
413 qptr->header = (char *) malloc((unsigned) qptr->header_len);
414 if (!qptr->header)
415 return ENOMEM;
416 (void) memcpy(qptr->header, packet, qptr->header_len);
420 * If this is not a fragmented notice, then don't bother with a
421 * hole list.
422 * If we are a Zephyr server, all notices are treated as complete.
424 if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) {
425 __Q_CompleteLength++;
426 qptr->holelist = (struct _Z_Hole *) 0;
427 qptr->complete = 1;
428 /* allocate a msg buf for this piece */
429 if (notice.z_message_len == 0)
430 qptr->msg = 0;
431 else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len)))
432 return(ENOMEM);
433 else
434 (void) memcpy(qptr->msg, notice.z_message, notice.z_message_len);
435 qptr->msg_len = notice.z_message_len;
436 __Q_Size += notice.z_message_len;
437 qptr->packet_len = qptr->header_len+qptr->msg_len;
438 if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
439 return (ENOMEM);
440 (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
441 if(qptr->msg)
442 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
443 qptr->msg_len);
444 return (ZERR_NONE);
448 * We know how long the message is going to be (this is better
449 * than IP fragmentation...), so go ahead and allocate it all.
451 if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
452 return (ENOMEM);
453 qptr->msg_len = partof;
454 __Q_Size += partof;
457 * Well, it's a fragmented notice...allocate a hole list and
458 * initialize it to the full packet size. Then insert the
459 * current fragment.
461 if (!(qptr->holelist = (struct _Z_Hole *)
462 malloc(sizeof(struct _Z_Hole))))
463 return (ENOMEM);
464 qptr->holelist->next = (struct _Z_Hole *) 0;
465 qptr->holelist->first = 0;
466 qptr->holelist->last = partof-1;
467 return (Z_AddNoticeToEntry(qptr, &notice, part));
471 /* Fragment management routines - compliments, more or less, of RFC815 */
473 Code_t Z_AddNoticeToEntry(qptr, notice, part)
474 struct _Z_InputQ *qptr;
475 ZNotice_t *notice;
476 int part;
478 int last, oldfirst, oldlast;
479 struct _Z_Hole *hole, *lasthole;
480 struct timeval tv;
482 /* Incorporate this notice's checked authentication. */
483 if (notice->z_checked_auth == ZAUTH_FAILED)
484 qptr->auth = ZAUTH_FAILED;
485 else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED)
486 qptr->auth = ZAUTH_NO;
488 (void) gettimeofday(&tv, (struct timezone *)0);
489 qptr->timep = tv.tv_sec;
491 last = part+notice->z_message_len-1;
493 hole = qptr->holelist;
494 lasthole = (struct _Z_Hole *) 0;
496 /* copy in the message body */
497 (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
499 /* Search for a hole that overlaps with the current fragment */
500 while (hole) {
501 if (part <= hole->last && last >= hole->first)
502 break;
503 lasthole = hole;
504 hole = hole->next;
507 /* If we found one, delete it and reconstruct a new hole */
508 if (hole) {
509 oldfirst = hole->first;
510 oldlast = hole->last;
511 if (lasthole)
512 lasthole->next = hole->next;
513 else
514 qptr->holelist = hole->next;
515 free((char *)hole);
517 * Now create a new hole that is the original hole without the
518 * current fragment.
520 if (part > oldfirst) {
521 /* Search for the end of the hole list */
522 hole = qptr->holelist;
523 lasthole = (struct _Z_Hole *) 0;
524 while (hole) {
525 lasthole = hole;
526 hole = hole->next;
528 if (lasthole) {
529 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
530 if (!inputq)
531 return (ENOMEM);
532 lasthole->next = (struct _Z_Hole *)inputq;
533 hole = lasthole->next;
535 else {
536 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
537 if (!inputq)
538 return (ENOMEM);
539 qptr->holelist = (struct _Z_Hole *)inputq;
540 hole = qptr->holelist;
542 hole->next = NULL;
543 hole->first = oldfirst;
544 hole->last = part-1;
546 if (last < oldlast) {
547 /* Search for the end of the hole list */
548 hole = qptr->holelist;
549 lasthole = (struct _Z_Hole *) 0;
550 while (hole) {
551 lasthole = hole;
552 hole = hole->next;
554 if (lasthole) {
555 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
556 if (!inputq)
557 return (ENOMEM);
558 lasthole->next = (struct _Z_Hole *)inputq;
559 hole = lasthole->next;
561 else {
562 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
563 if (!inputq)
564 return (ENOMEM);
565 qptr->holelist = (struct _Z_Hole *)inputq;
566 hole = qptr->holelist;
568 hole->next = (struct _Z_Hole *) 0;
569 hole->first = last+1;
570 hole->last = oldlast;
574 if (!qptr->holelist) {
575 if (!qptr->complete)
576 __Q_CompleteLength++;
577 qptr->complete = 1;
578 qptr->timep = 0; /* don't time out anymore */
579 qptr->packet_len = qptr->header_len+qptr->msg_len;
580 if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
581 return (ENOMEM);
582 (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
583 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
584 qptr->msg_len);
587 return (ZERR_NONE);
590 Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
591 ZNotice_t *notice;
592 char *buffer;
593 int buffer_len;
594 int *len;
595 Z_AuthProc cert_routine;
597 Code_t retval;
598 static char version[BUFSIZ]; /* default init should be all \0 */
599 struct sockaddr_in name;
600 socklen_t namelen = sizeof(name);
602 if (!notice->z_sender)
603 notice->z_sender = ZGetSender();
605 if (notice->z_port == 0) {
606 if (ZGetFD() < 0) {
607 retval = ZOpenPort((unsigned short *)0);
608 if (retval != ZERR_NONE)
609 return (retval);
611 retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
612 if (retval != 0)
613 return (retval);
614 notice->z_port = name.sin_port;
617 notice->z_multinotice = "";
619 (void) gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
620 notice->z_uid.tv.tv_sec = htonl((unsigned long) notice->z_uid.tv.tv_sec);
621 notice->z_uid.tv.tv_usec = htonl((unsigned long) notice->z_uid.tv.tv_usec);
623 (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
625 notice->z_multiuid = notice->z_uid;
627 if (!version[0])
628 (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
629 ZVERSIONMINOR);
630 notice->z_version = version;
632 return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
635 Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
636 ZNotice_t *notice;
637 char *buffer;
638 int buffer_len;
639 int *len;
640 Z_AuthProc cert_routine;
642 if (!cert_routine) {
643 notice->z_auth = 0;
644 notice->z_authent_len = 0;
645 notice->z_ascii_authent = "";
646 notice->z_checksum = 0;
647 return (Z_FormatRawHeader(notice, buffer, buffer_len,
648 len, NULL, NULL));
651 return ((*cert_routine)(notice, buffer, buffer_len, len));
654 Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
655 ZNotice_t *notice;
656 char *buffer;
657 gsize buffer_len;
658 int *len;
659 char **cstart, **cend;
661 char newrecip[BUFSIZ];
662 char *ptr, *end;
663 int i;
665 if (!notice->z_class)
666 notice->z_class = "";
668 if (!notice->z_class_inst)
669 notice->z_class_inst = "";
671 if (!notice->z_opcode)
672 notice->z_opcode = "";
674 if (!notice->z_recipient)
675 notice->z_recipient = "";
677 if (!notice->z_default_format)
678 notice->z_default_format = "";
680 ptr = buffer;
681 end = buffer+buffer_len;
683 if (buffer_len < strlen(notice->z_version)+1)
684 return (ZERR_HEADERLEN);
686 g_strlcpy(ptr, notice->z_version, buffer_len);
687 ptr += strlen(ptr)+1;
689 if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
690 == ZERR_FIELDLEN)
691 return (ZERR_HEADERLEN);
692 ptr += strlen(ptr)+1;
694 if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
695 return (ZERR_HEADERLEN);
696 ptr += strlen(ptr)+1;
698 if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid,
699 sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
700 return (ZERR_HEADERLEN);
701 ptr += strlen(ptr)+1;
703 if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
704 return (ZERR_HEADERLEN);
705 ptr += strlen(ptr)+1;
707 if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
708 return (ZERR_HEADERLEN);
709 ptr += strlen(ptr)+1;
711 if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
712 return (ZERR_HEADERLEN);
713 ptr += strlen(ptr)+1;
715 if (Z_AddField(&ptr, notice->z_ascii_authent, end))
716 return (ZERR_HEADERLEN);
717 if (Z_AddField(&ptr, notice->z_class, end))
718 return (ZERR_HEADERLEN);
719 if (Z_AddField(&ptr, notice->z_class_inst, end))
720 return (ZERR_HEADERLEN);
721 if (Z_AddField(&ptr, notice->z_opcode, end))
722 return (ZERR_HEADERLEN);
723 if (Z_AddField(&ptr, notice->z_sender, end))
724 return (ZERR_HEADERLEN);
725 if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
726 if (Z_AddField(&ptr, notice->z_recipient, end))
727 return (ZERR_HEADERLEN);
729 else {
730 if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
731 sizeof(newrecip))
732 return (ZERR_HEADERLEN);
733 (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
734 if (Z_AddField(&ptr, newrecip, end))
735 return (ZERR_HEADERLEN);
737 if (Z_AddField(&ptr, notice->z_default_format, end))
738 return (ZERR_HEADERLEN);
740 /* copy back the end pointer location for crypto checksum */
741 if (cstart)
742 *cstart = ptr;
743 if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
744 return (ZERR_HEADERLEN);
745 ptr += strlen(ptr)+1;
746 if (cend)
747 *cend = ptr;
749 if (Z_AddField(&ptr, notice->z_multinotice, end))
750 return (ZERR_HEADERLEN);
752 if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid,
753 sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
754 return (ZERR_HEADERLEN);
755 ptr += strlen(ptr)+1;
757 for (i=0;i<notice->z_num_other_fields;i++)
758 if (Z_AddField(&ptr, notice->z_other_fields[i], end))
759 return (ZERR_HEADERLEN);
761 *len = ptr-buffer;
763 return (ZERR_NONE);
766 static int
767 Z_AddField(char **ptr, const char *field, char *end)
769 register int len;
771 len = field ? strlen (field) + 1 : 1;
773 if (*ptr+len > end)
774 return 1;
775 if (field)
776 strcpy(*ptr, field);
777 else
778 **ptr = '\0';
779 *ptr += len;
781 return 0;
784 struct _Z_InputQ *Z_GetFirstComplete()
786 struct _Z_InputQ *qptr;
788 qptr = __Q_Head;
790 while (qptr) {
791 if (qptr->complete)
792 return (qptr);
793 qptr = qptr->next;
796 return ((struct _Z_InputQ *)0);
799 struct _Z_InputQ *Z_GetNextComplete(qptr)
800 struct _Z_InputQ *qptr;
802 qptr = qptr->next;
803 while (qptr) {
804 if (qptr->complete)
805 return (qptr);
806 qptr = qptr->next;
809 return ((struct _Z_InputQ *)0);
812 void Z_RemQueue(qptr)
813 struct _Z_InputQ *qptr;
815 struct _Z_Hole *hole, *nexthole;
817 if (qptr->complete)
818 __Q_CompleteLength--;
820 __Q_Size -= qptr->msg_len;
822 free(qptr->header);
823 free(qptr->msg);
824 free(qptr->packet);
826 hole = qptr->holelist;
827 while (hole) {
828 nexthole = hole->next;
829 free((char *)hole);
830 hole = nexthole;
833 if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
834 free ((char *)qptr);
835 __Q_Head = (struct _Z_InputQ *)0;
836 __Q_Tail = (struct _Z_InputQ *)0;
837 return;
840 if (qptr == __Q_Head) {
841 __Q_Head = qptr->next;
842 __Q_Head->prev = (struct _Z_InputQ *)0;
843 free ((char *)qptr);
844 return;
846 if (qptr == __Q_Tail) {
847 __Q_Tail = qptr->prev;
848 __Q_Tail->next = (struct _Z_InputQ *)0;
849 free ((char *)qptr);
850 return;
852 qptr->prev->next = qptr->next;
853 qptr->next->prev = qptr->prev;
854 free ((char *)qptr);
855 return;
858 Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func)
859 ZNotice_t *notice;
860 int len;
861 Z_AuthProc cert_func;
862 Z_SendProc send_func;
864 ZNotice_t partnotice;
865 ZPacket_t buffer;
866 char multi[64];
867 int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
868 Code_t retval;
870 hdrsize = len-notice->z_message_len;
871 fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
873 offset = 0;
875 waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
876 && !__Zephyr_server);
878 partnotice = *notice;
880 while (offset < notice->z_message_len || !notice->z_message_len) {
881 (void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
882 partnotice.z_multinotice = multi;
883 if (offset > 0) {
884 (void) gettimeofday(&partnotice.z_uid.tv,
885 (struct timezone *)0);
886 partnotice.z_uid.tv.tv_sec =
887 htonl((unsigned long) partnotice.z_uid.tv.tv_sec);
888 partnotice.z_uid.tv.tv_usec =
889 htonl((unsigned long) partnotice.z_uid.tv.tv_usec);
890 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
891 sizeof(__My_addr));
893 message_len = min(notice->z_message_len-offset, fragsize);
894 partnotice.z_message = (char*)notice->z_message+offset;
895 partnotice.z_message_len = message_len;
896 if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
897 &ret_len, cert_func)) != ZERR_NONE) {
898 return (retval);
900 memcpy(buffer + ret_len, partnotice.z_message, message_len);
901 if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
902 waitforack)) != ZERR_NONE) {
903 return (retval);
905 offset += fragsize;
906 if (!notice->z_message_len)
907 break;
910 return (ZERR_NONE);
913 /*ARGSUSED*/
914 Code_t Z_XmitFragment(notice, buf, len, wait)
915 ZNotice_t *notice;
916 char *buf;
917 int len;
918 int wait;
920 return(ZSendPacket(buf, len, wait));
923 #ifdef Z_DEBUG
924 /* For debugging printing */
925 const char *const ZNoticeKinds[] = {
926 "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
927 "CLIENTACK", "STAT"
929 #endif
931 #ifdef Z_DEBUG
933 #undef Z_debug
934 void Z_debug (const char *format, ...)
936 va_list pvar;
937 if (!__Z_debug_print)
938 return;
939 va_start (pvar, format);
940 (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
941 va_end (pvar);
944 void Z_debug_stderr (format, args, closure)
945 const char *format;
946 va_list args;
947 void *closure;
949 vfprintf (stderr, format, args);
950 putc ('\n', stderr);
953 #undef ZGetFD
954 int ZGetFD () { return __Zephyr_fd; }
956 #undef ZQLength
957 int ZQLength () { return __Q_CompleteLength; }
959 #undef ZGetDestAddr
960 struct sockaddr_in ZGetDestAddr () { return __HM_addr; }
962 #undef ZGetRealm
963 Zconst char * ZGetRealm () { return __Zephyr_realm; }
965 #undef ZSetDebug
966 void ZSetDebug(proc, arg)
967 void (*proc) __P((const char *, va_list, void *));
968 char *arg;
970 __Z_debug_print = proc;
971 __Z_debug_print_closure = arg;
973 #endif /* Z_DEBUG */