1 /*
2  * userent.c -- handles:
3  *   user-entry handling, new stylem more versatile.
4  *
5  * $Id: userent.c,v 1.31 (0.9) 2004/01/11 15:36:40 [Xp-AvR] Exp $
6  */
7 
8 #include "main.h"
9 #include "users.h"
10 
11 extern int noshare;
12 extern struct userrec *userlist;
13 extern struct dcc_t *dcc;
14 extern Tcl_Interp *interp;
15 extern char whois_fields[];
16 
17 
18 int share_greet = 0;            /* Share greeting info                  */
19 static struct user_entry_type *entry_type_list;
20 
21 
init_userent()22 void init_userent()
23 {
24   entry_type_list = 0;
25   add_entry_type(&USERENTRY_COMMENT);
26   add_entry_type(&USERENTRY_XTRA);
27   add_entry_type(&USERENTRY_INFO);
28   add_entry_type(&USERENTRY_LASTON);
29   add_entry_type(&USERENTRY_BOTADDR);
30   add_entry_type(&USERENTRY_PASS);
31   add_entry_type(&USERENTRY_HOSTS);
32   add_entry_type(&USERENTRY_BOTFL);
33 }
34 
list_type_kill(struct list_type * t)35 void list_type_kill(struct list_type *t)
36 {
37   struct list_type *u;
38 
39   while (t) {
40     u = t->next;
41     if (t->extra)
42       nfree(t->extra);
43     nfree(t);
44     t = u;
45   }
46 }
47 
list_type_expmem(struct list_type * t)48 int list_type_expmem(struct list_type *t)
49 {
50   int tot = 0;
51 
52   for (; t; t = t->next)
53     tot += sizeof(struct list_type) + strlen(t->extra) + 1;
54 
55   return tot;
56 }
57 
def_unpack(struct userrec * u,struct user_entry * e)58 int def_unpack(struct userrec *u, struct user_entry *e)
59 {
60   char *tmp;
61 
62   tmp = e->u.list->extra;
63   e->u.list->extra = NULL;
64   list_type_kill(e->u.list);
65   e->u.string = tmp;
66   return 1;
67 }
68 
def_pack(struct userrec * u,struct user_entry * e)69 int def_pack(struct userrec *u, struct user_entry *e)
70 {
71   char *tmp;
72 
73   tmp = e->u.string;
74   e->u.list = user_malloc(sizeof(struct list_type));
75   e->u.list->next = NULL;
76   e->u.list->extra = tmp;
77   return 1;
78 }
79 
def_kill(struct user_entry * e)80 int def_kill(struct user_entry *e)
81 {
82   nfree(e->u.string);
83   nfree(e);
84   return 1;
85 }
86 
def_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)87 int def_write_userfile(FILE *f, struct userrec *u, struct user_entry *e, char *key)
88 {
89   if (efprintf(f, key, "--%s %s\n", e->type->name, e->u.string) == EOF)
90     return 0;
91   return 1;
92 }
93 
def_get(struct userrec * u,struct user_entry * e)94 void *def_get(struct userrec *u, struct user_entry *e)
95 {
96   return e->u.string;
97 }
98 
def_set(struct userrec * u,struct user_entry * e,void * buf)99 int def_set(struct userrec *u, struct user_entry *e, void *buf)
100 {
101   char *string = (char *) buf;
102 
103   if (string && !string[0])
104     string = NULL;
105   if (!string && !e->u.string)
106     return 1;
107   if (string) {
108     int l = strlen(string);
109     char *i;
110 
111     if (l > 160)
112       l = 160;
113 
114 
115     e->u.string = user_realloc(e->u.string, l + 1);
116 
117     strncpyz(e->u.string, string, l + 1);
118 
119     for (i = e->u.string; *i; i++)
120       if ((unsigned int) *i < 32 && !strchr("\002\003\026\037", *i))
121         *i = '?';
122   } else {
123     nfree(e->u.string);
124     e->u.string = NULL;
125   }
126   if (!noshare && !(u->flags & (USER_BOT | USER_UNSHARED))) {
127     if (e->type != &USERENTRY_INFO || share_greet)
128       shareout(NULL, "c %s %s %s\n", e->type->name, u->handle,
129                e->u.string ? e->u.string : "");
130   }
131   return 1;
132 }
133 
def_gotshare(struct userrec * u,struct user_entry * e,char * data,int idx)134 int def_gotshare(struct userrec *u, struct user_entry *e, char *data, int idx)
135 {
136   putlog(LOG_CMDS, "*", "%s: change %s %s", dcc[idx].nick, e->type->name,
137          u->handle);
138   return e->type->set(u, e, data);
139 }
140 
def_tcl_get(Tcl_Interp * interp,struct userrec * u,struct user_entry * e,int argc,char ** argv)141 int def_tcl_get(Tcl_Interp * interp, struct userrec *u,
142                 struct user_entry *e, int argc, char **argv)
143 {
144   Tcl_AppendResult(interp, e->u.string, NULL);
145   return TCL_OK;
146 }
147 
def_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)148 int def_tcl_set(Tcl_Interp * irp, struct userrec *u,
149                 struct user_entry *e, int argc, char **argv)
150 {
151   BADARGS(4, 4, " handle type setting");
152 
153   e->type->set(u, e, argv[3]);
154   return TCL_OK;
155 }
156 
def_expmem(struct user_entry * e)157 int def_expmem(struct user_entry *e)
158 {
159   return strlen(e->u.string) + 1;
160 }
161 
def_display(int idx,struct user_entry * e)162 void def_display(int idx, struct user_entry *e)
163 {
164   dprintf(idx, "  %s: %s\n", e->type->name, e->u.string);
165 }
166 
def_dupuser(struct userrec * new,struct userrec * old,struct user_entry * e)167 int def_dupuser(struct userrec *new, struct userrec *old, struct user_entry *e)
168 {
169   return set_user(e->type, new, e->u.string);
170 }
171 
comment_display(int idx,struct user_entry * e)172 static void comment_display(int idx, struct user_entry *e)
173 {
174   if (dcc[idx].user && (dcc[idx].user->flags & USER_MASTER))
175     dprintf(idx, "  COMMENT: %.70s\n", e->u.string);
176 }
177 
178 struct user_entry_type USERENTRY_COMMENT = {
179   0,                            /* always 0 ;) */
180   def_gotshare,
181   def_dupuser,
182   def_unpack,
183   def_pack,
184   def_write_userfile,
185   def_kill,
186   def_get,
187   def_set,
188   def_tcl_get,
189   def_tcl_set,
190   def_expmem,
191   comment_display,
192   "COMMENT"
193 };
194 
195 struct user_entry_type USERENTRY_INFO = {
196   0,                            /* always 0 ;) */
197   def_gotshare,
198   def_dupuser,
199   def_unpack,
200   def_pack,
201   def_write_userfile,
202   def_kill,
203   def_get,
204   def_set,
205   def_tcl_get,
206   def_tcl_set,
207   def_expmem,
208   def_display,
209   "INFO"
210 };
211 
pass_set(struct userrec * u,struct user_entry * e,void * buf)212 int pass_set(struct userrec *u, struct user_entry *e, void *buf)
213 {
214   char new[32];
215   register char *pass = buf;
216 
217   if (e->u.extra)
218     nfree(e->u.extra);
219   if (!pass || !pass[0] || (pass[0] == '-'))
220     e->u.extra = NULL;
221   else {
222     unsigned char *p = (unsigned char *) pass;
223 
224     if (strlen(pass) > 30)
225       pass[30] = 0;
226     while (*p) {
227       if ((*p <= 32) || (*p == 127))
228         *p = '?';
229       p++;
230     }
231     if ((u->flags & USER_BOT) || (pass[0] == '+'))
232       strcpy(new, pass);
233     else
234       encrypt_pass(pass, new);
235     e->u.extra = user_malloc(strlen(new) + 1);
236     strcpy(e->u.extra, new);
237   }
238   if (!noshare && !(u->flags & (USER_BOT | USER_UNSHARED)))
239     shareout(NULL, "c PASS %s %s\n", u->handle, pass ? pass : "");
240   return 1;
241 }
242 
pass_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)243 static int pass_tcl_set(Tcl_Interp * irp, struct userrec *u,
244                         struct user_entry *e, int argc, char **argv)
245 {
246   BADARGS(3, 4, " handle PASS ?newpass?");
247 
248   pass_set(u, e, argc == 3 ? NULL : argv[3]);
249   return TCL_OK;
250 }
251 
252 struct user_entry_type USERENTRY_PASS = {
253   0,
254   def_gotshare,
255   0,
256   def_unpack,
257   def_pack,
258   def_write_userfile,
259   def_kill,
260   def_get,
261   pass_set,
262   def_tcl_get,
263   pass_tcl_set,
264   def_expmem,
265   0,
266   "PASS"
267 };
268 
laston_unpack(struct userrec * u,struct user_entry * e)269 static int laston_unpack(struct userrec *u, struct user_entry *e)
270 {
271   char *par, *arg;
272   struct laston_info *li;
273 
274   par = e->u.list->extra;
275   arg = newsplit(&par);
276   if (!par[0])
277     par = "???";
278   li = user_malloc(sizeof(struct laston_info));
279   li->lastonplace = user_malloc(strlen(par) + 1);
280   li->laston = atoi(arg);
281   strcpy(li->lastonplace, par);
282   list_type_kill(e->u.list);
283   e->u.extra = li;
284   return 1;
285 }
286 
laston_pack(struct userrec * u,struct user_entry * e)287 static int laston_pack(struct userrec *u, struct user_entry *e)
288 {
289   char work[1024];
290   struct laston_info *li;
291   int l;
292 
293   li = (struct laston_info *) e->u.extra;
294   l = sprintf(work, "%lu %s", li->laston, li->lastonplace);
295   e->u.list = user_malloc(sizeof(struct list_type));
296   e->u.list->next = NULL;
297   e->u.list->extra = user_malloc(l + 1);
298   strcpy(e->u.list->extra, work);
299   nfree(li->lastonplace);
300   nfree(li);
301   return 1;
302 }
303 
laston_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)304 static int laston_write_userfile(FILE *f, struct userrec *u,
305                                  struct user_entry *e, char *key)
306 {
307   struct laston_info *li = (struct laston_info *) e->u.extra;
308 
309   if (efprintf(f, key, "--LASTON %lu %s\n", li->laston,
310               li->lastonplace ? li->lastonplace : "") == EOF)
311     return 0;
312   return 1;
313 }
314 
laston_kill(struct user_entry * e)315 static int laston_kill(struct user_entry *e)
316 {
317   if (((struct laston_info *) (e->u.extra))->lastonplace)
318     nfree(((struct laston_info *) (e->u.extra))->lastonplace);
319   nfree(e->u.extra);
320   nfree(e);
321   return 1;
322 }
323 
laston_set(struct userrec * u,struct user_entry * e,void * buf)324 static int laston_set(struct userrec *u, struct user_entry *e, void *buf)
325 {
326   struct laston_info *li = (struct laston_info *) e->u.extra;
327 
328   if (li != buf) {
329     if (li) {
330       nfree(li->lastonplace);
331       nfree(li);
332     }
333 
334     li = e->u.extra = buf;
335   }
336   return 1;
337 }
338 
laston_tcl_get(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)339 static int laston_tcl_get(Tcl_Interp * irp, struct userrec *u,
340                           struct user_entry *e, int argc, char **argv)
341 {
342   struct laston_info *li = (struct laston_info *) e->u.extra;
343   char number[20];
344   struct chanuserrec *cr;
345 
346   BADARGS(3, 4, " handle LASTON ?channel?");
347 
348   if (argc == 4) {
349     for (cr = u->chanrec; cr; cr = cr->next)
350       if (!rfc_casecmp(cr->channel, argv[3])) {
351         Tcl_AppendResult(irp, int_to_base10(cr->laston), NULL);
352         break;
353       }
354     if (!cr)
355       Tcl_AppendResult(irp, "0", NULL);
356   } else {
357     sprintf(number, "%lu ", li->laston);
358     Tcl_AppendResult(irp, number, li->lastonplace, NULL);
359   }
360   return TCL_OK;
361 }
362 
laston_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)363 static int laston_tcl_set(Tcl_Interp * irp, struct userrec *u,
364                           struct user_entry *e, int argc, char **argv)
365 {
366   struct laston_info *li;
367   struct chanuserrec *cr;
368 
369   BADARGS(4, 5, " handle LASTON time ?place?");
370 
371   if ((argc == 5) && argv[4][0] && strchr(CHANMETA, argv[4][0])) {
372     for (cr = u->chanrec; cr; cr = cr->next)
373       if (!rfc_casecmp(cr->channel, argv[4])) {
374         cr->laston = atoi(argv[3]);
375         break;
376       }
377   }
378   li = user_malloc(sizeof(struct laston_info));
379 
380   if (argc == 5) {
381     li->lastonplace = user_malloc(strlen(argv[4]) + 1);
382     strcpy(li->lastonplace, argv[4]);
383   } else {
384     li->lastonplace = user_malloc(1);
385     li->lastonplace[0] = 0;
386   }
387   li->laston = atoi(argv[3]);
388   set_user(&USERENTRY_LASTON, u, li);
389   return TCL_OK;
390 }
391 
laston_expmem(struct user_entry * e)392 static int laston_expmem(struct user_entry *e)
393 {
394   return sizeof(struct laston_info) +
395     strlen(((struct laston_info *) (e->u.extra))->lastonplace) + 1;
396 }
397 
laston_dupuser(struct userrec * new,struct userrec * old,struct user_entry * e)398 static int laston_dupuser(struct userrec *new, struct userrec *old,
399                           struct user_entry *e)
400 {
401   struct laston_info *li = e->u.extra, *li2;
402 
403   if (li) {
404     li2 = user_malloc(sizeof(struct laston_info));
405 
406     li2->laston = li->laston;
407     li2->lastonplace = user_malloc(strlen(li->lastonplace) + 1);
408     strcpy(li2->lastonplace, li->lastonplace);
409     return set_user(&USERENTRY_LASTON, new, li2);
410   }
411   return 0;
412 }
413 
414 struct user_entry_type USERENTRY_LASTON = {
415   0,                            /* always 0 ;) */
416   0,
417   laston_dupuser,
418   laston_unpack,
419   laston_pack,
420   laston_write_userfile,
421   laston_kill,
422   def_get,
423   laston_set,
424   laston_tcl_get,
425   laston_tcl_set,
426   laston_expmem,
427   0,
428   "LASTON"
429 };
430 
botaddr_unpack(struct userrec * u,struct user_entry * e)431 static int botaddr_unpack(struct userrec *u, struct user_entry *e)
432 {
433   char *p, *q;
434   struct bot_addr *bi = user_malloc(sizeof(struct bot_addr));
435 
436   EvangelineBzero(bi, sizeof(struct bot_addr));
437 
438   if (!(q = strchr((p = e->u.list->extra), ':'))) {
439     bi->address = user_malloc(strlen(p) + 1);
440     strcpy(bi->address, p);
441   } else {
442     bi->address = user_malloc((q - p) + 1);
443     strncpy(bi->address, p, q - p);
444     bi->address[q - p] = 0;
445     q++;
446     bi->telnet_port = atoi(q);
447     if ((q = strchr(q, '/')))
448       bi->relay_port = atoi(q + 1);
449   }
450   if (!bi->telnet_port)
451     bi->telnet_port = 3333;
452   if (!bi->relay_port)
453     bi->relay_port = bi->telnet_port;
454   list_type_kill(e->u.list);
455   e->u.extra = bi;
456   return 1;
457 }
458 
botaddr_pack(struct userrec * u,struct user_entry * e)459 static int botaddr_pack(struct userrec *u, struct user_entry *e)
460 {
461   char work[1024];
462   struct bot_addr *bi;
463   int l;
464 
465   bi = (struct bot_addr *) e->u.extra;
466   l = simple_sprintf(work, "%s:%u/%u", bi->address, bi->telnet_port,
467                      bi->relay_port);
468   e->u.list = user_malloc(sizeof(struct list_type));
469   e->u.list->next = NULL;
470   e->u.list->extra = user_malloc(l + 1);
471   strcpy(e->u.list->extra, work);
472   nfree(bi->address);
473   nfree(bi);
474   return 1;
475 }
476 
botaddr_kill(struct user_entry * e)477 static int botaddr_kill(struct user_entry *e)
478 {
479   nfree(((struct bot_addr *) (e->u.extra))->address);
480   nfree(e->u.extra);
481   nfree(e);
482   return 1;
483 }
484 
botaddr_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)485 static int botaddr_write_userfile(FILE *f, struct userrec *u,
486                                   struct user_entry *e, char *key)
487 {
488   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
489 
490   if (efprintf(f, key, "--%s %s:%u/%u\n", e->type->name, bi->address,
491               bi->telnet_port, bi->relay_port) == EOF)
492     return 0;
493   return 1;
494 }
495 
botaddr_set(struct userrec * u,struct user_entry * e,void * buf)496 static int botaddr_set(struct userrec *u, struct user_entry *e, void *buf)
497 {
498   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
499 
500   if (!bi && !buf)
501     return 1;
502   if (bi != buf) {
503     if (bi) {
504       nfree(bi->address);
505       nfree(bi);
506     }
507     bi = e->u.extra = buf;
508   }
509   if (bi && !noshare && !(u->flags & USER_UNSHARED)) {
510     shareout(NULL, "c BOTADDR %s %s %d %d\n", u->handle,
511              bi->address, bi->telnet_port, bi->relay_port);
512   }
513   return 1;
514 }
515 
botaddr_tcl_get(Tcl_Interp * interp,struct userrec * u,struct user_entry * e,int argc,char ** argv)516 static int botaddr_tcl_get(Tcl_Interp * interp, struct userrec *u,
517                            struct user_entry *e, int argc, char **argv)
518 {
519   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
520   char number[20];
521 
522   sprintf(number, " %d", bi->telnet_port);
523   Tcl_AppendResult(interp, bi->address, number, NULL);
524   sprintf(number, " %d", bi->relay_port);
525   Tcl_AppendResult(interp, number, NULL);
526   return TCL_OK;
527 }
528 
botaddr_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)529 static int botaddr_tcl_set(Tcl_Interp * irp, struct userrec *u,
530                            struct user_entry *e, int argc, char **argv)
531 {
532   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
533 
534   BADARGS(4, 6, " handle type address ?telnetport ?relayport??");
535 
536   if (u->flags & USER_BOT) {
537     if (!bi) {
538       bi = user_malloc(sizeof(struct bot_addr));
539       EvangelineBzero(bi, sizeof(struct bot_addr));
540     } else
541       nfree(bi->address);
542     bi->address = user_malloc(strlen(argv[3]) + 1);
543     strcpy(bi->address, argv[3]);
544     if (argc > 4)
545       bi->telnet_port = atoi(argv[4]);
546     if (argc > 5)
547       bi->relay_port = atoi(argv[5]);
548     if (!bi->telnet_port)
549       bi->telnet_port = 3333;
550     if (!bi->relay_port)
551       bi->relay_port = bi->telnet_port;
552     botaddr_set(u, e, bi);
553   }
554   return TCL_OK;
555 }
556 
botaddr_expmem(struct user_entry * e)557 static int botaddr_expmem(struct user_entry *e)
558 {
559   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
560 
561   return strlen(bi->address) + 1 + sizeof(struct bot_addr);
562 }
563 
botaddr_display(int idx,struct user_entry * e)564 static void botaddr_display(int idx, struct user_entry *e)
565 {
566   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
567 
568   dprintf(idx, "  ADDRESS: %.70s\n", bi->address);
569   dprintf(idx, "     users: %d, bots: %d\n", bi->relay_port, bi->telnet_port);
570 }
571 
botaddr_gotshare(struct userrec * u,struct user_entry * e,char * buf,int idx)572 static int botaddr_gotshare(struct userrec *u, struct user_entry *e,
573                             char *buf, int idx)
574 {
575   struct bot_addr *bi = user_malloc(sizeof(struct bot_addr));
576   char *arg;
577 
578   EvangelineBzero(bi, sizeof(struct bot_addr));
579   arg = newsplit(&buf);
580   bi->address = user_malloc(strlen(arg) + 1);
581   strcpy(bi->address, arg);
582   arg = newsplit(&buf);
583   bi->telnet_port = atoi(arg);
584   bi->relay_port = atoi(buf);
585   if (!bi->telnet_port)
586     bi->telnet_port = 3333;
587   if (!bi->relay_port)
588     bi->relay_port = bi->telnet_port;
589   if (!(dcc[idx].status & STAT_GETTING))
590     putlog(LOG_CMDS, "*", "%s: change botaddr %s", dcc[idx].nick, u->handle);
591   return botaddr_set(u, e, bi);
592 }
593 
botaddr_dupuser(struct userrec * new,struct userrec * old,struct user_entry * e)594 static int botaddr_dupuser(struct userrec *new, struct userrec *old,
595                            struct user_entry *e)
596 {
597   if (old->flags & USER_BOT) {
598     struct bot_addr *bi = e->u.extra, *bi2;
599 
600     if (bi) {
601       bi2 = user_malloc(sizeof(struct bot_addr));
602 
603       bi2->telnet_port = bi->telnet_port;
604       bi2->relay_port = bi->relay_port;
605       bi2->address = user_malloc(strlen(bi->address) + 1);
606       strcpy(bi2->address, bi->address);
607       return set_user(&USERENTRY_BOTADDR, new, bi2);
608     }
609   }
610   return 0;
611 }
612 
613 struct user_entry_type USERENTRY_BOTADDR = {
614   0,                            /* always 0 ;) */
615   botaddr_gotshare,
616   botaddr_dupuser,
617   botaddr_unpack,
618   botaddr_pack,
619   botaddr_write_userfile,
620   botaddr_kill,
621   def_get,
622   botaddr_set,
623   botaddr_tcl_get,
624   botaddr_tcl_set,
625   botaddr_expmem,
626   botaddr_display,
627   "BOTADDR"
628 };
629 
xtra_set(struct userrec * u,struct user_entry * e,void * buf)630 int xtra_set(struct userrec *u, struct user_entry *e, void *buf)
631 {
632   struct xtra_key *curr, *old = NULL, *new = buf;
633 
634   for (curr = e->u.extra; curr; curr = curr->next) {
635     if (curr->key && !EvangelineStrcasecmp(curr->key, new->key)) {
636       old = curr;
637       break;
638     }
639   }
640   if (!old && (!new->data || !new->data[0])) {
641     nfree(new->key);
642     if (new->data)
643       nfree(new->data);
644     nfree(new);
645     return TCL_OK;
646   }
647 
648   if (!noshare && !(u->flags & (USER_BOT | USER_UNSHARED)))
649     shareout(NULL, "c XTRA %s %s %s\n", u->handle, new->key,
650              new->data ? new->data : "");
651   if ((old && old != new) || !new->data || !new->data[0]) {
652     list_delete((struct list_type **) (&e->u.extra), (struct list_type *) old);
653     nfree(old->key);
654     nfree(old->data);
655     nfree(old);
656   }
657   if (old != new && new->data) {
658     if (new->data[0])
659       list_insert((&e->u.extra), new)
660   } else {
661     if (new->data)
662       nfree(new->data);
663     nfree(new->key);
664     nfree(new);
665   }
666   return TCL_OK;
667 }
668 
xtra_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)669 static int xtra_tcl_set(Tcl_Interp * irp, struct userrec *u,
670                         struct user_entry *e, int argc, char **argv)
671 {
672   struct xtra_key *xk;
673   int l;
674 
675   BADARGS(4, 5, " handle type key ?value?");
676 
677   xk = user_malloc(sizeof(struct xtra_key));
678   l = strlen(argv[3]);
679   EvangelineBzero(xk, sizeof(struct xtra_key));
680   if (l > 500)
681     l = 500;
682   xk->key = user_malloc(l + 1);
683   strncpyz(xk->key, argv[3], l + 1);
684 
685   if (argc == 5) {
686     int k = strlen(argv[4]);
687 
688     if (k > 500 - l)
689       k = 500 - l;
690     xk->data = user_malloc(k + 1);
691     strncpyz(xk->data, argv[4], k + 1);
692   }
693   xtra_set(u, e, xk);
694   return TCL_OK;
695 }
696 
xtra_unpack(struct userrec * u,struct user_entry * e)697 int xtra_unpack(struct userrec *u, struct user_entry *e)
698 {
699   struct list_type *curr, *head;
700   struct xtra_key *t;
701   char *key, *data;
702 
703   head = curr = e->u.list;
704   e->u.extra = NULL;
705   while (curr) {
706     t = user_malloc(sizeof(struct xtra_key));
707 
708     data = curr->extra;
709     key = newsplit(&data);
710     if (data[0]) {
711       t->key = user_malloc(strlen(key) + 1);
712       strcpy(t->key, key);
713       t->data = user_malloc(strlen(data) + 1);
714       strcpy(t->data, data);
715       list_insert((&e->u.extra), t);
716     }
717     curr = curr->next;
718   }
719   list_type_kill(head);
720   return 1;
721 }
722 
xtra_pack(struct userrec * u,struct user_entry * e)723 static int xtra_pack(struct userrec *u, struct user_entry *e)
724 {
725   struct list_type *t;
726   struct xtra_key *curr, *next;
727 
728   curr = e->u.extra;
729   e->u.list = NULL;
730   while (curr) {
731     t = user_malloc(sizeof(struct list_type));
732     t->extra = user_malloc(strlen(curr->key) + strlen(curr->data) + 4);
733     sprintf(t->extra, "%s %s", curr->key, curr->data);
734     list_insert((&e->u.list), t);
735     next = curr->next;
736     nfree(curr->key);
737     nfree(curr->data);
738     nfree(curr);
739     curr = next;
740   }
741   return 1;
742 }
743 
xtra_display(int idx,struct user_entry * e)744 static void xtra_display(int idx, struct user_entry *e)
745 {
746   int code, lc, j;
747   EVANGELINE_CONST char **list;
748   struct xtra_key *xk;
749 
750   code = Tcl_SplitList(interp, whois_fields, &lc, &list);
751   if (code == TCL_ERROR)
752     return;
753   for (xk = e->u.extra; xk; xk = xk->next) {
754     for (j = 0; j < lc; j++) {
755       if (!EvangelineStrcasecmp(list[j], xk->key))
756         dprintf(idx, "  %s: %s\n", xk->key, xk->data);
757     }
758   }
759   Tcl_Free((char *) list);
760 }
761 
xtra_gotshare(struct userrec * u,struct user_entry * e,char * buf,int idx)762 static int xtra_gotshare(struct userrec *u, struct user_entry *e,
763                          char *buf, int idx)
764 {
765   char *arg;
766   struct xtra_key *xk;
767   int l;
768 
769   arg = newsplit(&buf);
770   if (!arg[0])
771     return 1;
772 
773   xk = user_malloc(sizeof(struct xtra_key));
774   EvangelineBzero(xk, sizeof(struct xtra_key));
775   l = strlen(arg);
776   if (l > 500)
777     l = 500;
778   xk->key = user_malloc(l + 1);
779   strncpyz(xk->key, arg, l + 1);
780 
781   if (buf[0]) {
782     int k = strlen(buf);
783 
784     if (k > 500 - l)
785       k = 500 - l;
786     xk->data = user_malloc(k + 1);
787     strncpyz(xk->data, buf, k + 1);
788   }
789   xtra_set(u, e, xk);
790   return 1;
791 }
792 
xtra_dupuser(struct userrec * new,struct userrec * old,struct user_entry * e)793 static int xtra_dupuser(struct userrec *new, struct userrec *old,
794                         struct user_entry *e)
795 {
796   struct xtra_key *x1, *x2;
797 
798   for (x1 = e->u.extra; x1; x1 = x1->next) {
799     x2 = user_malloc(sizeof(struct xtra_key));
800 
801     x2->key = user_malloc(strlen(x1->key) + 1);
802     strcpy(x2->key, x1->key);
803     x2->data = user_malloc(strlen(x1->data) + 1);
804     strcpy(x2->data, x1->data);
805     set_user(&USERENTRY_XTRA, new, x2);
806   }
807   return 1;
808 }
809 
xtra_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)810 static int xtra_write_userfile(FILE *f, struct userrec *u,
811                                struct user_entry *e, char *key)
812 {
813   struct xtra_key *x;
814 
815   for (x = e->u.extra; x; x = x->next)
816     if (efprintf(f, key, "--XTRA %s %s\n", x->key, x->data) == EOF)
817       return 0;
818   return 1;
819 }
820 
xtra_kill(struct user_entry * e)821 int xtra_kill(struct user_entry *e)
822 {
823   struct xtra_key *x, *y;
824 
825   for (x = e->u.extra; x; x = y) {
826     y = x->next;
827     nfree(x->key);
828     nfree(x->data);
829     nfree(x);
830   }
831   nfree(e);
832   return 1;
833 }
834 
xtra_tcl_get(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)835 static int xtra_tcl_get(Tcl_Interp * irp, struct userrec *u,
836                         struct user_entry *e, int argc, char **argv)
837 {
838   struct xtra_key *x;
839 
840   BADARGS(3, 4, " handle XTRA ?key?");
841 
842   if (argc == 4) {
843     for (x = e->u.extra; x; x = x->next)
844       if (!EvangelineStrcasecmp(argv[3], x->key)) {
845         Tcl_AppendResult(irp, x->data, NULL);
846         return TCL_OK;
847       }
848     return TCL_OK;
849   }
850   for (x = e->u.extra; x; x = x->next) {
851     char *p;
852     EVANGELINE_CONST char *list[2];
853 
854     list[0] = x->key;
855     list[1] = x->data;
856     p = Tcl_Merge(2, list);
857     Tcl_AppendElement(irp, p);
858     Tcl_Free((char *) p);
859   }
860   return TCL_OK;
861 }
862 
xtra_expmem(struct user_entry * e)863 static int xtra_expmem(struct user_entry *e)
864 {
865   struct xtra_key *x;
866   int tot = 0;
867 
868   for (x = e->u.extra; x; x = x->next) {
869     tot += sizeof(struct xtra_key);
870 
871     tot += strlen(x->key) + 1;
872     tot += strlen(x->data) + 1;
873   }
874   return tot;
875 }
876 
877 struct user_entry_type USERENTRY_XTRA = {
878   0,
879   xtra_gotshare,
880   xtra_dupuser,
881   xtra_unpack,
882   xtra_pack,
883   xtra_write_userfile,
884   xtra_kill,
885   def_get,
886   xtra_set,
887   xtra_tcl_get,
888   xtra_tcl_set,
889   xtra_expmem,
890   xtra_display,
891   "XTRA"
892 };
893 
hosts_dupuser(struct userrec * new,struct userrec * old,struct user_entry * e)894 static int hosts_dupuser(struct userrec *new, struct userrec *old,
895                          struct user_entry *e)
896 {
897   struct list_type *h;
898 
899   for (h = e->u.extra; h; h = h->next)
900     set_user(&USERENTRY_HOSTS, new, h->extra);
901   return 1;
902 }
903 
hosts_null(struct userrec * u,struct user_entry * e)904 static int hosts_null(struct userrec *u, struct user_entry *e)
905 {
906   return 1;
907 }
908 
hosts_write_userfile(FILE * f,struct userrec * u,struct user_entry * e,char * key)909 static int hosts_write_userfile(FILE *f, struct userrec *u,
910                                 struct user_entry *e, char *key)
911 {
912   struct list_type *h;
913 
914   for (h = e->u.extra; h; h = h->next)
915     if (efprintf(f, key, "--HOSTS %s\n", h->extra) == EOF)
916       return 0;
917   return 1;
918 }
919 
hosts_kill(struct user_entry * e)920 static int hosts_kill(struct user_entry *e)
921 {
922   list_type_kill(e->u.list);
923   nfree(e);
924   return 1;
925 }
926 
hosts_expmem(struct user_entry * e)927 static int hosts_expmem(struct user_entry *e)
928 {
929   return list_type_expmem(e->u.list);
930 }
931 
hosts_display(int idx,struct user_entry * e)932 static void hosts_display(int idx, struct user_entry *e)
933 {
934   char s[1024];
935   struct list_type *q;
936 
937   s[0] = 0;
938   strcpy(s, "  HOSTS: ");
939   for (q = e->u.list; q; q = q->next) {
940     if (s[0] && !s[9])
941       strcat(s, q->extra);
942     else if (!s[0])
943       sprintf(s, "         %s", q->extra);
944     else {
945       if (strlen(s) + strlen(q->extra) + 2 > 65) {
946         dprintf(idx, "%s\n", s);
947         sprintf(s, "         %s", q->extra);
948       } else {
949         strcat(s, ", ");
950         strcat(s, q->extra);
951       }
952     }
953   }
954   if (s[0])
955     dprintf(idx, "%s\n", s);
956 }
957 
hosts_set(struct userrec * u,struct user_entry * e,void * buf)958 static int hosts_set(struct userrec *u, struct user_entry *e, void *buf)
959 {
960   if (!buf || !EvangelineStrcasecmp(buf, "none")) {
961     list_type_kill(e->u.list);
962     e->u.list = NULL;
963   } else {
964     char *host = buf, *p = strchr(host, ',');
965     struct list_type **t;
966 
967     while (p) {
968       *p = '?';
969       p = strchr(host, ',');
970     }
971     t = &(e->u.list);
972     while (*t) {
973       if (wild_match(host, (*t)->extra)) {
974         struct list_type *u;
975 
976         u = *t;
977         *t = (*t)->next;
978         if (u->extra)
979           nfree(u->extra);
980         nfree(u);
981       } else
982         t = &((*t)->next);
983     }
984     *t = user_malloc(sizeof(struct list_type));
985 
986     (*t)->next = NULL;
987     (*t)->extra = user_malloc(strlen(host) + 1);
988     strcpy((*t)->extra, host);
989   }
990   return 1;
991 }
992 
hosts_tcl_get(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)993 static int hosts_tcl_get(Tcl_Interp * irp, struct userrec *u,
994                          struct user_entry *e, int argc, char **argv)
995 {
996   struct list_type *x;
997 
998   BADARGS(3, 3, " handle HOSTS");
999 
1000   for (x = e->u.list; x; x = x->next)
1001     Tcl_AppendElement(irp, x->extra);
1002   return TCL_OK;
1003 }
1004 
hosts_tcl_set(Tcl_Interp * irp,struct userrec * u,struct user_entry * e,int argc,char ** argv)1005 static int hosts_tcl_set(Tcl_Interp * irp, struct userrec *u,
1006                          struct user_entry *e, int argc, char **argv)
1007 {
1008   BADARGS(3, 4, " handle HOSTS ?host?");
1009 
1010   if (argc == 4)
1011     addhost_by_handle(u->handle, argv[3]);
1012   else
1013     addhost_by_handle(u->handle, "none");
1014   return TCL_OK;
1015 }
1016 
hosts_gotshare(struct userrec * u,struct user_entry * e,char * buf,int idx)1017 static int hosts_gotshare(struct userrec *u, struct user_entry *e,
1018                           char *buf, int idx)
1019 {
1020   return 0;
1021 }
1022 
1023 struct user_entry_type USERENTRY_HOSTS = {
1024   0,
1025   hosts_gotshare,
1026   hosts_dupuser,
1027   hosts_null,
1028   hosts_null,
1029   hosts_write_userfile,
1030   hosts_kill,
1031   def_get,
1032   hosts_set,
1033   hosts_tcl_get,
1034   hosts_tcl_set,
1035   hosts_expmem,
1036   hosts_display,
1037   "HOSTS"
1038 };
1039 
list_append(struct list_type ** h,struct list_type * i)1040 int list_append(struct list_type **h, struct list_type *i)
1041 {
1042   for (; *h; h = &((*h)->next));
1043   *h = i;
1044   return 1;
1045 }
1046 
list_delete(struct list_type ** h,struct list_type * i)1047 int list_delete(struct list_type **h, struct list_type *i)
1048 {
1049   for (; *h; h = &((*h)->next))
1050     if (*h == i) {
1051       *h = i->next;
1052       return 1;
1053     }
1054   return 0;
1055 }
1056 
list_contains(struct list_type * h,struct list_type * i)1057 int list_contains(struct list_type *h, struct list_type *i)
1058 {
1059   for (; h; h = h->next)
1060     if (h == i) {
1061       return 1;
1062     }
1063   return 0;
1064 }
1065 
add_entry_type(struct user_entry_type * type)1066 int add_entry_type(struct user_entry_type *type)
1067 {
1068   struct userrec *u;
1069 
1070   list_insert(&entry_type_list, type);
1071   for (u = userlist; u; u = u->next) {
1072     struct user_entry *e = find_user_entry(type, u);
1073 
1074     if (e && e->name) {
1075       e->type = type;
1076       e->type->unpack(u, e);
1077       nfree(e->name);
1078       e->name = NULL;
1079     }
1080   }
1081   return 1;
1082 }
1083 
del_entry_type(struct user_entry_type * type)1084 int del_entry_type(struct user_entry_type *type)
1085 {
1086   struct userrec *u;
1087 
1088   for (u = userlist; u; u = u->next) {
1089     struct user_entry *e = find_user_entry(type, u);
1090 
1091     if (e && !e->name) {
1092       e->type->pack(u, e);
1093       e->name = user_malloc(strlen(e->type->name) + 1);
1094       strcpy(e->name, e->type->name);
1095       e->type = NULL;
1096     }
1097   }
1098   return list_delete((struct list_type **) &entry_type_list,
1099                      (struct list_type *) type);
1100 }
1101 
find_entry_type(char * name)1102 struct user_entry_type *find_entry_type(char *name)
1103 {
1104   struct user_entry_type *p;
1105 
1106   for (p = entry_type_list; p; p = p->next) {
1107     if (!EvangelineStrcasecmp(name, p->name))
1108       return p;
1109   }
1110   return NULL;
1111 }
1112 
find_user_entry(struct user_entry_type * et,struct userrec * u)1113 struct user_entry *find_user_entry(struct user_entry_type *et,
1114                                    struct userrec *u)
1115 {
1116   struct user_entry **e, *t;
1117 
1118   for (e = &(u->entries); *e; e = &((*e)->next)) {
1119     if (((*e)->type == et) ||
1120         ((*e)->name && !EvangelineStrcasecmp((*e)->name, et->name))) {
1121       t = *e;
1122       *e = t->next;
1123       t->next = u->entries;
1124       u->entries = t;
1125       return t;
1126     }
1127   }
1128   return NULL;
1129 }
1130 
get_user(struct user_entry_type * et,struct userrec * u)1131 void *get_user(struct user_entry_type *et, struct userrec *u)
1132 {
1133   struct user_entry *e;
1134 
1135   if (u && (e = find_user_entry(et, u)))
1136     return et->get(u, e);
1137   return 0;
1138 }
1139 
set_user(struct user_entry_type * et,struct userrec * u,void * d)1140 int set_user(struct user_entry_type *et, struct userrec *u, void *d)
1141 {
1142   struct user_entry *e;
1143   int r;
1144 
1145   if (!u || !et)
1146     return 0;
1147 
1148   if (!(e = find_user_entry(et, u))) {
1149     e = user_malloc(sizeof(struct user_entry));
1150 
1151     e->type = et;
1152     e->name = NULL;
1153     e->u.list = NULL;
1154     list_insert((&(u->entries)), e);
1155   }
1156   r = et->set(u, e, d);
1157   if (!e->u.list) {
1158     list_delete((struct list_type **) &(u->entries), (struct list_type *) e);
1159     nfree(e);
1160   }
1161   return r;
1162 }
1163