1 #ifdef RCS
2 static char rcsid[]="$Id: servfunc.c,v 1.1.1.1 2000/11/13 02:42:48 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/servfunc.c,v $
17  * $Revision: 1.1.1.1 $
18  * $Date: 2000/11/13 02:42:48 $
19  * $Author: holsta $
20  * $State: Exp $
21  * $Locker:  $
22  *
23  * ---------------------------------------------------------------------------
24  *****************************************************************************/
25 
26 #include "dancer.h"
27 #include "trio.h"
28 #include "strio.h"
29 #include "list.h"
30 #include "function.h"
31 #include "servfunc.h"
32 #include "fplrun.h"
33 
34 /* --- Global ----------------------------------------------------- */
35 
36 extern time_t now;
37 
38 extern char servername[];
39 extern char servfile[];
40 extern char *errfrom;
41 extern itemserv *currentserv;
42 
43 itemserv *servHead;
44 static int servid = 1;
45 
46 
47 /* --- FindServ --------------------------------------------------- */
48 
FindServ(char * name,long port)49 itemserv *FindServ(char *name, long port)
50 {
51   int id;
52   itemserv *s;
53 
54   snapshot;
55   id = atoi(name);
56   for (s = First(servHead); s; s = Next(s)) {
57     if ((id && (id == s->s.id)) ||
58         (StrEqual(name, s->s.name) && (port == s->s.port))) {
59       return s;
60     }
61   }
62   return NULL;
63 }
64 
65 /* --- NextServ --------------------------------------------------- */
66 
NextServ(void)67 itemserv *NextServ(void)
68 {
69   itemserv *afterthis;
70   itemserv *s;
71 
72   snapshot;
73   afterthis = currentserv;
74   for (s = First(servHead); s; s = Next(s)) {
75     if (s->s.flags & SERV_DISABLED)
76       continue;
77     if (NULL == afterthis)
78       return s;
79     else if (s == afterthis)
80       afterthis = NULL; /* get the next */
81   }
82   return First(servHead); /* if nothing matched, return the first */
83 }
84 
AddServ(struct ServerSub * sub)85 int AddServ(struct ServerSub *sub)
86 {
87   int retcode = TRUE;
88   itemserv *s;
89 
90   snapshot;
91   s = FindServ(sub->name, sub->port);
92   if (NULL == s) {
93     s = NewEntry(itemserv);
94     if (s) {
95       InsertLast(servHead, s);
96       s->s    = *sub;
97       s->s.id = servid++;
98       return FALSE;
99     }
100   }
101   else if (s->s.flags & SERV_DISABLED &&
102            !(sub->flags & SERV_DISABLED) &&
103            !(sub->flags & SERV_INCONFIG)) {
104     /*
105      * The existing one is marked disabled. The new one is not, and it is
106      * not from the .config file.
107      * .config file entries are not allowed to undo disabled ones.
108      */
109 
110     /*
111      * The added one already exists, so we should return successful
112      * but we should free the resources of this new struct since we
113      * are reusing an old one.
114      */
115     s->s.flags &= ~SERV_DISABLED;
116     retcode = FALSE;
117   }
118   else if (sub->flags & SERV_INCONFIG) {
119     s->s.flags |= SERV_INCONFIG; /* this exist in .config we know now */
120   }
121 
122   /* Free the resources */
123   if (sub->name)
124     StrFree(sub->name);
125   if (sub->passwd)
126     StrFree(sub->passwd);
127   if (sub->adder)
128     StrFree(sub->adder);
129   if (sub->message)
130     StrFree(sub->message);
131 
132   return retcode;
133 }
134 
ManAddServ(char * name,long port,char * passwd,char * who,long flags)135 int ManAddServ(char *name, long port, char *passwd, char *who, long flags)
136 {
137   struct ServerSub sub;
138 
139   snapshot;
140   memset(&sub, 0, sizeof(struct ServerSub));
141   sub.name    = StrDuplicate(name);
142   sub.port    = port ? port : IRCPORT;
143   sub.passwd  = passwd ? StrDuplicate(passwd) : NULL;
144   sub.adder   = who ? StrDuplicate(who) : NULL;
145   sub.addtime = now;
146   sub.flags   = flags;
147   return AddServ(&sub);
148 }
149 
ListServ(char * from,char * line)150 void ListServ(char *from, char *line)
151 {
152   char match[MIDBUFFER] = "*";
153   itemserv *s;
154 
155   snapshot;
156   StrScan(line, "%"MIDBUFFERTXT"s", match);
157   for (s = First(servHead); s; s = Next(s)) {
158     if (Match(s->s.name, match)) {
159       Sendf(from, "%d - %s %d%s%s", s->s.id, s->s.name, s->s.port,
160             s->s.passwd ? " <password>" : "",
161             (s->s.flags & SERV_DISABLED) ? " [DISABLED]" : "");
162     }
163   }
164 }
165 
166 /* --- SaveServ --------------------------------------------------- */
167 
SaveServ(void)168 int SaveServ(void)
169 {
170   char tempfile[BIGBUFFER];
171   bool ok = TRUE;
172   itemserv *s;
173   FILE *f;
174 
175   snapshot;
176   if (NIL == servfile[0])
177     return TRUE;
178 
179   StrFormatMax(tempfile, sizeof(tempfile), "%s~", servfile);
180 
181   f = fopen(tempfile, "w");
182   if (f) {
183     if (0 > fprintf(f, "# Dancer serverlist version: " VERSIONMSG "\n")) {
184       ok = FALSE;
185     }
186     else {
187       for (s = First(servHead); s; s = Next(s)) {
188         if (0 > fprintf(f, "%s:%d:%s\n" ":%s\n" "-%s\n" "!%d %d %d %d %d %d\n",
189                         s->s.name, s->s.port, s->s.passwd ? s->s.passwd : "",
190                         s->s.message ? s->s.message : "",
191                         s->s.adder ? s->s.adder : "",
192                         s->s.connect, s->s.disconnect, s->s.average,
193                         s->s.numconnects, s->s.flags, s->s.addtime)) {
194           ok = FALSE;
195           break;
196         }
197       }
198     }
199     fclose(f);
200 
201     if (ok)
202       rename(tempfile, servfile);
203   }
204   else
205     return TRUE;
206 
207   return FALSE;
208 }
209 
210 /* --- LoadServ --------------------------------------------------- */
211 
LoadServ(void)212 int LoadServ(void)
213 {
214   char buffer[MAXLINE];
215   char name1[BIGBUFFER];
216   char name2[BIGBUFFER];
217   int number[6];
218   struct ServerSub sub;
219   FILE *f;
220 
221   snapshot;
222   f = fopen(servfile, "r");
223   if (f) {
224     memset(&sub, 0, sizeof(struct ServerSub));
225     while (fgets(buffer, sizeof(buffer), f)) {
226       switch(buffer[0]) {
227 
228       case '#':
229       case '\n':
230         break;
231 
232       case ':':
233         if (1 == StrScan(buffer, ":%[^\n]", name1)) {
234           sub.message = StrDuplicate(name1);
235         }
236         break;
237 
238       case '-':
239         if (1 == StrScan(buffer, "-%[^\n]", name1)) {
240           sub.adder = StrDuplicate(name1);
241         }
242         break;
243 
244       case '!':
245         if (6 == StrScan(buffer, "!%d %d %d %d %d %d",
246                          &number[0], &number[1], &number[2],
247                          &number[3], &number[4], &number[5])) {
248           sub.connect     = number[0];
249           sub.disconnect  = number[1];
250           sub.average     = number[2];
251           sub.numconnects = number[3];
252           sub.flags       = number[4] & ~SERV_INCONFIG;
253           sub.addtime     = number[5];
254         }
255         AddServ(&sub);
256         memset(&sub, 0, sizeof(struct ServerSub));
257         break;
258 
259       default:
260         name2[0]  = (char)0;
261         number[0] = IRCPORT;
262         if (1 <= StrScan(buffer, "%[^:]:%d:%[^\n]",
263                          name1, &number[0], name2)) {
264           sub.name = StrDuplicate(name1);
265           sub.port = number[0];
266           if (name2[0])
267             sub.passwd = StrDuplicate(name2);
268         }
269         break;
270       }
271     }
272     fclose(f);
273   }
274   else
275     return TRUE;
276 
277   return FALSE;
278 }
279 
FreeServ(void * v)280 void FreeServ(void *v)
281 {
282   itemserv *s;
283 
284   snapshot;
285   s = (itemserv *)v;
286   if (s) {
287     if (s->s.name)
288       StrFree(s->s.name);
289     if (s->s.passwd)
290       StrFree(s->s.passwd);
291     if (s->s.message)
292       StrFree(s->s.message);
293     if (s->s.adder)
294       StrFree(s->s.adder);
295   }
296 }
297 
ServInit(void)298 void ServInit(void)
299 {
300   extern itemlist *serverHead;
301   char servername[BIGBUFFER], serverpasswd[BIGBUFFER];
302   int serverport;
303   itemlist *p;
304 
305   snapshot;
306   servHead = NewList(itemserv);
307   if (servHead) {
308     /* First, we get the servers from the .serv file */
309     LoadServ();
310 
311     /* Now, we convert the old-style serverlist */
312     for (p = First(serverHead); p; p = Next(p)) {
313       serverpasswd[0] = (char)0;
314       serverport = IRCPORT;
315       StrScan((char *)p->pointer, "%[a-zA-Z0-9.-]%*[ :]%d%*[ :]%[^\n]",
316               servername, &serverport, serverpasswd);
317       ManAddServ(servername, serverport, serverpasswd[0] ? serverpasswd : NULL,
318                  NULL, SERV_INCONFIG);
319     }
320   }
321 }
322 
ServCleanup(void)323 void ServCleanup(void)
324 {
325   snapshot;
326   SaveServ();
327   DeleteList(servHead, FreeServ);
328 }
329 
DelServ(char * name,long port)330 int DelServ(char *name, long port)
331 {
332   itemserv *s;
333 
334   snapshot;
335   s = FindServ(name, port);
336   if (s) {
337     if (s->s.flags & SERV_INCONFIG) {
338       /*
339        * This is entered in the .config file and therefore we cannot
340        * remove this for real, just mark it disabled
341        */
342       s->s.flags |= SERV_DISABLED;
343     }
344     else {
345       DeleteEntry(servHead, s, FreeServ); /* remove */
346     }
347     return FALSE;
348   }
349   return TRUE;
350 }
351 
ManDelServ(char * from,char * line)352 int ManDelServ(char *from, char *line)
353 {
354   char server[SEMIBUFFER];
355   long port = IRCPORT;
356 
357   snapshot;
358   if (StrScan(line, "%"SEMIBUFFERTXT"s %d", server, &port)) {
359     if (currentserv &&
360         StrEqual(server, currentserv->s.name) &&
361         (port == currentserv->s.port)) {
362       Send(errfrom, GetText(msg_cant_delete_current_server));
363       return TRUE;
364     }
365     if (DelServ(server, port)) {
366       Sendf(errfrom, GetText(msg_could_not_find_server), server, port);
367       return TRUE;
368     }
369     Sendf(from, GetText(msg_server_removed), server, port);
370     SaveServ();
371   }
372   else
373     return TRUE;
374 
375   return FALSE;
376 }
377 
StatServ(char * from,int options,char * server,long port)378 void StatServ(char *from, int options, char *server, long port)
379 {
380   itemserv *s;
381 
382   snapshot;
383   if (NIL == server[0]) {
384     s = currentserv;
385     if (NULL == s) {
386       Sendf(errfrom, GetText(msg_server_not_in_list), servername);
387       return;
388     }
389   }
390   else {
391     s = FindServ(server, port);
392     if (NULL == s) {
393       Sendf(errfrom, GetText(msg_could_not_find_server), server, port);
394       return;
395     }
396   }
397 
398   /*
399    * The switch makes duplicate flags get ignored, only one of them set
400    * will make a change
401    */
402   switch(options) {
403   case SERV_ENABLED:
404     s->s.flags &= ~SERV_DISABLED;
405     break;
406   case SERV_DISABLED:
407     s->s.flags |= SERV_DISABLED;
408     break;
409   }
410 
411   Sendf(from, "%s port %d %s", s->s.name, s->s.port,
412         s->s.passwd ? "<passwd>" : "");
413   Sendf(from, "%s last connect %s ago", (currentserv == s) ? "<current>" : "",
414         s->s.connect ? TimeAgo(s->s.connect) : "ages");
415   Sendf(from, "last disconnect %s ago, average connect time %s",
416         s->s.disconnect ? TimeAgo(s->s.disconnect) : "ages",
417         SecsToString(s->s.average));
418   Sendf(from, "number of connects: %d", s->s.numconnects);
419   Sendf(from, "State:%s",
420         (s->s.flags & SERV_DISABLED) ? " [DISABLED]" : " normal");
421 }
422 
ConnectServ(itemserv * serv)423 void ConnectServ(itemserv *serv)
424 {
425   snapshot;
426   currentserv = serv;
427   if (serv) {
428 #ifdef HAVE_LIBFPL
429     if (runfpl(RUN_CONNECT, serv->s.name, FPLRUN_PRE))
430       return;
431 #endif
432     serv->s.connect = now;
433     serv->s.numconnects++;
434     SaveServ();
435     runfpl(RUN_CONNECT, serv->s.name, FPLRUN_POST);
436   }
437 }
438 
DisconnectServ(char * fmt,...)439 void DisconnectServ(char *fmt, ...)
440 {
441   char buf[BIGBUFFER];
442   va_list args;
443 
444   snapshot;
445   va_start(args, fmt);
446   trio_vsnprintf(buf, sizeof(buf), fmt, args);
447   va_end(args);
448 
449 #ifdef HAVE_LIBFPL
450   if (runfpl(RUN_DISCONNECT, buf, FPLRUN_PRE))
451     return;
452 #endif
453 
454   if (currentserv) {
455     if (currentserv->s.message)
456       StrFree(currentserv->s.message);
457     currentserv->s.message = StrDuplicate(buf);
458     currentserv->s.disconnect = now;
459 
460     /* calculate the new average connect time */
461     currentserv->s.average = ((currentserv->s.average *
462                               (currentserv->s.numconnects - 1)) +
463                               (currentserv->s.disconnect -
464                                currentserv->s.connect)) /
465                                currentserv->s.numconnects;
466   }
467 
468   runfpl(RUN_DISCONNECT, buf, FPLRUN_POST);
469 }
470