1 #ifdef RCS
2 static char rcsid[]="$Id: link.c,v 1.1.1.1 2000/11/13 02:42:45 holsta Exp $";
3 #endif
4 /******************************************************************************
5  *                    Internetting Cooperating Programmers
6  * ----------------------------------------------------------------------------
7  *
8  *  ____    PROJECT
9  * |  _ \  __ _ _ __   ___ ___ _ __
10  * | | | |/ _` | '_ \ / __/ _ \ '__|
11  * | |_| | (_| | | | | (_|  __/ |
12  * |____/ \__,_|_| |_|\___\___|_|   the IRC bot
13  *
14  * All files in this archive are subject to the GNU General Public License.
15  *
16  * $Source: /cvsroot/dancer/dancer/src/link.c,v $
17  * $Revision: 1.1.1.1 $
18  * $Date: 2000/11/13 02:42:45 $
19  * $Author: holsta $
20  * $State: Exp $
21  * $Locker:  $
22  *
23  * ---------------------------------------------------------------------------
24  *****************************************************************************/
25 
26 /*
27  * - Exchange of userlist not implemented.
28  * - Problems when linking more than two clusters of linkbots
29  *   together (only one cluster gets to know about the other
30  *   cluster)
31  */
32 
33 /*
34  * Define to test reliability. If defined it will skip acks
35  * and send duplicates at random. Don't do this at home, kids.
36  */
37 #undef UNRELIABLE
38 
39 #include "dancer.h"
40 #include "trio.h"
41 #include "strio.h"
42 #include "list.h"
43 #include "user.h"
44 #include "transfer.h"
45 #include "link.h"
46 #include "command.h"
47 #include "function.h"
48 
49 #include <stdarg.h>
50 #include <sys/socket.h>
51 
52 #define TIMEREQUEST (-1)
53 
54 extern time_t now;
55 extern int linkSocket;
56 
57 extern struct sockaddr_in fromaddr;
58 extern itemuser *userHead;
59 extern itemlink *linkHead;
60 extern char nickname[];
61 extern ulong linkvalue;
62 extern long levels[];
63 
64 time_t commontime = 0; /* Reference zero time */
65 
66 
67 /* ----------------------------------------------------------------
68  *
69  *  Level 1 routines
70  *
71  * ---------------------------------------------------------------- */
72 
73 /*
74  * Various routines to provide reliable message passing. The rtt_XXX
75  * routines are taken from chapter 8.4 of "Unix Network Programming"
76  * by Stevens. Didn't bother to add the comments.
77  */
78 
79 #ifdef UNRELIABLE
80 int exp_backoff[] = {1, 1, 1, 1, 1};
81 #else
82 int exp_backoff[] = {1, 2, 4, 8, 16};
83 #endif
84 int whatever[] = {1, 1};
85 
86 #define RTT_RXTMIN 2
87 #define RTT_RXTMAX 120
88 #define RTT_MAXNREXMT (sizeof(exp_backoff)/sizeof(exp_backoff[0]))
89 
rtt_init(itemlink * r)90 void rtt_init(itemlink *r)
91 {
92   snapshot;
93   r->rtt_rtt = r->rtt_srtt = 0;
94   r->rtt_rttdev = 1.5;
95   r->rtt_nxtrto = 0;
96 }
97 
rtt_newpack(itemlink * r)98 inline void rtt_newpack(itemlink *r)
99 {
100   snapshot;
101   r->rtt_nrexmt = 0;
102 }
103 
104 /* Returns timeout value */
rtt_start(itemlink * r)105 int rtt_start(itemlink *r)
106 {
107   int rexmt;
108 
109   snapshot;
110   if (r->rtt_nrexmt > 0) {
111     r->rtt_currto *= exp_backoff[r->rtt_nrexmt];
112     return (r->rtt_currto);
113   }
114   gettimeofday(&r->time_start, NULL);
115   if (r->rtt_nxtrto > 0) {
116     r->rtt_currto = r->rtt_nxtrto;
117     r->rtt_nxtrto = 0;
118     return (r->rtt_currto);
119   }
120   rexmt = (int)(r->rtt_srtt + (2.0 * r->rtt_rttdev) + 0.5);
121   if (rexmt < RTT_RXTMIN)
122     rexmt = RTT_RXTMIN;
123   else if (rexmt > RTT_RXTMAX)
124     rexmt = RTT_RXTMAX;
125   return (r->rtt_currto = rexmt);
126 }
127 
rtt_stop(itemlink * r)128 void rtt_stop(itemlink *r)
129 {
130   long diff;
131   float err;
132 
133   snapshot;
134   if (r->rtt_nrexmt > 0)
135     r->rtt_nxtrto = r->rtt_currto;
136   else {
137     r->rtt_nxtrto = 0;
138     gettimeofday(&r->time_stop, NULL);
139     diff = r->time_stop.tv_sec - r->time_start.tv_sec;
140     if (r->time_stop.tv_usec < r->time_start.tv_usec)
141       diff--;
142     r->rtt_rtt = (float)diff;
143     /* Use integer version instead */
144     err = r->rtt_rtt - r->rtt_srtt;
145     r->rtt_srtt += err/8;
146     if (err < 0.0)
147       err = -err;
148     r->rtt_rttdev += (err - r->rtt_rttdev) / 4;
149   }
150 }
151 
rtt_timeout(itemlink * r)152 int rtt_timeout(itemlink *r)
153 {
154   snapshot;
155   rtt_stop(r);
156   return (++r->rtt_nrexmt >= RTT_MAXNREXMT);
157 }
158 
159 /*
160  * msgid, type, msg, \n
161  */
162 
163 #if 0
164 int L1_recv(struct Socket *self, char *buf, int len, int flags)
165 {
166   int size = sizeof(self->fromaddr);
167 
168   snapshot;
169   size = recvfrom(self->handle, buf, len, flags,
170 		  (struct sockaddr *)&(self->fromaddr), &size);
171   buf[size] = NIL;
172 #ifdef DBUG
173   fprintf(stderr, "L1_recv: %d (%d) << %s",
174 	  self->handle, ntohs(self->fromaddr.sin_port), buf);
175 #endif
176   return size;
177 }
178 
179 int L1_send(itemlink *self, char *msg, int len, int flags)
180 {
181   snapshot;
182   sendto(self->handle, msg, len, flags,
183 	 (struct sockaddr *)&self->addr, sizeof(struct sockaddr_in));
184 #ifdef DBUG
185   fprintf(stderr, "%d (%d) >> %s",
186           self->handle, ntohs(self->addr.sin_port), rawmsg);
187 #endif
188 }
189 #endif
190 
191 /* --- ReadLink --------------------------------------------------- */
192 
ReadLink(char * inbuf)193 int ReadLink(char *inbuf)
194 {
195   int size = sizeof(fromaddr);
196 
197   snapshot;
198   size = recvfrom(linkSocket, inbuf, MAXLINE, 0,
199                   (struct sockaddr *)&fromaddr, &size);
200   inbuf[size] = NIL;
201 #ifdef DBUG
202   fprintf(stderr, "%d (%d) << %s", linkSocket, ntohs(fromaddr.sin_port), inbuf);
203 #endif
204   return size;
205 }
206 
207 /* --- WriteLink -------------------------------------------------- */
208 
209 #define UDPBUFFER 1024
210 
WriteLinkRaw(itemlink * r,char * rawmsg)211 void WriteLinkRaw(itemlink *r, char *rawmsg)
212 {
213   snapshot;
214 
215 #ifdef DBUG
216   fprintf(stderr, "%d (%d) >> %s",
217           linkSocket, ntohs(r->addr.sin_port), rawmsg);
218 #endif
219 
220   sendto(linkSocket, rawmsg, StrLength(rawmsg), 0,
221 	 (struct sockaddr *)&r->addr, sizeof(struct sockaddr_in));
222 }
223 
WriteLink(itemlink * r,int type,char * msg)224 void WriteLink(itemlink *r, int type, char *msg)
225 {
226   unsigned char buffer[UDPBUFFER];
227 
228   snapshot;
229   StrFormatMax(buffer, sizeof(buffer), "%d %d %s\n", ++r->mymsgid, type, msg);
230   WriteLinkRaw(r, buffer);
231 }
232 
WriteLinkf(itemlink * r,int type,char * format,...)233 void WriteLinkf(itemlink *r, int type, char *format, ...)
234 {
235   char buffer[MAXLINE];
236   va_list args;
237 
238   snapshot;
239   va_start(args, format);
240   trio_vsnprintf(buffer, sizeof(buffer), format, args);
241   va_end(args);
242 
243   WriteLink(r, type, buffer);
244 }
245 
246 /* --- SendLink --------------------------------------------------- */
247 /* If queue is empty send directly, else queue it. Don't remove
248  * from queue until ACK is received. The message on top of the
249  * list is always the one being sent, the rest are stalled to
250  * ensure casuality.
251  */
252 
QueueLink(itemlink * r,int type,char * msg)253 void QueueLink(itemlink *r, int type, char *msg)
254 {
255   char buffer[BIGGERBUFFER];
256   itemmsg *m;
257 
258   snapshot;
259   StrFormatMax(buffer, sizeof(buffer), "%d %lu %s\n", ++r->mymsgid, type, msg);
260 
261   m = NewEntry(itemmsg);
262   if (m) {
263     m->msg = StrDuplicate(buffer);
264 
265     /* If first in queue ship it now */
266     if (EmptyList(&r->RemoteHead)) {
267       rtt_newpack(r);
268       WriteLinkRaw(r, buffer);
269 
270 #ifdef UNRELIABLE
271       if (Rnd() < 0.2) /* Send duplicate */
272         WriteLinkRaw(r, buffer);
273 #endif
274 
275       r->expires = now + rtt_start(r);
276     }
277 
278     InsertLast(&r->RemoteHead, m);
279   }
280 }
281 
SendLink(itemlink * r,int type,char * format,...)282 void SendLink(itemlink *r, int type, char *format, ...)
283 {
284   char buffer[BIGGERBUFFER];
285   va_list args;
286 
287   snapshot;
288 
289   va_start(args, format);
290   trio_vsnprintf(buffer, sizeof(buffer), format, args);
291   va_end(args);
292 
293   QueueLink(r, type, buffer);
294 }
295 
SendLinkAll(int type,char * format,...)296 void SendLinkAll(int type, char *format, ...)
297 {
298   char buffer[BIGGERBUFFER];
299   va_list args;
300   itemlink *r;
301 
302   snapshot;
303 
304   va_start(args, format);
305   trio_vsnprintf(buffer, sizeof(buffer), format, args);
306   va_end(args);
307 
308   for (r = First(linkHead); r; r = Next(r)) {
309     if (!r->new)
310       QueueLink(r, type, buffer);
311   }
312 }
313 
SendLinkBut(itemlink * rin,int type,char * format,...)314 void SendLinkBut(itemlink *rin, int type, char *format, ...)
315 {
316   char buffer[BIGGERBUFFER];
317   va_list args;
318   itemlink *r;
319 
320   snapshot;
321 
322   va_start(args, format);
323   trio_vsnprintf(buffer, sizeof(buffer), format, args);
324   va_end(args);
325 
326   for (r = First(linkHead); r; r = Next(r)) {
327     if (!r->new && (r != rin))
328       QueueLink(r, type, buffer);
329   }
330 }
331 
332 /* --- CheckLinkQueue --------------------------------------------- */
333 
334 /*
335  * Whenever a message is sent it must wait for acknowledgement.
336  * When messages are sent they are put in a queue. Each linked
337  * bot has its own queue. When an ack is received the next message
338  * from the queue is sent.
339  */
340 
CheckLinkQueue(void)341 void CheckLinkQueue(void)
342 {
343   itemlink *r;
344   itemmsg *m;
345 
346   snapshot;
347 
348   /* Called each second */
349   for (r = First(linkHead); r; r = Next(r)) {
350     m = First(&r->RemoteHead);
351     if (m) {
352       if (r->expires <= now) {
353         if (rtt_timeout(r)) {
354           /* Link is dead, remove it */
355           r = RemoveLink(r);
356           continue; /* for */
357         }
358         else {
359           /* Retransmit message */
360           WriteLinkRaw(r, m->msg);
361           r->expires = now + rtt_start(r);
362         }
363       }
364     }
365   }
366 }
367 
FlushLinkQueue(itemlink * r)368 void FlushLinkQueue(itemlink *r)
369 {
370   snapshot;
371   FlushList(&r->RemoteHead, FreeMessage);
372 }
373 
374 /* --- LinkDequeue ------------------------------------------------ */
375 
LinkDequeue(itemlink * r,unsigned long msgid)376 bool LinkDequeue(itemlink *r, unsigned long msgid)
377 {
378   unsigned long mid;
379   int type;
380   itemmsg *m;
381 
382   snapshot;
383 
384   /* Remove from top of queue */
385   if ((m = First(&r->RemoteHead)) &&
386       (2 == StrScan(m->msg, "%d %lu", &mid, &type))) {
387 
388     /* Duplicates of previously acknowledged message may exist */
389     if (mid == msgid) {
390       /* Wait to remove the rejected link until it acknowledges */
391       if (IBCP_REJECT == type) {
392         RemoveLink(r);
393         return TRUE;
394       }
395       else {
396         DeleteEntry(&r->RemoteHead, m, FreeMessage);
397 
398         m = First(&r->RemoteHead);
399         if (m) {
400           /* Ship the next */
401           rtt_newpack(r);
402           WriteLinkRaw(r, m->msg);
403           r->expires = now + rtt_start(r);
404         }
405       }
406     }
407   }
408   return FALSE;
409 }
410 
411 
412 /* ----------------------------------------------------------------
413  *
414  *  Level 2 routines
415  *
416  * ---------------------------------------------------------------- */
417 
418 /* --- LinkQuit --------------------------------------------------- */
419 
420 /*
421  * The QUIT message surpasses the queue. We don't care about
422  * acknowledgement - if the recipient received it fine; if not
423  * the connection will timeout eventually.
424  */
425 
LinkQuit(void)426 void LinkQuit(void)
427 {
428   itemlink *r;
429 
430   snapshot;
431 
432   /* Equivalent to SendLinkAll(IBCP_QUIT, "Bored"); */
433   for (r = First(linkHead); r; r = Next(r))
434     WriteLink(r, IBCP_QUIT, "Bored");
435 }
436 
437 /* --- LinkHello -------------------------------------------------- */
438 
LinkHello(char * msg)439 itemlink *LinkHello(char *msg)
440 {
441   int ver, bottype;
442   ulong key;
443   itemlink *r = NULL;
444   char name[MINIBUFFER];
445 
446   snapshot;
447   if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key))
448     {
449       /*
450        * We initiated the link. Now that we've got the info
451        * of the other end we add it and reply with our info.
452        */
453       r = AddLink(name, NULL, ntohl(fromaddr.sin_addr.s_addr),
454 		  ntohs(fromaddr.sin_port));
455       if (r)
456 	{
457 	  r->bottype = bottype;
458 	  r->protoversion = ver;
459 	  /* We asked to link so we assume that the other end is authenticated */
460 	  r->passed = TRUE;
461 	  SendLink(r, IBCP_HELLO_REPLY, "%d %d %s %lu",
462 		   IBCP_VERSION, IBCP_BOT_DANCER, nickname, key ^ linkvalue);
463 	}
464     }
465   return r;
466 }
467 
468 
469 /* --- LinkHelloReply --------------------------------------------- */
470 
LinkHelloReply(itemlink * r,char * msg)471 void LinkHelloReply(itemlink *r, char *msg)
472 {
473   int ver, bottype;
474   ulong key;
475   char name[MINIBUFFER];
476 
477   snapshot;
478   if (4 == StrScan(msg, "%d %d %s %lu", &ver, &bottype, name, &key)) {
479     if (r)
480       {
481 	/*
482 	 * The other end initiated the link. We have already
483 	 * sent our info (in the HELLO message in ctcp.c) and
484 	 * now get the info of the initiater in return
485 	 */
486 	r->bottype = bottype;
487 	r->protoversion = ver;
488 	if (name)
489 	  r->name = StrDuplicate(name);
490 
491 	if ((r->linkvalue ^ key) == r->tmpvalue)
492 	  {
493 	    r->passed = TRUE;
494 #if 0
495 	    SendLinkBut(r, IBCP_AUTH, "%ld %d %d %d %s",
496 			ntohl(fromaddr.sin_addr.s_addr), ntohs(fromaddr.sin_port),
497 			ver, bottype, name);
498 	    r->new = FALSE;
499 #endif
500 	    SendLink(r, IBCP_ACCEPT, "");
501 
502 #if 0
503 	    /* Tell newcomer about everybody else in net */
504 	    for (rr = First(linkHead); rr; rr = Next(rr))
505 	      {
506 		if (rr != r)
507 		  SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
508 			   ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
509 			   rr->protoversion, rr->bottype, rr->name);
510 	      }
511 	    SendLink(r, IBCP_AUTH_END, "1");
512 	    /* Logf(LINK, "Added %s from %s %d", r->name,
513 	       ntohl(r->addr.sin_addr.s_addr), ntons(r->addr.sin_port));
514 	       */
515 #endif
516 	  }
517 	else
518 	  {
519 	    r->passed = FALSE;
520 	    SendLink(r, IBCP_REJECT, "No authentication");
521 	    /* Link will be removed in LinkDequeue() */
522 	    /* Logf(LINK, "Rejected..."); */
523 	    return;
524 	  }
525       }
526   }
527 }
528 
529 
530 /* --- LinkAuth --------------------------------------------------- */
531 
LinkAuth(itemlink * r,char * msg)532 void LinkAuth(itemlink *r, char *msg)
533 {
534   itemlink *rr;
535   long addr;
536   int port, ver, bottype;
537   char name[MINIBUFFER];
538 
539   snapshot;
540   if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
541     {
542       rr = AddLink(name, NULL, addr, port);
543       if (rr)
544 	{
545 	  rr->bottype = bottype;
546 	  rr->protoversion = ver;
547 	  rr->passed = TRUE;
548 	  rr->new = FALSE;  /* Add immediately */
549 	}
550     }
551 }
552 
LinkAuthList(itemlink * r,char * msg)553 void LinkAuthList(itemlink *r, char *msg)
554 {
555   itemlink *rr;
556   long addr;
557   int port, ver, bottype;
558   char name[MINIBUFFER];
559 /*   char naddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:256.256.256.256"]; */
560 
561   snapshot;
562   if (5 == StrScan(msg, "%ld %d %d %d %s", &addr, &port, &ver, &bottype, name))
563     {
564       rr = AddLink(name, NULL, addr, port);
565       if (rr)
566 	{
567 	  rr->bottype = bottype;
568 	  rr->protoversion = ver;
569 	  rr->passed = TRUE;
570 	  rr->new = TRUE;
571 	}
572     }
573 }
574 
LinkAuthEnd(itemlink * r,char * msg)575 void LinkAuthEnd(itemlink *r, char *msg)
576 {
577   itemlink *rr, *xrr;
578 
579   snapshot;
580   if (*msg ^ '0') {
581     /* Return our cluster */
582     for (rr = First(linkHead); rr; rr = Next(rr)) {
583       if ( !rr->new && (rr != r) )
584 	SendLink(r, IBCP_AUTH_LIST, "%ld %d %d %d %s",
585 		 ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
586 		 rr->protoversion, rr->bottype, rr->name);
587     }
588     SendLink(r, IBCP_AUTH_END, "0");
589   }
590 
591   /* Commit newly received links */
592   for (rr = First(linkHead); rr; rr = Next(rr)) {
593     if (rr->new) {
594       for (xrr = rr; xrr; xrr = Next(xrr)) {
595 	if ( !xrr->new )
596 	  SendLink(xrr, IBCP_AUTH, "%ld %d %d %d %s",
597 		   ntohl(rr->addr.sin_addr.s_addr), ntohs(rr->addr.sin_port),
598 		   rr->protoversion, rr->bottype, rr->name);
599       }
600       rr->new = FALSE;
601     }
602   }
603 }
604 
605 /* --- LinkAccept ------------------------------------------------- */
606 
LinkAccept(itemlink * r)607 void LinkAccept(itemlink *r)
608 {
609   snapshot;
610   SendLink(r, IBCP_SYNC, "%ld %ld", TIMEREQUEST, now);
611 }
612 
613 /* --- LinkSync --------------------------------------------------- */
614 
LinkSync(itemlink * r,char * msg)615 void LinkSync(itemlink *r, char *msg)
616 {
617   long ct, then;
618 
619   snapshot;
620   if (2 == StrScan(msg, "%ld %ld", &ct, &then)) {
621     if (ct == TIMEREQUEST) {
622       /* It is a request for common time */
623       SendLink(r, IBCP_SYNC, "%ld %ld", now - commontime, then);
624     }
625     else {
626       /* T_common_ref = T_now - (T_remote + T_round-trip/2) */
627       long cnow = now;
628       commontime = cnow - ct - (cnow - then) / 2;
629       SendLink(r, IBCP_USERS_REQUEST, "%lu", LatestUserUpdate());
630     }
631   }
632 }
633 
634 /* --- LinkNickname ----------------------------------------------- */
635 
LinkNickname(itemlink * r,char * msg)636 void LinkNickname(itemlink *r, char *msg)
637 {
638   snapshot;
639   if (r->name)
640     StrFree(r->name);
641   r->name = StrDuplicate(msg);
642 }
643 
644 /* --- LinkMulticast ---------------------------------------------- */
645 
LinkMulticast(itemlink * r,char * msg)646 void LinkMulticast(itemlink *r, char *msg)
647 {
648   char *text;
649 
650   snapshot;
651   text = StrIndex(msg, ' ');
652   if (text) {
653     /*
654      * Multicasting from remote link is only forwarded
655      * to local listening clients
656      */
657     MulticastLocalf(atoi(msg), "[%s]%s", r->name, text);
658   }
659 }
660 
661 /* --- LinkSendUsers ---------------------------------------------- */
662 
663 #if 0
664 char *LevelType(int level)
665 {
666   snapshot;
667   if (level < LEVELRECOG)
668     return "UNKNOWN";
669   else if (level < LEVELCHANOP)
670     return "RECOGNIZED";
671   else if (level < LEVELTRUST)
672     return "CHANOP";
673   else if (level < LEVELEXPERT)
674     return "TRUSTED";
675   else if (level < LEVELBOT)
676     return "EXPERT";
677   else if (level < LEVELOWNER)
678     return "MAINTAINER";
679   else
680     return "OWNER";
681 }
682 
683 void LinkSendUser(itemlink *r, itemuser *u)
684 {
685   char buffer[BIGGERBUFFER];
686   itemlist *t;
687 
688   snapshot;
689   StrFormatMax(buffer, sizeof(buffer), "%s", LevelType(u->level));
690   if (u->flags.autoop)
691     StrAppendMax(buffer, sizeof(buffer), ",AUTO");
692   if (u->flags.banprotect)
693     StrAppendMax(buffer, sizeof(buffer), ",PROTECT");
694   /* u->flags.linkbot is local data and not shared */
695 
696   SendLink(r, IBCP_DATA_USER, "BEGIN: NICK:%s PASS:%s PRIV:%s CTIME:%ld MTIME:%ld",
697            u->nick, u->passwd, buffer, u->created - commontime, u->modified - commontime);
698   SendLink(r, IBCP_DATA_USER, "EMAIL:\"%s\" COMMENT:\"%s\"",
699            u->realname, u->comment);
700 
701   buffer[0] = (char)0;
702   for (t = First(u->domainhead); t; t = Next(t))
703 /* What is this? */
704     StrFormatMax(buffer, sizeof(buffer), "%s%s,",
705                  (NULL == StrIndex((char *)t->pointer, '!')) ? "*!" : "",
706                  (char *)t->pointer);
707   SendLink(r, IBCP_DATA_USER, "HOST:%s END:", buffer);
708 }
709 
710 void LinkSendUserlist(itemlink *r)
711 {
712   itemuser *u;
713 
714   snapshot;
715   for (u = First(userHead); u; u = Next(u))
716     LinkSendUser(r, u);
717 }
718 
719 /* --- LinkUpdateUser --------------------------------------------- */
720 
721 void LinkUpdateUser(itemlink *r, char *msg)
722 {
723   static itemuser user;
724   char buffer[BIGGERBUFFER];
725   char strtype[MINIBUFFER];
726   char strargs[BIGBUFFER];
727   int index = 0;
728 
729   snapshot;
730 #ifdef HAVE_N_IN_SCANF
731   StrScan(&msg[index], "%s %n", buffer, &index);
732 #else
733   StrScan(&msg[index], "%s", buffer);
734   index = StrLength(buffer);
735 #endif
736 
737   StrScan(buffer, "[^:]*1[:][^\n]", strtype, strargs);
738 
739   if (StrEqual(strtype, "BEGIN"))
740     memset(&user, NIL, sizeof(user));
741   else if (StrEqual(strtype, "NICK"))
742     user.nick = StrDuplicate(strargs);
743   else if (StrEqual(strtype, "PASS"))
744     user.passwd = StrDuplicate(strargs);
745 /* Remember that time is relative to commontime */
746   else if (StrEqual(strtype, "END")) {
747     /* Insert user entry */
748 #if 0
749     AddUser(&user, buffer);  /* <--- Must be UpdateUser() not AddUser() */
750     StrFormatMax(buffer, sizeof(buffer), "%s 0 %d %d 0", user.passwd, NULL,
751                  user.modified, user.created);
752     AddNewData(&user, buffer);
753     AddDomain(&user, whatever);
754 #endif
755     if (user.nick)
756       StrFree(user.nick);
757     if (user.passwd)
758       StrFree(user.passwd);
759   }
760 }
761 #endif
762 
763 /* --- LinkUsers -------------------------------------------------- */
764 
765 char *SetUserFlags(uFlags *);
766 
LinkUsersRequest(itemlink * r,char * msg)767 void LinkUsersRequest(itemlink *r, char *msg)
768 {
769   char buffer[3*BIGBUFFER];
770   itemuser *u;
771   itemlist *l;
772   time_t t;
773 
774   snapshot;
775   if (1 == StrScan(msg, "%lu", &t) ) {
776     printf("update since %lu\n", t);
777 
778     /* Ship all entries that are newer than 't' */
779     for (u = First(userHead); u; u = Next(u)) {
780       if (u->modified > t - 400) {  /* !!! remove - 400 !!! */
781 
782         /* Should send the same data as UserSave() */
783         SendLink(r, IBCP_USERS_LIST, "%s", WriteUserHead(buffer, sizeof(buffer), u));
784 	for (l = First(u->domainhead); l; l = Next(l))
785 	  SendLink(r, IBCP_USERS_LIST, "!%s\n", (char *)l->pointer);
786       }
787     }
788     SendLink(r, IBCP_USERS_END, "");
789   }
790 }
791 
LinkUsersUpdate(itemlink * r,char * msg)792 void LinkUsersUpdate(itemlink *r, char *msg)
793 {
794   snapshot;
795   printf("Should do the update here\n");
796 }
797 
LinkUsersList(itemlink * r,char * msg)798 void LinkUsersList(itemlink *r, char *msg)
799 {
800   snapshot;
801   LinkUsersUpdate(r, msg);
802   /* Forward to rest of local cluster */
803   SendLinkBut(r, IBCP_USERS_UPDATE, msg);
804 }
805 
LinkUsersEnd(itemlink * r,char * msg)806 void LinkUsersEnd(itemlink *r, char *msg)
807 {
808   snapshot;
809 /*  SendLink(r, IBCP_AUTH_REQUEST, "");*/
810   printf("initiate AUTH... when installed\n");
811 }
812 
813 
814 /* --- LinkRemote ------------------------------------------------- */
815 
LinkRemoteCmd(itemlink * r,char * msg)816 void LinkRemoteCmd(itemlink *r, char *msg)
817 {
818   char name[MINIBUFFER];
819   char cmd[MIDBUFFER];
820   char buffer[BIGBUFFER] = "";
821 
822   snapshot;
823   if (2 <= StrScan(msg, "%s %s %[^\n]", name, cmd, buffer)) {
824     printf("remote '%s %s' from %s", cmd, buffer[0] ? buffer : "", name);
825   }
826 }
827 
LinkRemoteAnswer(itemlink * r,char * msg)828 void LinkRemoteAnswer(itemlink *r, char *msg)
829 {
830   extern bool chat;
831   extern itemclient *client;
832   char name[MINIBUFFER];
833   char buffer[BIGBUFFER];
834   bool chit;
835   itemclient *klient;
836 
837   snapshot;
838   if (2 == StrScan(msg, "%"MINIBUFFERTXT"s %"BIGBUFFERTXT"[^\n]", name, buffer)) {
839     printf("remote answer '%s' to %s", buffer, name);
840     chit = chat;
841     klient = client;
842     chat = (client = FindClientByNick(name)) ? TRUE : FALSE;
843     Send(name, buffer);
844     chat = chit;
845     client = klient;
846   }
847 }
848 
849 /* --- LinkParse -------------------------------------------------- */
850 
851 #define IDBACKTRACK 1000u
852 
IsDuplicate(unsigned long this,unsigned long last)853 bool IsDuplicate(unsigned long this, unsigned long last)
854 {
855   snapshot;
856 
857   /* This strange looking code works because we are dealing
858    * with unsigned arithmetic. Hopefully the compiler doesn't
859    * choose to optimize it away.
860    */
861   if (this <= last)
862     return (this - IDBACKTRACK <= last - IDBACKTRACK);
863   return FALSE;
864 }
865 
LinkParse(char * line)866 void LinkParse(char *line)
867 {
868   itemlink *r;
869   char buffer[BIGBUFFER];
870   char out[BIGBUFFER];
871   char *msg;
872   int type, rc;
873   unsigned long msgid;
874 
875   snapshot;
876 #if 1
877 
878   if (2 <= StrScan(line, "%d %d %[^\n]", &msgid, &type, buffer)) {
879     msg = buffer;
880     r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
881     if (NULL == r) {
882       if (type == IBCP_HELLO) {
883         /* We will only accept a HELLO from unknown destinations. */
884         /* And only if it contains data */
885         if (StrLength(msg) > 0) {
886           r = LinkHello(msg);
887           if (r) {
888             /* Acknowledge directly */
889             StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
890             WriteLinkRaw(r, out);
891             r->yourmsgid = msgid;
892           }
893         }
894       }
895 
896       if (NULL == r)
897         return;
898     }
899 
900     /* r is always set at this point */
901 
902     if (IBCP_ACK == type) {
903       /* We got an acknowledgement. Dequeue message and send next */
904       LinkDequeue(r, msgid);
905       /* Don't acknowledge acknowledgements... bad karma */
906       return;
907     }
908 
909     if (IsDuplicate(msgid, r->yourmsgid))
910       /* Ignore duplicates */
911       return;
912 
913     rtt_stop(r);
914 
915     if (StrLength(msg) > 0) {
916       /* If zero it's only an ack */
917 
918 #if 1
919 #ifdef UNRELIABLE
920       if (Rnd() > 0.2) /* Don't acknowledge */
921 #endif
922 	    StrFormatMax(out, sizeof(out), "%d %d\n", msgid, IBCP_ACK);
923 	  WriteLinkRaw(r, out); /* &fromaddr */
924 	  /* bool wantpiggy; ulong piggymsg; */
925 #endif
926 
927 	  /*
928 	   * Check if from authenticated bot. There are two ways to become
929 	   * authenticated: either by authentication at connect-time, or
930 	   * through validation by another bot.
931 	   */
932 
933 	  if (r->passed)
934 	    {
935 	      switch (type)
936 		{
937 		case IBCP_QUIT:  /* Link that decided to quit */
938 		  RemoveLink(r);
939 		  r = NULL;
940 		  break;
941 		case IBCP_ACCEPT:
942 		  LinkAccept(r);
943 		  break;
944 		case IBCP_REJECT:  /* I was rejected by r */
945 		  RemoveLink(r);
946 		  r = NULL;
947 		  break;
948 		case IBCP_SYNC:  /* Establish or request common time */
949 		  LinkSync(r, msg);
950 		  break;
951 		case IBCP_AUTH:
952 		  LinkAuth(r, msg);
953 		  break;
954 		case IBCP_AUTH_LIST:
955 		  /* Not broadcasted until AUTH_END is received */
956 		  LinkAuthList(r, msg);
957 		  break;
958 		case IBCP_AUTH_END:
959 		  LinkAuthEnd(r, msg);
960 		  break;
961 
962 		  /* Handle userlist */
963 		case IBCP_USERS_REQUEST:
964 		  LinkUsersRequest(r, msg);
965 		  break;
966 		case IBCP_USERS_UPDATE:
967 		  LinkUsersUpdate(r, msg);
968 		  break;
969 		case IBCP_USERS_LIST:
970 		  LinkUsersList(r, msg);
971 		  break;
972 		case IBCP_USERS_END:
973 		  LinkUsersEnd(r, msg);
974 		  break;
975 
976 		case IBCP_REMOTE_CMD:
977 		  LinkRemoteCmd(r, msg);
978 		  break;
979 		case IBCP_REMOTE_ANSWER:
980 		  LinkRemoteAnswer(r, msg);
981 		  break;
982 
983 		case IBCP_NICKNAME:
984 		  LinkNickname(r, msg);
985 		  break;
986 
987 		case IBCP_MULTICAST:
988 		  LinkMulticast(r, msg);
989 		  break;
990 
991 		default:
992 		  break;
993 		}
994 	    }
995 	  else if (type == IBCP_HELLO_REPLY)
996 	    {
997 	      /*
998 	       * HELLO_REPLY is part of the authentication scheme and
999 	       * therefor we will only accept it if the link isn't
1000 	       * authenticated yet.
1001 	       */
1002 	      LinkHelloReply(r, msg);
1003 	    }
1004 	  r->yourmsgid = msgid;
1005 	}
1006       r->lasttime = now;
1007     }
1008 
1009 #else
1010 
1011   unsigned long msgid;
1012   int type;
1013 
1014   /* Skip escape code if present */
1015   if (*line == IBCP_ESC) line++;
1016 
1017   msg = buffer;
1018   if ( 2 <= StrScan(line, "%d %lu %[^\n]", &type, &msgid, msg) ) {
1019 
1020     r = FindLink(fromaddr.sin_addr.s_addr, fromaddr.sin_port);
1021 
1022     if (type == IBCP_ACK) {
1023       /* We got an acknowledgement. Dequeue message and send next */
1024       if (r)
1025         LinkDequeue(r, msgid);
1026       /* Don't acknowledge acknowledgements... bad karma */
1027       return;
1028     }
1029 
1030     /* Ignore duplicates */
1031     if (r && IsDuplicate(msgid, r->yourmsgid)) {
1032       printf("Ignored\n");
1033       return;
1034     }
1035 
1036 #ifdef UNRELIABLE
1037     if (Rnd() > 0.2) /* Don't acknowledge */
1038 #endif
1039       WriteLink(&fromaddr, IBCP_ACK, "");
1040 
1041     if (type == IBCP_HELLO) {
1042       LinkHello(r, msg);
1043       return;
1044     } else if (type == IBCP_HELLO_REPLY) {
1045       LinkHelloReply(r, msg);
1046       return;
1047     }
1048 
1049     if (r) {
1050 
1051       rtt_stop(r);
1052 
1053       /*
1054        * Check if from authenticated bot. There are two ways to become
1055        * authenticated: either by authentication at connect-time, or
1056        * through validation by another bot
1057        */
1058 
1059       /*if (r->passed)*/ {
1060         switch (type) {
1061 
1062         case IBCP_QUIT:  /* Link that decided to quit */
1063           RemoveLink(r);
1064           break;
1065 
1066         case IBCP_ACCEPT:
1067           LinkAccept(r);
1068           break;
1069         case IBCP_REJECT:  /* I was rejected by r */
1070           RemoveLink(r);
1071           break;
1072 
1073         case IBCP_AUTH:
1074           LinkAuth(r, msg);
1075           break;
1076         case IBCP_AUTH_LIST:
1077 	  /* Not passed until AUTH_END is received */
1078           LinkAuthList(r, msg);
1079           break;
1080 	case IBCP_AUTH_END:
1081 	  LinkAuthEnd(r, msg);
1082 	  break;
1083 
1084         case IBCP_SYNC:  /* Establish or request common time */
1085           LinkSync(r, msg);
1086           break;
1087 
1088 	  /* Handle userlist */
1089         case IBCP_USERS_REQUEST:
1090           LinkUsersRequest(r, msg);
1091           break;
1092         case IBCP_USERS_UPDATE:
1093           LinkUsersUpdate(r, msg);
1094           break;
1095         case IBCP_USERS_LIST:
1096           LinkUsersList(r, msg);
1097           break;
1098         case IBCP_USERS_END:
1099           LinkUsersEnd(r, msg);
1100           break;
1101 
1102         case IBCP_REMOTE_CMD:
1103           LinkRemoteCmd(r, msg);
1104           break;
1105         case IBCP_REMOTE_ANSWER:
1106           LinkRemoteAnswer(r, msg);
1107           break;
1108 
1109         case IBCP_NICKNAME:
1110           LinkNickname(r, msg);
1111           break;
1112 
1113         case IBCP_MULTICAST:
1114           LinkMulticast(r, msg);
1115           break;
1116 
1117         default:
1118           break;
1119         }
1120       }
1121       r->yourmsgid = msgid;
1122       r->lasttime = now;
1123     }
1124   }
1125 
1126 #endif
1127 }
1128