home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / CONVERS.C < prev    next >
C/C++ Source or Header  |  1994-10-09  |  66KB  |  2,404 lines

  1. /* convers server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  * ported to NOS by PE1NMB - 920120
  4.  * Mods by PA0GRI
  5.  * Cleanup, and additional mods by WG7J
  6.  * Additions by N2RJT & WA2ZKD
  7.  */
  8.  
  9. #include <time.h>
  10. #include <ctype.h>
  11. #include <alloc.h>
  12. #ifdef  UNIX
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #endif
  16. #ifdef MSDOS
  17. #include <io.h>
  18. #endif
  19. #include "global.h"
  20. #ifdef CONVERS
  21. #include "mailbox.h"
  22. #include "netuser.h"
  23. #include "pktdrvr.h"
  24. #include "timer.h"
  25. #include "cmdparse.h"
  26. #include "usock.h"
  27. #include "socket.h"
  28. #include "session.h"
  29. #include "files.h"
  30. #include "mailutil.h"
  31.  
  32. #define LINK    1
  33. #define space
  34.  
  35.  
  36. char Chostname[CNAMELEN+1];
  37. void conv_incom __ARGS((int s,void *t,void *p));
  38. void xconv_incom __ARGS((int s,void *t,void *p));
  39. void conv_incom2 __ARGS((int s,void *t,void *p,struct convection *cp));
  40. int ConvUsers;
  41. int ConvHosts;
  42.  
  43. #ifdef space
  44. static char cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
  45. #ifdef LOCAL_CHANNELS
  46. static char clocal[]  = "*** This is a local channel - no chatting with other nodes\n";
  47. static char cmessage[]= "*** This is a message channel - only /msg allowed or received\n";
  48. #endif
  49. #else
  50. static char cnumber[] = "* range 0..%d.\n";
  51. #ifdef LOCAL_CHANNELS
  52. static char clocal[]  = "* LOCAL CHANNEL\n";
  53. static char cmessage[]= "* MESSAGE CHANNEL\n";
  54. #endif
  55. #endif
  56.  
  57. #define MAXCHANNEL  32767
  58. #define LINELEN     256
  59. /* The convers daemon stack needs to be AT LEAST 4 times the LINELEN !
  60.  * since quiet a few of the commands have local vars of size 2 or 3 * LINELEN.
  61.  */
  62. #define CDAEMONSTACK 2048
  63. #define CLINKSTACK 1024
  64. #define MAX_WAITTIME    (60*60*3)
  65. #define NAMELEN 10
  66.  
  67. struct convection {
  68.     int  type;          /* Connection type */
  69. #define CT_UNKNOWN      0
  70. #define CT_USER         1
  71. #define CT_HOST         2
  72. #define CT_CLOSED       3
  73.     char  name[NAMELEN+1];         /* Name of user or host */
  74.     char  host[NAMELEN+1];         /* Name of host where user is logged on */
  75.     struct convection *via;     /* Pointer to neighbor host */
  76.     char *data;                 /* room for some personal data */
  77.     int channel;            /* Channel number */
  78.     int32 time;         /* Connect time */
  79.     int maxq;           /* Maximum outstanding data before link reset */
  80.     int locked;         /* Set if mesg already sent */
  81.     int fd;             /* Socket descriptor */
  82.     int flags;          /* User flags */
  83. #define CLOSE_SOCK  1
  84. #define USE_SOUND   2
  85. #define USE_LZW     4
  86.     /* This buffer is only needed for local users; a lot of space is wasted
  87.      * for users from other hosts (256 bytes per user!). Fixed 930728 - WG7J
  88.      * char ibuf[LINELEN];
  89.      */
  90.     char *ibuf;                      /* Input buffer */
  91.     unsigned long received;          /* Number of bytes received */
  92.     unsigned long xmitted;           /* Number of bytes transmitted */
  93.     struct convection *next;    /* Linked list pointer */
  94. };
  95.  
  96. #define CM_UNKNOWN  (1 << CT_UNKNOWN)
  97. #define CM_USER     (1 << CT_USER)
  98. #define CM_HOST     (1 << CT_HOST)
  99. #define CM_CLOSED   (1 << CT_CLOSED)
  100.  
  101. #define NULLCONNECTION  ((struct convection *) 0)
  102.  
  103. static struct convection *convections;
  104.  
  105. /* N2RJT - added channel names */
  106. #ifdef CHANNELNAMES
  107.  
  108. struct channelname {
  109.     int channel;    /* channel number */
  110.     char *name;     /* channel name   */
  111.     struct channelname *next;   /* linked list pointer */
  112. };
  113.  
  114. #define NULLCHANNELNAME ((struct channelname *) 0)
  115.  
  116. static struct channelname *channelnames = NULLCHANNELNAME;
  117.  
  118. #ifdef LOCAL_CHANNELS
  119. #define ISLOCAL(chan) (!strncmpi(channame_of(chan),"loc",3))
  120. #define ISMESSAGE(chan) (!strncmpi(channame_of(chan),"msg",3))
  121. #endif
  122. #define PERSONAL_LEN 24
  123. #else
  124. #define PERSONAL_LEN 31
  125.  
  126. #ifdef LOCAL_CHANNELS
  127. #define ISLOCAL(chan) (chan>=30000 && chan < 32000)
  128. #define ISMESSAGE(chan) (chan >= 32000)
  129. #endif
  130. #endif /* CHANNELNAMES */
  131.  
  132. #ifndef LOCAL_CHANNELS
  133. #define ISLOCAL(chan) (0)
  134. #define ISMESSAGE(chan) (0)
  135. #endif
  136.  
  137. struct permlink {
  138.     char name[NAMELEN+1];   /* Name of link */
  139.     int32 addr;             /* address to link to */
  140. #ifdef XCONVERS
  141.     int use_lzw;
  142. #endif
  143.     struct convection *convection;  /* Pointer to associated connection */
  144.     int32 statetime;        /* Time of last (dis)connect */
  145.     int  tries;         /* Number of connect tries */
  146.     int32 waittime;         /* Time between connect tries */
  147.     int32 retrytime;        /* Time of next connect try */
  148.     int fd;             /* socket descriptor */
  149.     struct permlink *next;      /* Linked list pointer */
  150. };
  151. #define NULLPERMLINK ((struct permlink *) 0)
  152.  
  153. struct filter_link {
  154.     struct filter_link *next;
  155.     int32 addr;
  156. };
  157. #define NULLFL ((struct filter_link *) 0)
  158.  
  159. #ifdef LINK
  160. struct proc *Linker;
  161. static void connect_permlinks __ARGS((int a,void *b,void *c));
  162. static void update_permlinks __ARGS((char *name,struct convection *cp));
  163. #endif
  164.  
  165. static void free_connection __ARGS((register struct convection *cp));
  166. static char *formatline __ARGS((char  *prefix,char *text));
  167. static char  *timestring __ARGS((long  gmt));
  168. static void clear_locks __ARGS((void));
  169. static void send_msg_to_user __ARGS((char *fromname,char *toname,char *text));
  170. static void send_user_change_msg __ARGS((char *name,char *host,int oldchannel,int newchannel));
  171. static void send_link_change_msg __ARGS((struct convection *cp,char *name,char *change));
  172. static void send_invite_msg __ARGS((char *fromname,char *toname,int channel));
  173. static void personal_command __ARGS((struct convection *cp));
  174. static void bye_command __ARGS((struct convection *cp));
  175. static void send_msg_to_channel __ARGS((char *fromname,int channel,char *text));
  176. static void free_closed_connections __ARGS((void));
  177. static struct convection *alloc_connection __ARGS((int fd));
  178. static void process_commands __ARGS((struct convection *cp,struct mbx *m));
  179. static void set_personal __ARGS((struct convection *cp));
  180. static void personal_data __ARGS((struct convection *cp));
  181. static void store_personal __ARGS((struct convection *cp));
  182. static void version_command __ARGS((struct convection *cp));
  183. static void help_command __ARGS((struct convection *cp));
  184. static int channum_of __ARGS((char *name));
  185. static char *channame_of __ARGS((int num));
  186. static void read_channels __ARGS((void));
  187. static void show_channels __ARGS((struct convection *cp));
  188. static char *pvia __ARGS((void *p));
  189.  
  190. static struct filter_link *Filterlinks;
  191. static int FilterMode;
  192. static struct permlink *permlinks;
  193. extern char Ccall[AXALEN];
  194. static int allow_info_updates;
  195.  
  196. static int docinfo __ARGS((int argc,char *argv[], void *p));
  197. static int docfilter __ARGS((int argc,char *argv[],void *p));
  198. static int dochostname __ARGS((int argc,char *argv[],void *p));
  199. static int dociface __ARGS((int argc,char *argv[],void *p));
  200. static int doconfcall __ARGS((int argc,char *argv[],void *p));
  201. static int doclink __ARGS((int argc,char *argv[],void *p));
  202. static int docxlink __ARGS((int argc,char *argv[],void *p));
  203. static int doclinks __ARGS((int argc,char *argv[],void *p,int lzw));
  204. static int docunlink __ARGS((int argc,char *argv[],void *p));
  205. static int doct4 __ARGS((int argc,char *argv[],void *p));
  206. static int docmaxwait __ARGS((int argc,char *argv[],void *p));
  207. static int dohmaxq __ARGS((int argc,char *argv[],void *p));
  208. static int doumaxq __ARGS((int argc,char *argv[],void *p));
  209. static int dotdisc __ARGS((int argc,char *argv[],void *p));
  210. static int docdefaultchannel __ARGS((int argc,char *argv[],void *p));
  211.  
  212. static struct cmds DFAR Ccmds[] = {
  213.     "channel",  docdefaultchannel, 0, 0, NULLCHAR,
  214.     "filter",   docfilter,  0, 0, NULLCHAR,
  215.     "hmaxq",    dohmaxq,    0, 0, NULLCHAR,
  216.     "hostname", dochostname,0, 0, NULLCHAR,
  217.     "interface",dociface,   0, 0, NULLCHAR,
  218.     "maxwait",  docmaxwait, 0, 0, NULLCHAR,
  219. #ifdef AX25
  220.     "mycall",   doconfcall, 0, 0, NULLCHAR,
  221. #endif
  222. #ifdef LINK
  223.     "link",     doclink,    0, 0, NULLCHAR,
  224. #endif
  225. #ifdef CHANGE_PERSONAL
  226.     "setinfo",  docinfo,    0, 0, NULLCHAR,
  227. #endif
  228. #ifdef AX25
  229.     "t4",       doct4,      0, 0, NULLCHAR,
  230. #endif
  231.     "tdisc",    dotdisc,    0, 0, NULLCHAR,
  232.     "umaxq",    doumaxq,    0, 0, NULLCHAR,
  233. #ifdef LINK
  234.     "drop",   docunlink,  0, 0, NULLCHAR,
  235. #ifdef XCONVERS
  236.     "xlink",    docxlink,   0, 0, NULLCHAR,
  237. #endif
  238. #endif
  239.     NULLCHAR,
  240. };
  241.  
  242. /* N2RJT - usputs doesn't return length. */
  243. static int
  244. usputscnt(int s, char *x)
  245. {
  246.     if (usputs(s,x)!=EOF)
  247.         return strlen(x);
  248.     else
  249.         return -1;
  250. }
  251.  
  252. #ifdef CHANNELNAMES
  253. static int
  254. channum_of(char *name)
  255. {
  256.     struct channelname *tick;
  257.     tick = channelnames;
  258.     while (tick != NULLCHANNELNAME) {
  259.         if (tick->name != NULLCHAR)
  260.             if (!stricmp(name,tick->name))
  261.                 return tick->channel;
  262.         tick = tick->next;
  263.     }
  264.     return -1;
  265. }
  266.  
  267. static char *
  268. channame_of(int num)
  269. {
  270.     struct channelname *tick;
  271.     tick = channelnames;
  272.     while (tick != NULLCHANNELNAME) {
  273.         if (num==tick->channel)
  274.             return tick->name;
  275.         tick = tick->next;
  276.     }
  277.     return NULLCHAR;
  278. }
  279.  
  280. static void
  281. read_channels()
  282. {
  283.     FILE *f;
  284.     char line[256], *s2;
  285.     struct channelname *temp, *list;
  286.     if (channelnames != NULLCHANNELNAME)
  287.         return;
  288.  
  289.     channelnames = NULLCHANNELNAME;
  290.     list = NULLCHANNELNAME;
  291.     if ((f=fopen(Channelfile,READ_TEXT))==NULLFILE)
  292.         return;
  293.  
  294.     while (fgets(line,sizeof(line),f)!=NULL) {
  295.         rip(line);
  296.         temp = (struct channelname *) malloc (sizeof(struct channelname));
  297.         temp->channel = atoi(line);
  298.         temp->name = NULLCHAR;
  299.         if ((s2 = strchr(line,' '))!=0) {
  300.             s2++;
  301.             temp->name = strdup(s2);
  302.         }
  303.         temp->next = NULLCHANNELNAME;
  304.         if (list)
  305.             list->next = temp;
  306.         else
  307.             channelnames = temp;
  308.         list = temp;
  309.     }
  310.     fclose(f);
  311. }
  312.  
  313. static void
  314. show_channels(struct convection *cp)
  315. {
  316.     struct channelname *temp;
  317.     if (channelnames != NULLCHANNELNAME) {
  318.         cp->xmitted += usprintf(cp->fd, "Channel names:\n");
  319.     }
  320.     temp = channelnames;
  321.     while (temp != NULLCHANNELNAME) {
  322.         cp->xmitted += usprintf(cp->fd, "%5d %-8s %s\n",
  323.             temp->channel, temp->name, ISLOCAL(temp->channel) ? "(local)" :
  324.             ISMESSAGE(temp->channel) ? "(message)" : "");
  325.         temp = temp->next;
  326.     }
  327.     cp->xmitted += usputscnt(cp->fd, "***\n");
  328. }
  329. #endif /* CHANNELNAMES */
  330.  
  331. /* Multiplexer for top-level convers command */
  332. int
  333. doconvers(argc,argv,p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337. {
  338.     return subcmd(Ccmds,argc,argv,p);
  339. }
  340.  
  341. #ifdef AX25
  342. /* Display or change our AX.25 conference call */
  343. static int
  344. doconfcall(argc,argv,p)
  345. int argc;
  346. char *argv[];
  347. void *p;
  348. {
  349.     char tmp[AXBUF];
  350.  
  351.     if(argc < 2){
  352.         tprintf("%s\n",pax25(tmp,Ccall));
  353.         return 0;
  354.     }
  355.     if(setcall(Ccall,argv[1]) == -1)
  356.         return -1;
  357.     return 0;
  358. }
  359.  
  360. int32 CT4init = 7200;   /* 2 hours default */
  361.  
  362. /* Set link redundancy timer */
  363. static int
  364. doct4(argc,argv,p)
  365. int argc;
  366. char *argv[];
  367. void *p;
  368. {
  369.     return setlong(&CT4init,"Conf. redundancy timer (sec)",argc,argv);
  370. }
  371. #endif /* AX25 */
  372.  
  373. int32 CMaxwait = MAX_WAITTIME;
  374.  
  375. /* Set maxwait time for timed out links */
  376. static int
  377. docmaxwait(argc,argv,p)
  378. int argc;
  379. char *argv[];
  380. void *p;
  381. {
  382.     return setlong(&CMaxwait,"Re-link max wait (sec)",argc,argv);
  383. }
  384.  
  385. int HMaxQ = 5*1024;
  386.  
  387. /* Set max qlimit for host links */
  388. static int
  389. dohmaxq(argc,argv,p)
  390. int argc;
  391. char *argv[];
  392. void *p;
  393. {
  394.     return setint(&HMaxQ,"Max. Host Queue (bytes)",argc,argv);
  395. }
  396.  
  397. int UMaxQ = 1024;
  398.  
  399. /* Set max qlimit for user links */
  400. static int
  401. doumaxq(argc,argv,p)
  402. int argc;
  403. char *argv[];
  404. void *p;
  405. {
  406.     return setint(&UMaxQ,"Max. User Queue (bytes)",argc,argv);
  407. }
  408.  
  409. int CDefaultChannel;
  410.  
  411. /* Set the initial channel */
  412. static int
  413. docdefaultchannel(argc,argv,p)
  414. int argc;
  415. char *argv[];
  416. void *p;
  417. {
  418.     return setint(&CDefaultChannel,"Default channel",argc,argv);
  419. }
  420.  
  421. int32 Ctdiscinit = 0;
  422.  
  423. /* Set convers redundancy timer */
  424. static int
  425. dotdisc(argc,argv,p)
  426. int argc;
  427. char *argv[];
  428. void *p;
  429. {
  430.     return setlong(&Ctdiscinit,"redundancy timer (sec)",argc,argv);
  431. }
  432.  
  433. static int
  434. dochostname(argc,argv,p)
  435. int argc;
  436. char *argv[];
  437. void *p;
  438. {
  439.     if(argc == 1)
  440.         tprintf("%s\n",Chostname);
  441.     else {
  442.         strncpy(Chostname,argv[1],NAMELEN);
  443.         Chostname[CNAMELEN] = '\0';
  444.     }
  445.     return 0;
  446. }
  447.  
  448. #ifdef CHANGE_PERSONAL
  449. static int
  450. docinfo(argc,argv,p)
  451. int argc;
  452. char *argv[];
  453. void *p;
  454. {
  455.     return setbool(&allow_info_updates,"Allow users to change info file",argc,argv);
  456. }
  457. #endif
  458.  
  459. static int
  460. docfilter(argc,argv,p)
  461. int argc;
  462. char *argv[];
  463. void *p;
  464. {
  465.     int32 addr;
  466.     struct filter_link *fl;
  467.  
  468.     if(argc == 1) {
  469.         if(Filterlinks) {
  470.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  471.             for(fl=Filterlinks;fl;fl=fl->next)
  472.                 tprintf("%s\n",inet_ntoa(fl->addr));
  473.         }
  474.         return 0;
  475.     }
  476.     if(!stricmp(argv[1],"mode")) {
  477.         if(argc == 2)
  478.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  479.         else {
  480.             if(*argv[2] == 'a' || *argv[2] == 'A')
  481.                 FilterMode = 1;
  482.             else
  483.                 FilterMode = 0;
  484.         }
  485.         return 0;
  486.     }
  487.     if((addr = resolve(argv[1])) == 0) {
  488.         tprintf(Badhost,argv[1]);
  489.         return 1;
  490.     }
  491.     /* check to see if we already have this in the list */
  492.     for(fl=Filterlinks;fl;fl=fl->next)
  493.         if(fl->addr == addr)
  494.             return 0;       /* already have this one ! */
  495.  
  496.     /* Seems like a new one */
  497.     fl = (struct filter_link *)callocw(1,sizeof(struct filter_link));
  498.     fl->addr = addr;
  499.     fl->next = Filterlinks;
  500.     Filterlinks = fl;
  501.     return 0;
  502. }
  503.  
  504. #ifdef LINK
  505. #ifdef XCONVERS
  506. static int
  507. doclinks(argc,argv,p, use_lzw)
  508. #else
  509. static int
  510. doclink(argc,argv,p)
  511. #endif
  512. int argc;
  513. char *argv[];
  514. void *p;
  515. #ifdef XCONVERS
  516. int use_lzw;
  517. #endif
  518. {
  519.     int32 addr;
  520.     struct permlink *pl;
  521.  
  522.     if(argc == 1) {
  523.         for(pl=permlinks;pl;pl=pl->next)
  524. #ifdef XCONVERS
  525.             tprintf("%10s: %s %s\n",pl->name,inet_ntoa(pl->addr), pl->use_lzw ?
  526.               "XCONVERS" : "CONVERS");
  527. #else
  528.             tprintf("%10s: %s\n",pl->name,inet_ntoa(pl->addr));
  529. #endif
  530.         return 0;
  531.     }
  532.     if((addr = resolve(argv[1])) == 0) {
  533.         tprintf(Badhost,argv[1]);
  534.         return 1;
  535.     }
  536.     /* check to see if we already have a link to such animal,
  537.      * this happens when we stop and restart the server - WG7J
  538.      */
  539.     for(pl=permlinks;pl;pl=pl->next)
  540.         if(pl->addr == addr)
  541.             return 1;       /* already have this one ! */
  542.  
  543.     /* Seems like a new link ! Go add it */
  544.     pl = (struct permlink *)callocw(1,sizeof(struct permlink ));
  545.     pl->addr = addr;
  546. #ifdef XCONVERS
  547.     pl->use_lzw = use_lzw;
  548. #endif
  549.     pl->next = permlinks;
  550.     permlinks = pl;
  551.     if(argc > 2) {
  552.         strncpy(pl->name,argv[2],NAMELEN);
  553.         update_permlinks(pl->name,NULLCONNECTION);
  554.     } else
  555.         strcpy(pl->name,"Unknown");
  556.     if(!Linker)
  557.         Linker = newproc("Clinker",CLINKSTACK,connect_permlinks,0,0,NULL,0);
  558.  
  559.     return 0;
  560. }
  561.  
  562. #ifdef XCONVERS
  563. static int
  564. doclink(argc,argv,p)
  565. int argc;
  566. char *argv[];
  567. void *p;
  568. {
  569.     return doclinks(argc,argv,p,0);
  570. }
  571.  
  572. static int
  573. docxlink(argc,argv,p)
  574. int argc;
  575. char *argv[];
  576. void *p;
  577. {
  578.     return doclinks(argc,argv,p,1);
  579. }
  580. #endif
  581.  
  582. static int
  583. docunlink(argc,argv,p)
  584. int argc;
  585. char *argv[];
  586. void *p;
  587. {
  588.     int fd;
  589.     int32 addr;
  590.     struct permlink *pl, *pls;
  591.  
  592.     if(argc == 1) {
  593.         pl=permlinks;
  594.         permlinks=NULLPERMLINK;
  595.         while(pl) {
  596.             tprintf("Unlinking %s\n",inet_ntoa(pl->addr));
  597. #ifdef LINK_CHANGE_MSG
  598.             send_link_change_msg(pl->convection,pl->name,"unlinked by sysop");
  599. #endif
  600.             shutdown(pl->fd,2);
  601.             close_s(pl->fd);
  602.             pls=pl->next;
  603.             free(pl);
  604.             pl=pls;
  605.         }
  606.         return 0;
  607.     }
  608.     if((addr = resolve(argv[1])) == 0) {
  609.         tprintf(Badhost,argv[1]);
  610.         return 1;
  611.     }
  612.  
  613.     pls=NULLPERMLINK;
  614.     for(pl=permlinks;pl;pls=pl,pl=pl->next)
  615.         if(pl->addr == addr) {
  616.             if (pls)
  617.                 pls->next = pl->next;
  618.             else
  619.                 permlinks = pl->next;
  620. #ifdef LINK_CHANGE_MSG
  621.             send_link_change_msg(pl->convection,pl->name,"unlinked by sysop");
  622. #endif
  623.             tprintf("Unlinking %s\n",inet_ntoa(pl->addr));
  624.             shutdown(pl->fd,2);
  625.             close_s(pl->fd);
  626.             free(pl);
  627.             return 0;
  628.         }
  629.  
  630.     tprintf("Not linked to %s\n",argv[1]);
  631.     return 0;
  632. }
  633. #endif
  634.  
  635. static int
  636. dociface(argc,argv,p)
  637. int argc;
  638. char *argv[];
  639. void *p;
  640. {
  641.     return setflag(argc,argv[1],IS_CONV_IFACE,argv[2]);
  642. }
  643.  
  644. /* Remember how many we've started .. maybe second for LZW link */
  645. static int convers_servers = 0;
  646.  
  647. /* Stop convers server */
  648. int
  649. conv0(argc,argv,p)
  650. int argc;
  651. char *argv[];
  652. void *p;
  653. {
  654.     int16 port;
  655.  
  656.     if(argc < 2)
  657.         port = IPPORT_CONVERS;
  658.     else
  659.         port = atoi(argv[1]);
  660.     if (convers_servers > 0)
  661.     convers_servers--;
  662. #ifdef LINK
  663.     if(!convers_servers && Linker)
  664.         killproc(Linker);
  665. #endif
  666.     return stop_tcp(port);
  667. }
  668.  
  669. /* Start up convers server */
  670. int
  671. conv1(argc,argv,p)
  672. int argc;
  673. char *argv[];
  674. void *p;
  675. {
  676.     int16 port;
  677.  
  678. #ifdef CHANNELNAMES
  679.     if (!convers_servers)
  680.         read_channels();
  681. #endif CHANNELNAMES
  682.     convers_servers++;
  683.     if(argc < 2)
  684.         port = IPPORT_CONVERS;
  685.     else
  686.         port = atoi(argv[1]);
  687.  
  688. #ifdef XCONVERS
  689.     if (port == IPPORT_XCONVERS)
  690.         return start_tcp(port,"XCONVERS Server",xconv_incom,CDAEMONSTACK);
  691.     else
  692. #endif
  693.         return start_tcp(port,"CONVERS Server",conv_incom,CDAEMONSTACK);
  694. }
  695.  
  696. static void
  697. free_connection(cp)
  698. register struct convection *cp;
  699. {
  700.     register struct permlink *p;
  701.  
  702.     for(p = permlinks; p; p = p->next)
  703.         if(p->convection == cp)
  704.             p->convection = NULLCONNECTION;
  705.     /* if(cp->data)   free() checks for NULL; smaller code :-) */
  706.     free(cp->data);
  707.     free(cp->ibuf);
  708.     if(cp->flags & CLOSE_SOCK)
  709.         close_s(cp->fd);
  710.     free((char *) cp);
  711. }
  712.  
  713. static void
  714. free_closed_connections()
  715. {
  716.     register struct convection *cp,*p;
  717.     time_t currtime;
  718.  
  719.     currtime = time(&currtime);
  720.  
  721.     for(p = NULLCONNECTION,cp = convections; cp; )
  722.         if(cp->type == CT_CLOSED ||
  723.         cp->type == CT_UNKNOWN && cp->time + 300 < currtime) {
  724.             if(p) {
  725.                 p->next = cp->next;
  726.                 free_connection(cp);
  727.                 cp = p->next;
  728.             } else {
  729.                 convections = cp->next;
  730.                 free_connection(cp);
  731.                 cp = convections;
  732.             }
  733.         } else {
  734.             p = cp;
  735.             cp = cp->next;
  736.         }
  737. }
  738.  
  739. static void
  740. update_permlinks(name,cp)
  741. char *name;
  742. struct convection *cp;
  743. {
  744.     register struct permlink *p;
  745.     time_t currtime;
  746.  
  747.     for(p = permlinks; p; p = p->next)
  748.         if(!strcmp(p->name,name)) {
  749.             currtime = time(&currtime);
  750.             p->convection = cp;
  751.             p->statetime = currtime;
  752.             p->tries = 0;
  753.             p->waittime = 60;
  754.             p->retrytime = currtime + p->waittime;
  755.         }
  756. }
  757.  
  758. static struct convection *
  759. alloc_connection(fd)
  760. int  fd;
  761. {
  762.     register struct convection *cp;
  763.     time_t currtime;
  764.  
  765.     currtime = time(NULL);
  766.  
  767.     cp = (struct convection *)callocw(1,sizeof(struct convection ));
  768.     cp->ibuf = (char *)callocw(1,LINELEN);
  769.     cp->fd = fd;
  770.     cp->maxq = UMaxQ;       /* Maximum qlimit for user */
  771.     cp->flags = CLOSE_SOCK+USE_SOUND;       /* close on exit, by default */
  772.     cp->time = currtime;
  773.     cp->next = convections;
  774.     convections = cp;
  775.     return cp;
  776. }
  777.  
  778. #ifdef LINK
  779. /* check the host links for backlogged data.
  780.  * If larger then set threshold, kill the link.
  781.  * WG7J, 930208
  782.  */
  783. void check_buffer_overload(void) {
  784.     struct convection *p;
  785.  
  786.     /* check the size of the outstanding data buffers */
  787.     for(p = convections; p; p = p->next)
  788.         if((p->maxq != 0) && (socklen(p->fd,1) > p->maxq)) {
  789.                 /* notify everyone of this special :-) occasion */
  790.             bye_command(p);
  791.                 /* Blow this one out of the water */
  792.             shutdown(p->fd,2);
  793.             close_s(p->fd);
  794.         }
  795. }
  796.  
  797. void
  798. connect_permlinks(a,b,c)
  799. int a;
  800. void *b;
  801. void *c;
  802. {
  803.     int s,x;
  804.     register struct permlink *p;
  805.     struct sockaddr_in cport;
  806.     time_t currtime;
  807.  
  808.     for(;;) {
  809.         pause(15000L);
  810.         for(p = permlinks; p; p = p->next) {
  811.             currtime = time(&currtime);
  812.             if(p->convection || p->retrytime > currtime)
  813.                 continue;
  814.             p->tries++;
  815.             p->waittime <<= 1;
  816.             if(p->waittime > CMaxwait)
  817.                 p->waittime = CMaxwait;
  818.             p->retrytime = p->waittime + currtime;
  819. #ifdef XCONVERS
  820.             x = p->use_lzw;
  821. #else
  822.             x = 0;
  823. #endif
  824.             cport.sin_family = AF_INET;
  825.             cport.sin_port = x ? IPPORT_XCONVERS : IPPORT_CONVERS;
  826.             cport.sin_addr.s_addr = p->addr; /* we've resolved this earlier */
  827.             if((s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  828.                 continue;
  829.             if(connect(s,(char *)&cport,SOCKSIZE) == -1) {
  830.                 shutdown(s,2);  /* to make sure it doesn't linger around */
  831.                 close_s(s);     /* WG7J - 9207228 */
  832.                 continue;
  833.             }
  834.             p->fd = s;
  835.             if(newproc("permlink",CDAEMONSTACK,
  836. #ifdef XCONVERS
  837.                x ? xconv_incom : conv_incom,
  838. #else
  839.                conv_incom,
  840. #endif
  841.                s,(void *)TELNET,NULL,0) == NULLPROC){
  842.                 shutdown(s,2);  /* blow it out of the water :-) */
  843.                 close_s(s);
  844.             }
  845.         }
  846.         /* This is now called from the garbage collect process, such that it
  847.          * checks even when the linker process isn't running! - WG7J
  848.         check_buffer_overload();
  849.         */
  850.     }
  851. }
  852. #endif
  853.  
  854.  
  855. static void
  856. clear_locks()
  857. {
  858.     register struct convection *p;
  859.  
  860.     for(p = convections;p;p = p->next)
  861.         p->locked = 0;
  862. }
  863.  
  864. static void send_sounds(struct convection *p) {
  865.     if(p->flags & USE_SOUND)
  866.         p->xmitted += usputscnt(p->fd,"");
  867. }
  868.  
  869. static char *timestring();
  870.  
  871. #ifdef LINK
  872. #ifdef LINK_CHANGE_MSG
  873. static void
  874. send_link_change_msg(cp,name,change)
  875. struct convection *cp;
  876. char *name,*change;
  877. {
  878.     register struct convection *p;
  879.     time_t curtime;
  880.     char   *now;
  881.     char deadmsg[256];
  882.     int users;
  883.  
  884.     curtime = time(NULL);
  885.     now = timestring(curtime);
  886.  
  887.     if (change=="DEAD") {
  888.         users = 0;
  889.         strcpy(deadmsg, "link lost, users:");
  890.         for(p = convections; p; p = p->next)
  891.             if(p->via == cp) {
  892.                 p->type = CT_CLOSED;
  893.                 strcat(deadmsg, " ");
  894.                 strcat(deadmsg, p->name);
  895.                 users++;
  896.             }
  897.         if (users==0)
  898.             strcpy(deadmsg, "link lost, no users.");
  899.  
  900.     } else
  901.         strcpy(deadmsg,change);
  902.  
  903.     clear_locks();
  904.     for(p = convections; p; p = p->next) {
  905.     if(p->type == CT_USER && !p->via && !p->locked)
  906.             p->xmitted += usprintf(p->fd,
  907.               "***%s %s %s.\n", now,name,deadmsg);
  908.     }
  909.     return;
  910. }
  911. #endif
  912. #endif
  913.  
  914. static void
  915. send_user_change_msg(name,host,oldchannel,newchannel)
  916. char  *name,*host;
  917. int  oldchannel,newchannel;
  918. {
  919.     register struct convection *p;
  920.     time_t curtime;
  921.     char   *now;
  922.     char   tempname[NAMELEN+CNAMELEN+3];
  923. #ifdef CHANNELNAMES
  924.     char *channame;
  925.     channame = channame_of(newchannel);
  926. #endif /* CHANNELNAMES */
  927.  
  928.     curtime = time(NULL);
  929.     now = timestring(curtime);
  930.     strcpy(tempname,name);
  931.     if (strcmp(host,Chostname)) {
  932.         strcat(tempname,"@");
  933.         strcat(tempname,host);
  934.     }
  935.  
  936.     for(p = convections; p; p = p->next) {
  937.         if(p->type == CT_USER && !p->via && !p->locked
  938. #ifdef LINK_CHANGE_MSG
  939.           && newchannel != -2
  940. #endif
  941.  
  942. #ifdef LOCAL_CHANNELS
  943.     && !ISMESSAGE(p->channel)
  944. #endif
  945.  
  946.         ) {
  947.             if(p->channel == oldchannel) {
  948.                 if(newchannel >= 0) {
  949. #ifdef CHANNELNAMES
  950.                     if (channame != NULLCHAR)
  951.                         p->xmitted += usprintf(p->fd,
  952.                         "***%s %s switched to channel %d (%s).\n",
  953.                         now,tempname,newchannel,channame);
  954.                     else
  955. #endif  /* CHANNELNAMES */
  956.                         p->xmitted += usprintf(p->fd,
  957.                         "***%s %s switched to channel %d.\n",
  958.                         now, tempname,newchannel);
  959.                 } else
  960.                     p->xmitted += usprintf(p->fd,
  961.                     "***%s %s signed off.\n",now, tempname);
  962.                 p->locked = 1;
  963.             }
  964.             if(p->channel == newchannel) {
  965.                 send_sounds(p);
  966.                 p->xmitted += usprintf(p->fd,
  967.                 "***%s %s signed on.\n",now, tempname);
  968.                 p->locked = 1;
  969.             }
  970.         }
  971.         if(p->type == CT_HOST && !p->locked) {
  972.             p->xmitted += usprintf(p->fd,
  973.             "/\377\200USER %s %s %d %d %d\n",
  974.             name,host,0,oldchannel,newchannel == -2 ? -1 : newchannel);
  975.             p->locked = 1;
  976.         }
  977.     }
  978.     return;
  979. }
  980.  
  981. #ifdef Oldcode
  982.  
  983. static char *
  984. formatline(prefix,text)
  985. char  *prefix,*text;
  986. {
  987.  
  988. #define PREFIXLEN 10
  989. #define CONVLINELEN   79
  990.  
  991.     register char  *f,*t,*x;
  992.     register int  l,lw;
  993.  
  994.     static char buf[2*LINELEN];
  995.  
  996.     for(f = prefix,t = buf; *f; *t++ = *f++) ;
  997.     l = (int)(t - buf);
  998.     f = text;
  999.  
  1000.     for(;;) {
  1001.         while(isspace(uchar(*f)))
  1002.             f++;
  1003.         if(!*f) {
  1004.             *t++ = '\n';
  1005.             *t = '\0';
  1006.             return buf;
  1007.         }
  1008.         for(x = f; *x && !isspace(uchar(*x)); x++) ;
  1009.         lw = (int)(x - f);
  1010.         if(l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
  1011.             *t++ = '\n';
  1012.             l = 0;
  1013.         }
  1014.         do {
  1015.             *t++ = ' ';
  1016.             l++;
  1017.         } while(l < PREFIXLEN);
  1018.         while(lw--) {
  1019.             *t++ = *f++;
  1020.             l++;
  1021.         }
  1022.     }
  1023. }
  1024.  
  1025. static void
  1026. send_msg_to_user(fromname,toname,text)
  1027. char  *fromname,*toname,*text;
  1028. {
  1029.     register struct convection *p;
  1030.     char buffer[2*LINELEN];
  1031.  
  1032.     for(p = convections; p; p = p->next) {
  1033.         if(p->type == CT_USER && !strcmp(p->name,toname))
  1034.             if(p->via) {
  1035.                 if(!p->via->locked) {
  1036.                     p->via->xmitted += usprintf(p->via->fd,
  1037.                     "/\377\200UMSG %s %s %s\n",fromname,toname,text);
  1038.                     p->via->locked = 1;
  1039.                 }
  1040.             } else {
  1041.                 if(!p->locked) {
  1042.                     if(strcmp(fromname,"conversd")) {
  1043.                         sprintf(buffer,"<*%s*>:",fromname);
  1044.                         p->xmitted += usputscnt(p->fd,formatline(buffer,text));
  1045.                     } else {
  1046.                         p->xmitted += usputscnt(p->fd,text);
  1047.                         p->xmitted += usputscnt("\n");
  1048.                     }
  1049.                     p->locked = 1;
  1050.                 }
  1051.             }
  1052.     }
  1053.     return;
  1054. }
  1055.  
  1056. static void
  1057. send_msg_to_channel(fromname,channel,text)
  1058. char  *fromname;
  1059. int  channel;
  1060. char  *text;
  1061. {
  1062.     char  buffer[3*LINELEN];
  1063.     register struct convection *p;
  1064.  
  1065. #ifdef LOCAL_CHANNELS
  1066.     if (ISMESSAGE(p->channel))
  1067.         return;
  1068. #endif
  1069.  
  1070.     for(p = convections; p; p = p->next) {
  1071.         if(p->type == CT_USER && p->channel == channel)
  1072.             if(p->via && !ISLOCAL(p->channel)) {
  1073.                 if(!p->via->locked) {
  1074.                     p->via->xmitted += usprintf(p->via->fd,
  1075.                     "/\377\200CMSG %s %d ",fromname,channel);
  1076.                     p->via->xmitted += usputscnt(p->via->fd, text);
  1077.                     p->via->xmitted += usputscnt(p->via->fd, "\n");
  1078.                     p->via->locked = 1;
  1079.                 }
  1080.             } else {
  1081.                 if(!p->locked) {
  1082.                     sprintf(buffer,"<%s>:",fromname);
  1083.                     p->xmitted += usputscnt(p->fd,formatline(&buffer[0],text));
  1084.                     p->locked = 1;
  1085.                 }
  1086.             }
  1087.     }
  1088. }
  1089.  
  1090. #else /* Oldcode */
  1091.  
  1092. /* Returns a formatted version of the given text.
  1093.  * The prefix appears at the beginning of the text, and each
  1094.  * line after the first will be indented to column PREFIXLEN.
  1095.  * All whitespace (SPACE and TAB) will be replaced by a single
  1096.  * SPACE character,
  1097.  * Lines will be filled to be CONVLINELEN characters long, wrapping
  1098.  * words as necessary.
  1099.  *
  1100.  * This uses an static internal  buffer rather than one passed by
  1101.  * the caller.  This increases the static memory used by the program
  1102.  * even if converse isn't active.  If we passed a buffer  allocated
  1103.  * on the stack, the process's stack would have to be large enough.
  1104.  */
  1105. static char *
  1106. formatline(prefix, text)
  1107. char  *prefix, *text;
  1108. {
  1109.  
  1110. #   define PREFIXLEN    10
  1111. #   define CONVLINELEN  79
  1112. #   define FMTBUFLEN    LINELEN
  1113.  
  1114.     static char          buf[FMTBUFLEN];
  1115.     register char       *f, *t;
  1116.     register int         l, lw;
  1117.     register int         left = FMTBUFLEN-2;
  1118.     /* Runs of characters in delims[] will be collapsed into a single
  1119.        space by formatline().
  1120.      */
  1121.     char                *delims = " \t\n\r";
  1122. /*
  1123. #   define BPUTC(c)     if (left > 0) { left--; *t++ = (c); } else
  1124. */
  1125. #   define BPUTC(c)     do{ if (left > 0) { left--; *t++ = (c); }} while(0)
  1126.  
  1127.     /* Copy prefix into buf; set l to length of prefix.
  1128.      */
  1129.     l = 0;
  1130.     for (f = prefix, t = buf; *f; ) {
  1131.         BPUTC (*f++);
  1132.         l++;
  1133.     }
  1134.  
  1135.     f = text;
  1136.  
  1137.     for (;;) {
  1138.         /* Skip leading spaces */
  1139.         while (isspace(uchar(*f)))
  1140.             f++;
  1141.  
  1142.         /* Return if nothing more or no room left */
  1143.         if (!*f || (left <= 0)) {
  1144.             *t++ = '\n';        /* don't use BPUTC; do even if !left */
  1145.             *t   = '\0';
  1146.             return buf;
  1147.         }
  1148.  
  1149.         /* Find length of next word (seq. of non-blanks) */
  1150.         lw = strcspn (f, delims);
  1151.  
  1152.         /* If the word would extend past end of line, do newline */
  1153.         if (l > PREFIXLEN && (l + 1 + lw) > CONVLINELEN) {
  1154.             BPUTC ('\n');
  1155.             l = 0;
  1156.         }
  1157.  
  1158.         /* Put out a single space */
  1159.         do {
  1160.             BPUTC (' ');
  1161.             l++;
  1162.         } while(l < PREFIXLEN);
  1163.  
  1164.         /* Put out the word */
  1165.         while(lw--) {
  1166.             BPUTC (*f++);
  1167.             l++;
  1168.         }
  1169.     }
  1170. #   undef BPUTC
  1171. }
  1172.  
  1173.  
  1174. static void
  1175. send_msg_to_user(fromname,toname,text)
  1176. char  *fromname,*toname,*text;
  1177. {
  1178.     register struct convection *p;
  1179.  
  1180.     for (p = convections; p; p = p->next) {
  1181.         if(p->type == CT_USER && !strcmp(p->name,toname))
  1182.             if(p->via) {
  1183.                 if(!p->via->locked) {
  1184.                     p->via->xmitted += usprintf(p->via->fd,
  1185.                     "/\377\200UMSG %.10s %.10s %.220s\n",
  1186.                     fromname, toname, text);
  1187.                     p->via->locked = 1;
  1188.                 }
  1189.             } else {
  1190.                 if(!p->locked) {
  1191.                     if(strcmp(fromname,"conversd")) {
  1192.                         char prefix[NAMELEN+10];
  1193.                         char *buf;
  1194.  
  1195.                         sprintf(prefix,"<*%.10s*>:",fromname);
  1196.  
  1197.                         buf = formatline (prefix,text);
  1198.                         p->xmitted += strlen (buf);
  1199.                         (void) usputs (p->fd, buf);
  1200.                     } else {    /* not from conversd */
  1201.                         p->xmitted += strlen (text);
  1202.                         (void) usputs (p->fd, text);
  1203.                     }   /* not from conversd */
  1204.                     p->locked = 1;
  1205.                 } /* if not locked */
  1206.             }   /* not via */
  1207.     } /* for */
  1208. }
  1209.  
  1210. static void
  1211. send_msg_to_channel(fromname,channel,text)
  1212. char  *fromname;
  1213. int  channel;
  1214. char  *text;
  1215. {
  1216.     register struct convection *p;
  1217.  
  1218. #ifdef LOCAL_CHANNELS
  1219.     if (ISMESSAGE(channel))
  1220.         return;
  1221. #endif
  1222.  
  1223.     for (p = convections; p; p = p->next) {
  1224.         if(p->type == CT_USER && p->channel == channel)
  1225.             if(p->via && !ISLOCAL(p->channel)) {
  1226.                 if(!p->via->locked) {
  1227.                     p->via->xmitted += usprintf(p->via->fd,
  1228.                     "/\377\200CMSG %.10s %d %.220s\n",
  1229.                     fromname, channel, text);
  1230.                     p->via->locked = 1;
  1231.                 }
  1232.             } else {
  1233.                 if(!p->locked) {
  1234.                     char         prefix[NAMELEN+10];
  1235.                     char        *buf;
  1236.  
  1237.                     sprintf(prefix,"<%.10s>:", fromname);
  1238.  
  1239.                     buf = formatline (prefix, text);
  1240.                     p->xmitted += strlen (buf);
  1241.                     (void) usputs (p->fd, buf);
  1242.  
  1243.                     p->locked = 1;
  1244.                 } /* not locked */
  1245.             } /* not via */
  1246.     } /* for */
  1247. }
  1248.  
  1249.  
  1250. #endif /* Oldcode */
  1251.  
  1252.  
  1253. extern char *Months[];      /* in smtpserv.c */
  1254.  
  1255. static char  *
  1256. timestring(gmt)
  1257. long  gmt;
  1258. {
  1259.     static char  buffer[10];
  1260.     struct tm *tm;
  1261.     time_t currtime;
  1262.  
  1263.     time(&currtime);
  1264.     tm = localtime(&gmt);
  1265.     if(gmt + 24 * 60 * 60 > currtime)
  1266.         sprintf(buffer," %2d:%02d",tm->tm_hour,tm->tm_min);
  1267.     else
  1268.         sprintf(buffer,"%-3.3s %2d",Months[tm->tm_mon],tm->tm_mday);
  1269.     return buffer;
  1270. }
  1271.  
  1272. #ifdef space
  1273. char invitetext[] = "\n*** Message from %s at%s ...\nPlease join convers channel %d.\n\n";
  1274. char mbinvitetext[] = "\n*** Message from %s at%s ...\nPlease join convers by typing 'CONV %d' !\n\n";
  1275. char responsetext[] = "*** Invitation sent to %s @ %s";
  1276. #else
  1277. char invitetext[] = "\n*** Msg frm %s at%s ...\nPse join ch. %d.\n\n";
  1278. char mbinvitetext[] = "\n*** Msg frm %s at%s ...\nPse hit 'CONV %d' to join convers.\n\n";
  1279. char responsetext[] = "*** sent to %s @ %s";
  1280. #endif
  1281. char cnvd[] = "conversd";
  1282.  
  1283. static void
  1284. send_invite_msg(fromname,toname,channel)
  1285. char  *fromname,*toname;
  1286. int  channel;
  1287. {
  1288.  
  1289.     char buffer[LINELEN];
  1290.     struct convection *p;
  1291. #ifdef MAILBOX
  1292.     struct mbx *m;
  1293. #endif
  1294.     time_t currtime;
  1295.  
  1296.     currtime = time(&currtime);
  1297.  
  1298. #ifdef MAILBOX
  1299.     /* Check users in the mailbox that aren't active */
  1300.     for(m=Mbox;m;m=m->next){
  1301.         if(m->state == MBX_CMD && !stricmp(m->name,toname)) {
  1302.             usprintf(m->user,mbinvitetext,fromname,timestring(currtime),channel);
  1303.             usflush(m->user);
  1304.             clear_locks();
  1305.             sprintf(buffer,responsetext,toname,"BBS@");
  1306.             strcat(buffer,Hostname);
  1307.         strcat(buffer,"\n");
  1308.             send_msg_to_user(cnvd,fromname,buffer);
  1309.             return;
  1310.         }
  1311.     }
  1312. #endif
  1313.  
  1314.     /* check the current convers users */
  1315.     for(p = convections; p; p = p->next) {
  1316.         if(p->type == CT_USER && !stricmp(p->name,toname)) {
  1317.             if(p->channel == channel) {
  1318.                 clear_locks();
  1319.                 sprintf(buffer,"*** User %s is already on this channel.\n",toname);
  1320.                 send_msg_to_user(cnvd,fromname,buffer);
  1321.                 return;
  1322.             }
  1323.             if(!p->via && !p->locked) {
  1324.                 p->xmitted += usprintf(p->fd,invitetext,fromname, \
  1325.                 timestring(currtime),channel);
  1326.                 clear_locks();
  1327.                 sprintf(buffer,responsetext,toname,Chostname);
  1328.                 strcat(buffer,"\n");
  1329.                 send_msg_to_user(cnvd,fromname,buffer);
  1330.                 return;
  1331.             }
  1332.             if(p->via && !p->via->locked) {
  1333.                 p->via->xmitted += usprintf(p->via->fd,
  1334.                 "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  1335.                 return;
  1336.             }
  1337.         }
  1338.     }
  1339.     /* Nothing found locally, invite user on all links */
  1340.     for(p = convections; p; p = p->next) {
  1341.         if(p->type == CT_HOST && !p->locked) {
  1342.             p->xmitted += usprintf(p->fd,
  1343.             "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  1344.         }
  1345.     }
  1346.     return;
  1347. }
  1348.  
  1349. static void
  1350. bye_command(cp)
  1351. struct convection *cp;
  1352. {
  1353.     struct convection *p;
  1354.  
  1355.     switch(cp->type) {
  1356.         case CT_UNKNOWN:
  1357.             cp->type = CT_CLOSED;
  1358.             break;
  1359.         case CT_USER:
  1360.             cp->type = CT_CLOSED;
  1361.             clear_locks();
  1362.             send_user_change_msg(cp->name,cp->host,cp->channel,-1);
  1363.             ConvUsers--;
  1364.             break;
  1365.         case CT_HOST:
  1366.             cp->type = CT_CLOSED;
  1367. #ifdef LINK_CHANGE_MSG
  1368.             send_link_change_msg(cp,cp->name,"DEAD");
  1369. #endif
  1370.             update_permlinks(cp->name,NULLCONNECTION);
  1371.             for(p = convections; p; p = p->next)
  1372.                 if(p->via == cp) {
  1373.                     p->type = CT_CLOSED;
  1374.                     clear_locks();
  1375. #ifdef LINK_CHANGE_MSG
  1376.                     send_user_change_msg(p->name,p->host,p->channel,-2);
  1377. #else
  1378.                     send_user_change_msg(p->name,p->host,p->channel,-1);
  1379. #endif
  1380.                 }
  1381.             ConvHosts--;
  1382.             break;
  1383.         case CT_CLOSED:
  1384.             break;
  1385.     }
  1386. }
  1387.  
  1388. static void
  1389. channel_command(cp)
  1390. struct convection *cp;
  1391. {
  1392. #ifdef CHANNELNAMES
  1393.     char *channame;
  1394.     char s[256];
  1395. #else
  1396.     char  s[7];
  1397. #endif
  1398.     int  newchannel;
  1399.  
  1400.     s[0] = '\0';
  1401.     sscanf(cp->ibuf,"%*s %6s",s);
  1402.     if(s[0] == '\0') {
  1403. #ifdef space
  1404.         cp->xmitted += usprintf(cp->fd,"*** You are on channel %d",cp->channel);
  1405. #else
  1406.         cp->xmitted += usprintf(cp->fd,"* On channel %d",cp->channel);
  1407. #endif
  1408. #ifdef CHANNELNAMES
  1409.         if ((channame=channame_of(cp->channel))!=NULLCHAR)
  1410.             cp->xmitted += usprintf(cp->fd," (%s)",channame);
  1411. #endif
  1412.         cp->xmitted += usputscnt(cp->fd,".\n");
  1413. #ifdef LOCAL_CHANNELS
  1414.         if (ISLOCAL(cp->channel))
  1415.             cp->xmitted += usputscnt(cp->fd,clocal);
  1416.         if (ISMESSAGE(cp->channel))
  1417.             cp->xmitted += usputscnt(cp->fd,cmessage);
  1418. #endif
  1419. #ifdef CHANNELNAMES
  1420.         show_channels(cp);
  1421. #endif
  1422.         return;
  1423.     }
  1424. #ifdef CHANNELNAMES
  1425.     newchannel = channum_of(s);
  1426.     if (newchannel == -1){
  1427. #endif
  1428.         newchannel = atoi(s);
  1429. #ifdef CHANNELNAMES
  1430.         if (newchannel == 0 && strcmp(s,"0"))
  1431.             newchannel = -1;
  1432.     }
  1433. #endif
  1434.     if(newchannel < 0) {
  1435.         /*  || newchannel > MAXCHANNEL) { */
  1436.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1437.         return;
  1438.     }
  1439.     if(newchannel == cp->channel) {
  1440.         cp->xmitted += usprintf(cp->fd,
  1441.         "*** Already on channel %d.\n",cp->channel);
  1442.         return;
  1443.     }
  1444.     send_user_change_msg(cp->name,cp->host,cp->channel,newchannel);
  1445.     cp->channel = newchannel;
  1446.     cp->xmitted += usprintf(cp->fd,"*** Now on channel %d",cp->channel);
  1447. #ifdef CHANNELNAMES
  1448.     if ((channame=channame_of(cp->channel))!=NULLCHAR)
  1449.         cp->xmitted += usprintf(cp->fd," (%s)",channame);
  1450. #endif
  1451.         cp->xmitted += usputscnt(cp->fd,".\n");
  1452. #ifdef LOCAL_CHANNELS
  1453.     if (ISLOCAL(cp->channel))
  1454.         cp->xmitted += usputscnt(cp->fd,clocal);
  1455.     if (ISMESSAGE(cp->channel))
  1456.         cp->xmitted += usputscnt(cp->fd,cmessage);
  1457. #endif
  1458.     return;
  1459. }
  1460.  
  1461. static void
  1462. help_command(cp)
  1463. struct convection *cp;
  1464. {
  1465.     FILE *fp;
  1466.     char fname[FILE_PATH_SIZE];    
  1467.     sprintf(fname,"%s/convers.hlp",Helpdir);
  1468.     if((fp = fopen(fname,READ_TEXT)) != NULLFILE) {
  1469.         sendfile(fp, cp->fd, ASCII_TYPE, 0, NULL);
  1470.         fclose(fp);
  1471.     } else {
  1472.         cp->xmitted += usprintf(cp->fd,"No help available. /q to quit\n");
  1473.     }
  1474.     return;
  1475. }
  1476.  
  1477. static void
  1478. version_command(cp)
  1479. struct convection *cp;
  1480. {
  1481.     cp->xmitted +=
  1482.     usprintf(cp->fd,"%s, Compile: %s, Uptime: %s, Core: %lu\n",  /*zkd*/
  1483.     shortversion,whofor,tformat(secclock()),farcoreleft());
  1484. }
  1485.  
  1486. static void
  1487. invite_command(cp)
  1488. struct convection *cp;
  1489. {
  1490.     char toname[NAMELEN+1];
  1491.     char *cp1;
  1492.  
  1493.     toname[0] = '\0';
  1494.     sscanf(cp->ibuf,"%*s %10s",toname);
  1495.     if((cp1=strchr(toname,'@')) != NULLCHAR)
  1496.         *cp1 = '\0';
  1497.     strlwr(toname);
  1498.     if(toname[0] != '\0')
  1499.         send_invite_msg(cp->name,toname,cp->channel);
  1500.     return;
  1501. }
  1502.  
  1503. int ShowConfLinks(int s, int full) {
  1504.     int num;
  1505.     struct convection *pc;
  1506.     struct permlink *pp;
  1507.     char  tmp[20];
  1508.  
  1509.     num = usprintf(s,"Host       State         Since%s\n",
  1510.     (full) ? " NextTry Tries Receivd Xmitted TxQueue" : "");
  1511.     for(pc = convections; pc; pc = pc->next)
  1512.         if(pc->type == CT_HOST)
  1513.             num += usprintf(s,
  1514.             (full) ?
  1515.             "%-10s Connected    %s               %7lu %7lu %7u\n" :
  1516.             "%-10s Connected    %s\n",
  1517.             pc->name,
  1518.             timestring(pc->time),
  1519.             pc->received,
  1520.             pc->xmitted,
  1521.             socklen(pc->fd,1));
  1522.  
  1523.     for(pp = permlinks; pp; pp = pp->next)
  1524.         if(!pp->convection || pp->convection->type != CT_HOST) {
  1525.             strcpy(tmp,timestring(pp->retrytime));
  1526.             num += usprintf(s,
  1527.             (full) ?
  1528.             "%-10s %-12s %s %s %5d\n" :
  1529.             "%-10s %-12s %s\n",
  1530.             pp->name,
  1531.             pp->convection ? "Connecting" : "Disconnected",
  1532.             timestring(pp->statetime),
  1533.             tmp,
  1534.             pp->tries);
  1535.         }
  1536.     num += usputscnt(s,"***\n");
  1537.     return num;
  1538. }
  1539.  
  1540. static void
  1541. links_command(cp)
  1542. struct convection *cp;
  1543. {
  1544.     char full[3];
  1545.     int f = 0;
  1546.     time_t curtime;
  1547.  
  1548.     curtime = time(NULL);
  1549.     cp->xmitted += usprintf(cp->fd,"*** %s",ctime(&curtime));
  1550.     full[0] = '\0';
  1551.     sscanf(cp->ibuf,"%*s %2s",full);
  1552.     if(*full == 'l' || *full == 'L')
  1553.         f = 1;
  1554.     cp->xmitted += ShowConfLinks(cp->fd,f);
  1555.     return;
  1556. }
  1557.  
  1558. static void
  1559. msg_command(cp)
  1560. struct convection *cp;
  1561. {
  1562.  
  1563.     char dummy[LINELEN],toname[NAMELEN+1],*text;
  1564.     register struct convection *p;
  1565.  
  1566.     toname[0] = '\0';
  1567.     sscanf(cp->ibuf,"%s %10s",dummy,toname);
  1568.     text = &cp->ibuf[0];
  1569.     text += strlen(dummy) + strlen(toname) + 2;
  1570.     strlwr(toname);
  1571.  
  1572.     if(!*text)
  1573.         return;
  1574.     for(p = convections; p; p = p->next)
  1575.         if(p->type == CT_USER && !strcmp(p->name,toname))
  1576.             break;
  1577.     if(!p)
  1578.         cp->xmitted += usprintf(cp->fd,"*** No such user: %s.\n",toname);
  1579.     else
  1580.         send_msg_to_user(cp->name,toname,text);
  1581.     return;
  1582. }
  1583.  
  1584. /* Set some personal data, like name and qth - WG7J */
  1585.  
  1586. static void
  1587. #ifdef CHANGE_PERSONAL
  1588. personal_data(cp)
  1589. #else
  1590. personal_command(cp)
  1591. #endif
  1592. struct convection *cp;
  1593. {
  1594.     struct convection *p;
  1595.     char *cp2;
  1596.  
  1597.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1598.         cp2++;
  1599.         if(*cp2) {  /* there actually is an argument */
  1600.             free(cp->data);
  1601.             rip(cp->ibuf);      /* get rid of ending '\n' */
  1602.             if(strlen(cp2) > PERSONAL_LEN)
  1603.                 *(cp2+PERSONAL_LEN) = '\0';
  1604.             cp->data = strdup(cp2);
  1605.             /* update all links too ! - WG7J */
  1606.             for(p=convections;p;p=p->next)
  1607.                 if(p->type == CT_HOST)
  1608.                     p->xmitted += usprintf(p->fd,"/\377\200UDAT %s %s %s\n",
  1609.                     cp->name,cp->host,cp->data);
  1610.             return;
  1611.         }
  1612.     }
  1613.     cp->xmitted += usprintf(cp->fd,"*** data set to: %s\n", \
  1614.     cp->data ? cp->data : "" );
  1615.     return;
  1616. }
  1617.  
  1618. /* find the personal information for this user */
  1619. void set_personal(struct convection *cp) {
  1620.     FILE *fp;
  1621.     char *cp1;
  1622.  
  1623.     if((fp = fopen(Cinfo,"r")) == NULL)
  1624.         return;
  1625.     while(fgets(cp->ibuf,LINELEN,fp) != NULL) {
  1626.         cp1 = cp->ibuf;
  1627.         /* find end of name */
  1628.         while(*cp1 != ' ' && *cp1 != '\t' && *cp1 != '\0')
  1629.             cp1++;
  1630.         if(!*cp1)
  1631.             continue;
  1632.         *cp1 = '\0';
  1633.         if(stricmp(cp->name,cp->ibuf))
  1634.             continue;
  1635.         /* Found personal data ! */
  1636.         *cp1 = ' ';
  1637.         fclose(fp);
  1638.         personal_command(cp);
  1639.         return;
  1640.     }
  1641.     fclose(fp);
  1642.     cp->xmitted += usputscnt(cp->fd,"*** Type /personal <your name> <your QTH>.\n");
  1643. }
  1644.  
  1645. #ifdef CHANGE_PERSONAL
  1646. /* Store personal data - N2RJT */
  1647. static void
  1648. store_personal(struct convection *cp)
  1649. {
  1650.     FILE *f1, *f2;
  1651.     char line[LINELEN];
  1652.     int namelen;
  1653.  
  1654.     namelen = strlen(cp->name);
  1655.     if (cp->data) {
  1656.  
  1657.         /* Save old personal file to backup */
  1658.         unlink(Cinfobak);
  1659.         if(rename(Cinfo,Cinfobak))
  1660.             return;
  1661.  
  1662.         /*Write all users back, but update this one!*/
  1663.         if((f2 = fopen(Cinfo,WRITE_TEXT)) == NULLFILE)
  1664.             /* Can't create defaults file ???*/
  1665.             return;
  1666.  
  1667.         if((f1 = fopen(Cinfobak,READ_TEXT)) != NULLFILE) {
  1668.             while (fgets(line, LINELEN, f1)!=NULLCHAR) {
  1669.                 if (strncmp(line,cp->name,namelen))
  1670.                     fputs(line, f2);
  1671.             }
  1672.             fclose(f1);
  1673.         }
  1674.         fprintf(f2, "%s %s\n", cp->name, cp->data);
  1675.         fclose(f2);
  1676.     }
  1677. }
  1678.  
  1679. static void
  1680. personal_command(cp)
  1681. struct convection *cp;
  1682. {
  1683.     personal_data(cp);
  1684.     if (allow_info_updates)
  1685.         store_personal(cp);
  1686. }
  1687. #endif  /* CHANGE_PERSONAL */
  1688.  
  1689. void SendMotd(int s)
  1690. {
  1691.     FILE *fp;
  1692.  
  1693.     if((fp=fopen(ConvMotd,"r")) != NULL) {
  1694.         sendfile(fp, s, ASCII_TYPE, 0, NULL);
  1695.         fclose(fp);
  1696.     }
  1697. }
  1698.  
  1699.  
  1700. /* protected by ftpusers file - WG7J */
  1701. static void
  1702. name_command(cp)
  1703. struct convection *cp;
  1704. {
  1705.     int newchannel = CDefaultChannel;
  1706.     char dummy[7];
  1707.     char *path;
  1708.     int pwdignore;
  1709.     long privs;
  1710. #ifdef CALLCHECK
  1711.     int i,digits;
  1712. #endif
  1713.  
  1714.     cp->name[0] = '\0';
  1715.     dummy[0] = '\0';
  1716.     sscanf(cp->ibuf,"%*s %10s %6s",cp->name,dummy);
  1717.     if(dummy[0] != '\0')
  1718.         newchannel = atoi(dummy);
  1719.     if(cp->name[0] == '\0')
  1720.         return;
  1721.     /* now check with ftpusers file - WG7J */
  1722.     if((path = mallocw(MBXLINE)) == NULLCHAR)
  1723.         return;
  1724.     pwdignore = 1;
  1725.     privs = userlogin(cp->name,NULLCHAR,&path,MBXLINE,&pwdignore,"confdef");
  1726.     free(path);
  1727.     if(privs & NO_CONVERS)
  1728.         return;
  1729. /* N2RJT - validate the callsign, similar to the check done in mailbox.c */
  1730. /* In this context, a valid callsign is any with 3 or more characters,   */
  1731. /* and at least one digit.  Length and digits don't include anything     */
  1732. /* after a dash.                                                         */
  1733. #ifdef CALLCHECK
  1734.     for (digits=i=0; i<strlen(cp->name); i++) {
  1735.         if ((cp->name)[i] == '-')
  1736.             break;
  1737.         if (isdigit((cp->name)[i]))
  1738.             digits++;
  1739.     }
  1740.     if (i<3 || digits==0)
  1741.         return;
  1742. #endif /* CALLCHECK */
  1743.     strlwr(cp->name);
  1744.     strcpy(cp->host,Chostname);
  1745.     cp->type = CT_USER;
  1746.     cp->xmitted += usprintf(cp->fd,
  1747.     "Conference @ %s  Type /HELP for help.\n",Chostname);
  1748.     /* Send the motd */
  1749.     SendMotd(cp->fd);
  1750.     if(dummy[0] != '\0' && newchannel < 0) {
  1751.         /* || newchannel > MAXCHANNEL) { */
  1752.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1753.     } else
  1754.         cp->channel = newchannel;
  1755.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  1756. #ifdef LOCAL_CHANNELS
  1757.     if (ISLOCAL(cp->channel))
  1758.         cp->xmitted += usputscnt(cp->fd,clocal);
  1759.     if (ISMESSAGE(cp->channel))
  1760.         cp->xmitted += usputscnt(cp->fd,cmessage);
  1761. #endif
  1762.     set_personal(cp);
  1763.     ConvUsers++;
  1764.     return;
  1765. }
  1766.  
  1767. /* Set or show the status of the 'sound' flag - WG7J */
  1768. static void
  1769. sounds_command(cp)
  1770. struct convection *cp;
  1771. {
  1772.     char *cp2;
  1773.  
  1774.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1775.         cp2++;
  1776.         if(*cp2) {   /* There is an argument */
  1777.             if(*cp2 == 'n' || *cp2 == 'N') {   /* Turn it off */
  1778.                 cp->flags &= ~USE_SOUND;
  1779.             } else
  1780.                 cp->flags |= USE_SOUND;
  1781.             return;
  1782.         }
  1783.     }
  1784.     if(cp->flags & USE_SOUND)
  1785.         cp->xmitted += usputscnt(cp->fd,"*** Sounds on\n");
  1786.     else
  1787.         cp->xmitted += usputscnt(cp->fd,"*** Sounds off\n");
  1788.     return;
  1789. }
  1790.  
  1791. #ifdef ENHANCED_VIA
  1792. /* Convert a socket (address + port) to an ascii string identifying
  1793.  * the family and possibly neighbor.
  1794.  */
  1795. char *
  1796. pvia(p)
  1797. void *p;    /* Pointer to structure to decode */
  1798. {
  1799.     static char buf[30];
  1800.     union sp sp;
  1801.     struct socket socket;
  1802.     struct nrroute_tab *np;
  1803.  
  1804.     sp.p = p;
  1805.     switch(sp.sa->sa_family){
  1806.     case AF_LOCAL:
  1807.         strcpy(buf,"local");
  1808.         break;
  1809.     case AF_INET:
  1810.         strcpy(buf,"telnet");
  1811.         break;
  1812. #ifdef    AX25
  1813.     case AF_AX25:
  1814.         if(strlen(sp.ax->iface) != 0)
  1815.             sprintf(buf,"ax25:%s",sp.ax->iface);
  1816.         else
  1817.             strcpy(buf,"ax25");
  1818.         break;
  1819. #endif
  1820. #ifdef    NETROM
  1821.     case AF_NETROM:
  1822.     if ((np = find_nrroute(sp.nr->nr_addr.node)) != NULLNRRTAB)
  1823.         strcpy(buf,np->alias);
  1824.     else
  1825.         pax25(buf,sp.nr->nr_addr.node);
  1826.         break;
  1827. #endif
  1828.     default:
  1829.         strcpy(buf,"?");
  1830.         break;
  1831.     }
  1832.     return buf;
  1833. }
  1834. #endif
  1835.  
  1836.  
  1837.  
  1838. /* Print a user display, return the number of characters sent */
  1839. int ShowConfUsers(int s,int quick,char *name) {
  1840.     int num,channel,l;
  1841.     struct convection *p;
  1842. #ifdef MAILBOX
  1843.     struct mbx *m;
  1844. #endif
  1845.     char buffer[LINELEN];
  1846. #ifdef CHANNELNAMES
  1847.     char *channame;
  1848. #endif
  1849.  
  1850.     if(quick) {
  1851.         num = usputscnt(s,"Channel ");
  1852. #ifdef CHANNELNAMES
  1853.         num += usputscnt(s,"          ");
  1854. #endif /* CHANNELNAMES */
  1855.         num += usputscnt(s,"Users\n");
  1856.         clear_locks();
  1857.         do {
  1858.             channel = -1;
  1859.             for(p = convections; p; p = p->next) {
  1860.                 if(p->type == CT_USER &&
  1861.                     !p->locked &&
  1862.                 (channel < 0 || channel == p->channel)) {
  1863.                     if(channel < 0) {
  1864.                         channel = p->channel;
  1865. #ifdef CHANNELNAMES
  1866.                         if ((channame=channame_of(channel))!=NULLCHAR) {
  1867.                             sprintf(buffer,"%7d(%s)         ",channel,channame);
  1868.                             buffer[17] = '\0';
  1869.                         } else
  1870.                             sprintf(buffer,"%7d          ", channel);
  1871. #else
  1872.                         sprintf(buffer,"%7d",channel);
  1873. #endif
  1874.                     }
  1875.                     strcat(buffer," ");
  1876.                     strcat(buffer,p->name);
  1877.                     p->locked = 1;
  1878.                 }
  1879.             }
  1880.             if(channel >= 0) {
  1881.                 num += usputscnt(s,buffer);
  1882.                 num += usputscnt(s,"\n");
  1883.             }
  1884.         } while(channel >= 0);
  1885.     } else {
  1886.         num = usputscnt(s,
  1887. #ifdef CHANNELNAMES
  1888.         "User       Host       Via      Channel Name       Time Personal\n");
  1889. #else
  1890.         "User       Host       Via        Channel Time Personal\n");
  1891. #endif
  1892.         for(p = convections; p; p = p->next) {
  1893.             if(p->type == CT_USER) {
  1894.                 if(name == NULL || *name == '\0' || !stricmp(p->name,name)) {
  1895.                     num += usprintf(s,"%-10s %-10s ",p->name,p->host);
  1896.  
  1897.                     if (p->via)
  1898.                         num += usprintf(s, "%-10s ", p->via->name);
  1899.                     else {
  1900. #ifdef ENHANCED_VIA
  1901.                         l = LINELEN;
  1902.                         if (getpeername(p->fd,buffer,&l)){
  1903.                             l = LINELEN;
  1904.                             getsockname(p->fd,buffer,&l);
  1905.                         }
  1906.                         num += usprintf(s, "%-10s ", pvia(buffer));
  1907. #else
  1908.                         num += usprintf(s, "%-10s ", "");
  1909. #endif
  1910.                     }
  1911.                     num += usprintf(s,
  1912. #ifdef CHANNELNAMES
  1913.                     "%5d %-8s %s %s\n",
  1914. #else    
  1915.                     "%5d %s %s\n",
  1916. #endif /* CHANNELNAMES */
  1917.                     p->channel,
  1918. #ifdef CHANNELNAMES
  1919.                     ((channame = channame_of(p->channel))!=0) ? channame : "",
  1920. #endif /* CHANNELNAMES */
  1921.                     timestring(p->time),
  1922.                     p->data ? p->data : "" );
  1923.                 }
  1924.             }
  1925.         }
  1926.     }
  1927. #ifdef MAILBOX
  1928.     if (name == NULL || *name == '\0') {
  1929.         for(m=Mbox;m;m=m->next) {
  1930.             if(m->state == MBX_CMD) {
  1931.                 if(quick)
  1932.                     num += usprintf(s," BBS %s\n",m->name);
  1933.                 else
  1934.                     num += usprintf(s,"%-10s BBS@%s\n",m->name,Hostname);
  1935.             }
  1936.         }
  1937.     }
  1938. #endif
  1939.     num += usputscnt(s,"***\n");
  1940.     return num;
  1941. }
  1942.  
  1943. static void
  1944. who_command(cp)
  1945. struct convection *cp;
  1946. {
  1947.     char buffer[LINELEN];
  1948.     int quick = 0;
  1949.     time_t curtime;
  1950.  
  1951.     curtime = time(NULL);
  1952.     cp->xmitted += usprintf(cp->fd,"*** %s", ctime(&curtime));
  1953.  
  1954.     buffer[0] = '\0';
  1955.     sscanf(cp->ibuf,"%*s %s",buffer);
  1956.     if(buffer[0] == 'q')
  1957.         quick = 1;
  1958.     cp->xmitted += ShowConfUsers(cp->fd,quick,buffer);
  1959.     return;
  1960. }
  1961.  
  1962. static void
  1963. h_cmsg_command(cp)
  1964. struct convection *cp;
  1965. {
  1966.     char *text;
  1967.     int  channel;
  1968.     char name[LINELEN],dummy[40];
  1969.  
  1970.     sscanf(cp->ibuf,"%s %10s %d",dummy,name,&channel);
  1971.     text = &cp->ibuf[0];
  1972.     text += strlen(dummy) + strlen(name) + 2;
  1973.     while(isspace(*text) == 0)
  1974.         text++;
  1975.     text++;
  1976.     if(isprint(*text) != 0)
  1977.         send_msg_to_channel(name,channel,text);
  1978.     return;
  1979. }
  1980.  
  1981. /* Return 1 if the host is to be allowed, or 0 if refused - WG7J */
  1982. int Allow_host(int s) {
  1983.     struct filter_link *fl;
  1984.     struct sockaddr_in fsocket;
  1985.     int i = sizeof(struct sockaddr_in);
  1986.  
  1987.     if(Filterlinks) {    /* Check for this ip address */
  1988.         getpeername(s,(char *)&fsocket,&i);
  1989.         for(fl=Filterlinks;fl;fl=fl->next)
  1990.             if(fl->addr == fsocket.sin_addr.s_addr)
  1991.                 return FilterMode;
  1992.         /* Not found ! */
  1993.         return !FilterMode;
  1994.     }
  1995.     return 1;
  1996. }
  1997.  
  1998. static void
  1999. h_host_command(cp)
  2000. struct convection *cp;
  2001. {
  2002.  
  2003.     char name[NAMELEN+1];
  2004.     struct convection *p;
  2005.     struct permlink *pp;
  2006.  
  2007.     if(!Allow_host(cp->fd)) {
  2008.         bye_command(cp);
  2009.         return;
  2010.     }
  2011.     name[0] = '\0';
  2012.     sscanf(cp->ibuf,"%*s %10s",name);
  2013.     if(name[0] == '\0') {
  2014.         bye_command(cp);
  2015.         return;
  2016.     }
  2017.     for(p = convections; p; p = p->next)
  2018.         if(!strcmp(p->name,name)) {
  2019.             bye_command(p);
  2020.             return;
  2021.         }
  2022.     for(pp = permlinks; pp; pp = pp->next)
  2023.         if(!strcmp(pp->name,name) && pp->convection && pp->convection != cp) {
  2024.             bye_command((strcmp(Chostname,name) < 0) ? pp->convection : cp);
  2025.             return;
  2026.         }
  2027. /*
  2028.     if(cp->type != CT_UNKNOWN)
  2029.         return;
  2030.  */
  2031.     cp->type = CT_HOST;
  2032.     cp->maxq = HMaxQ;
  2033.     strcpy(cp->name,name);      /* already allocated */
  2034.     update_permlinks(name,cp);
  2035. #ifdef LINK_CHANGE_MSG
  2036.     send_link_change_msg(cp,cp->name,"linked");
  2037. #endif
  2038.     cp->xmitted += usprintf(cp->fd,"/\377\200HOST %s\n",Chostname);
  2039.     for(p = convections; p; p = p->next)
  2040.         if(p->type == CT_USER) {
  2041.             cp->xmitted += usprintf(cp->fd,
  2042.             "/\377\200USER %s %s %d %d %d\n",
  2043.             p->name,p->host,0,-1,p->channel);
  2044.             if(p->data)
  2045.                 cp->xmitted += usprintf(cp->fd,
  2046.                 "/\377\200UDAT %s %s %s\n",
  2047.                 p->name,p->host,p->data);
  2048.         }
  2049.     ConvHosts++;
  2050.     return;
  2051. }
  2052.  
  2053. static void
  2054. h_invi_command(cp)
  2055. struct convection *cp;
  2056. {
  2057.     char fromname[NAMELEN+1],toname[NAMELEN+1];
  2058.     int  channel;
  2059.  
  2060.     sscanf(cp->ibuf,"%*s %10s %10s %d",fromname,toname,&channel);
  2061.     send_invite_msg(fromname,toname,channel);
  2062.     return;
  2063. }
  2064.  
  2065. static void
  2066. h_loop_command(cp)
  2067. struct convection *cp;
  2068. {
  2069.     char host[NAMELEN+1];
  2070.  
  2071.     sscanf(cp->ibuf,"%*s %10s",host);
  2072.     log(cp->fd, "conversd rx: LOOP %s",host);
  2073.     bye_command(cp);
  2074. }
  2075.  
  2076. /* Command to take user's personal data across a link - WG7J */
  2077. void
  2078. h_udat_command(cp)
  2079. struct convection *cp;
  2080. {
  2081.     char *name,*host,*data;
  2082.     int len;
  2083.     struct convection *p;
  2084.  
  2085.     /* do a validity check first */
  2086.     if((name = strchr(cp->ibuf,' ')) == NULLCHAR)
  2087.         return;
  2088.     name++;
  2089.     if((host = strchr(name,' ')) == NULLCHAR)
  2090.         return;
  2091.     *host++ = '\0';
  2092.     if((data = strchr(host,' ')) == NULLCHAR)
  2093.         return;
  2094.     *data++ = '\0';
  2095.     rip(data);      /* rip the '\n' */
  2096.     if((len=strlen(data)) == 0)
  2097.         return;
  2098.     if(len > PERSONAL_LEN)
  2099.         *(data+PERSONAL_LEN) = '\0';
  2100.  
  2101.     /* everything seems fine, now find user ! */
  2102.     for(p=convections;p;p=p->next) {
  2103.         if(!strcmp(p->name,name) && !strcmp(p->host,host)) {
  2104.             free(p->data);
  2105.             p->data = strdup(data);
  2106.         }
  2107.         /* update over other links  Apr 12/93 VE3DTE */
  2108.         if(p->type == CT_HOST && !p->locked)
  2109.             p->xmitted += usprintf(p->fd,"/\377\200UDAT %s %s %s\n",
  2110.             name,host,data);
  2111.     }
  2112. }
  2113.  
  2114. static void
  2115. h_umsg_command(cp)
  2116. struct convection *cp;
  2117. {
  2118.     char dummy[NAMELEN+1],fromname[NAMELEN+1],toname[NAMELEN+1],*text;
  2119.  
  2120.     sscanf(cp->ibuf,"%s %10s %10s",dummy,fromname,toname);
  2121.     text = &cp->ibuf[0];
  2122.     text += strlen(dummy) + strlen(fromname) + strlen(toname) + 3;
  2123.     if(*text)
  2124.         send_msg_to_user(fromname,toname,text);
  2125.     return;
  2126. }
  2127.  
  2128. static void
  2129. h_user_command(cp)
  2130. struct convection *cp;
  2131. {
  2132.     char host[3*NAMELEN+1],name[3*NAMELEN+1];
  2133.     int  newchannel,oldchannel;
  2134.     struct convection *p;
  2135.     time_t currtime;
  2136.  
  2137.     currtime = time(&currtime);
  2138.  
  2139.     sscanf(cp->ibuf,"%*s %s %s %*s %d %d",name,host,&oldchannel,&newchannel);
  2140.     /* Make sure the fields are not longer */
  2141.     host[NAMELEN] = name[NAMELEN] = '\0';
  2142.  
  2143.     for(p = convections; p; p = p->next)
  2144.         if(p->type == CT_USER) {
  2145.             /* new 920705 dl9sau */
  2146.             /* If Neighbour2 registers a user on HostX, while someone has already
  2147.              * been registered for HostX via Neighbour1, then we definitely have
  2148.              * a loop !  We send a loop detect message and then close the link:
  2149.              * /..LOOP <Chostname> <myneighbour> <host>
  2150.              *
  2151.              * The LOOP PREVENTION CODE detects ONLY a loop if it starts at this
  2152.              * host. That's, why I suggest this code to be implemented in every
  2153.              * conversd implementation.
  2154.              */
  2155.             if (oldchannel < 0 && p->via != cp && !stricmp(p->host, host)) {
  2156.                 usprintf(cp->fd,"/\377\200LOOP %s %s %s\n", \
  2157.                 Chostname, host,p->via ? p->via->name : Chostname);
  2158.                 log(cp->fd, "conversd sent: LOOP %s",host);
  2159.                 bye_command(cp);
  2160.                 return;
  2161.             }
  2162.             if(p->channel == oldchannel && p->via == cp && \
  2163.                 !strcmp(p->name,name) && !strcmp(p->host,host))
  2164.                 break;
  2165.         }
  2166.     if(!p) {
  2167.         p = (struct convection *)callocw(1,sizeof(struct convection ));
  2168.         p->type = CT_USER;
  2169.         strcpy(p->name,name);
  2170.         strcpy(p->host,host);
  2171.         p->via = cp;
  2172.         p->channel = oldchannel;
  2173.         p->time = currtime;
  2174.         p->next = convections;
  2175.         convections = p;
  2176.     }
  2177.     if((p->channel = newchannel) < 0) {
  2178.         p->type = CT_CLOSED;
  2179.         free_closed_connections();  /*  VE3DTE Apr 5/93 */
  2180.     }
  2181.     send_user_change_msg(name,host,oldchannel,newchannel);
  2182.     return;
  2183. }
  2184.  
  2185. struct cmdtable {
  2186.     char  *name;
  2187.     void (*fnc)(struct convection *);
  2188.     int  states;
  2189. };
  2190. struct cmdtable DFAR cmdtable[] = {
  2191.     "?",        help_command,       CM_USER,
  2192.     "bye",      bye_command,        CM_USER,
  2193.     "channel",  channel_command,    CM_USER,
  2194.     "exit",     bye_command,        CM_USER,
  2195.     "help",     help_command,       CM_USER,
  2196.     "invite",   invite_command,     CM_USER,
  2197.     "links",    links_command,      CM_USER,
  2198.     "msg",      msg_command,        CM_USER,
  2199.     "name",     name_command,       CM_UNKNOWN,
  2200.     "personal", personal_command,   CM_USER,
  2201.     "quit",     bye_command,        CM_USER,
  2202.     "sounds",   sounds_command,     CM_USER,
  2203.     "version",  version_command,    CM_USER,
  2204.     "who",      who_command,        CM_USER,
  2205.     "write",    msg_command,        CM_USER,
  2206.  
  2207.     "\377\200cmsg", h_cmsg_command,     CM_HOST,
  2208.     "\377\200host", h_host_command,     CM_UNKNOWN,
  2209.     "\377\200invi", h_invi_command,     CM_HOST,
  2210.     "\377\200loop", h_loop_command,     CM_HOST,
  2211.     "\377\200udat", h_udat_command,     CM_HOST,
  2212.     "\377\200umsg", h_umsg_command,     CM_HOST,
  2213.     "\377\200user", h_user_command,     CM_HOST,
  2214.     0,      0,          0,
  2215. };
  2216.  
  2217. static void
  2218. process_commands(cp,m)
  2219. struct convection *cp;
  2220. struct mbx *m;
  2221. {
  2222.     char arg[LINELEN];
  2223.     int arglen,size;
  2224.     char *ccp;
  2225.     struct cmdtable *cmdp;
  2226.  
  2227.     for(;;) {
  2228.         loop:
  2229.         if(cp->type == CT_CLOSED)
  2230.             break;
  2231.         setflush(cp->fd,'\n');
  2232.         usflush(cp->fd);
  2233.         memset(cp->ibuf,0,LINELEN);
  2234.         if(cp->type != CT_HOST)
  2235.             alarm(Ctdiscinit * 1000L);
  2236.         if((size = recvline(cp->fd,cp->ibuf,LINELEN-1)) <= 0)
  2237.             break;
  2238.         alarm(0L);
  2239.         cp->received += size;
  2240.         clear_locks();
  2241.         cp->locked = 1;
  2242.         if(*cp->ibuf == '/') {
  2243.             ccp = &cp->ibuf[1];
  2244.             arg[0] = '\0';
  2245.             sscanf(ccp,"%s",arg);
  2246.             arglen = strlen(arg);
  2247.             /* We are about to parse a command; most likely there
  2248.              * is alot of output; try to avoid fragmenting that
  2249.              * data by doing our own flushing ! - WG7J
  2250.              */
  2251.             setflush(cp->fd,-1);
  2252.             for(cmdp = cmdtable; cmdp->name; cmdp++) {
  2253.                 if(!strncmpi(cmdp->name,arg,arglen)) {
  2254.                     if(cmdp->states & (1 << cp->type))
  2255.                         (*cmdp->fnc)(cp);
  2256.                     goto loop;
  2257.                 }
  2258.             }
  2259.             if(cp->type == CT_USER)
  2260.                 cp->xmitted += usprintf(cp->fd,
  2261.                 "*** Unknown command '/%s'. Type /HELP for help.\n",arg);
  2262.             goto loop;
  2263.         }
  2264.         if((ccp = strpbrk(cp->ibuf,"\r\n")) != NULLCHAR)
  2265.             *ccp = '\0';
  2266.         if(isprint(cp->ibuf[0]) != 0 && cp->type == CT_USER)
  2267.             send_msg_to_channel(cp->name,cp->channel,cp->ibuf);
  2268.     }
  2269.     bye_command(cp);
  2270.     sockblock(cp->fd,SOCK_BLOCK);
  2271.     free_closed_connections();
  2272. }
  2273.  
  2274. /* Incoming convers session */
  2275. void
  2276. conv_incom(s,t,p)
  2277. int s;
  2278. void *t;
  2279. void *p;
  2280. {
  2281.     struct convection *cp;
  2282.  
  2283.     sockowner(s,Curproc);   /* We own it now */
  2284.     sockmode(s,SOCK_BINARY);
  2285.     sockblock(s,SOCK_NOTXBLOCK);   /* prevent backlogs ! */
  2286.     cp = alloc_connection(s);
  2287.     conv_incom2(s,t,p,cp);
  2288. }
  2289.  
  2290. #ifdef XCONVERS
  2291. /* Incoming LZW convers session */
  2292. void
  2293. xconv_incom(s,t,p)
  2294. int s;
  2295. void *t;
  2296. void *p;
  2297. {
  2298.     struct convection *cp;
  2299.  
  2300.     sockowner(s,Curproc);    /* We own it now */
  2301.     sockmode(s,SOCK_BINARY);
  2302.     sockblock(s,SOCK_NOTXBLOCK);   /* prevent backlogs ! */
  2303.     cp = alloc_connection(s);
  2304.     lzwinit(s,Lzwbits,Lzwmode);
  2305.     cp->flags |= USE_LZW;
  2306.     conv_incom2(s,t,p,cp);
  2307. }
  2308. #endif
  2309.  
  2310. static void
  2311. conv_incom2(s,t,p,cp)
  2312. int s;
  2313. void *t;
  2314. void *p;
  2315. struct convection *cp;
  2316. {
  2317.     struct permlink *pl;
  2318.  
  2319.     cp->channel = CDefaultChannel;
  2320.  
  2321.     for(pl = permlinks; pl; pl = pl->next)
  2322.         if(pl->fd == s) {
  2323.             pl->convection = cp;
  2324.             cp->xmitted += usprintf(s,"/\377\200HOST %s\n",Chostname);
  2325.         }
  2326.  
  2327.     if(pl == NULLPERMLINK) {
  2328. #ifdef AX25
  2329.         if((int)t == AX25TNC) { /* figure out call from socket */
  2330.             struct usock *up;
  2331.             char *chrp;
  2332.  
  2333.             if((up = itop(s)) == NULLUSOCK) {
  2334.                 free_connection(cp);
  2335.                 return;
  2336.             }
  2337.             sockmode(s,SOCK_ASCII);
  2338.             pax25(cp->name,up->cb.ax25->remote);
  2339.             if((chrp=strchr(cp->name,'-')) != NULL)
  2340.                 *chrp = '\0';
  2341.             strlwr(cp->name);
  2342.             strcpy(cp->host,Chostname);
  2343.             cp->type = CT_USER;
  2344.             cp->xmitted += usprintf(s,
  2345.             "Conference @ %s  Type /HELP for help.\n",Chostname);
  2346.             SendMotd(s);
  2347.             clear_locks();
  2348.             cp->locked = 1; /* send to everyone but ourself */
  2349.             send_user_change_msg(cp->name,cp->host,-1,CDefaultChannel);
  2350.             set_personal(cp);
  2351.             ConvUsers++;
  2352.         } else
  2353. #endif
  2354.             usputscnt(cp->fd,"\nPlease login with '/n <call> [channel #]'\n\n");
  2355.     }
  2356.     process_commands(cp,NULLMBX);
  2357. }
  2358.  
  2359. #ifdef MAILBOX
  2360.  
  2361. /* this is for Mailbox users */
  2362. void
  2363. mbox_converse(struct mbx *m,int channel)
  2364. {
  2365.     struct convection *cp;
  2366.     int oldflush;
  2367.  
  2368.     sockblock(m->user,SOCK_NOTXBLOCK);  /* prevent backlogs ! */
  2369.     oldflush = setflush(m->user,'\n');  /* automatic line flushing */
  2370.     cp = alloc_connection(m->user);
  2371.     cp->channel = channel;
  2372.     strcpy(cp->name,m->name);
  2373.     strcpy(cp->host,Chostname);
  2374.     cp->type = CT_USER;
  2375.     cp->flags &= ~CLOSE_SOCK;     /* do not close socket on exit */
  2376.     cp->xmitted += usprintf(m->user,
  2377.     "Conference @ %s  Type /HELP for help.\n",Chostname);
  2378.     SendMotd(m->user);
  2379.     clear_locks();
  2380.     cp->locked = 1; /* send to everyone but ourself */
  2381.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  2382.     set_personal(cp);
  2383.     ConvUsers++;
  2384.  
  2385. #ifdef LOCAL_CHANNELS
  2386.     if (ISLOCAL(cp->channel))
  2387.         cp->xmitted += usputscnt(cp->fd,clocal);
  2388.     if (ISMESSAGE(cp->channel))
  2389.         cp->xmitted += usputscnt(cp->fd,cmessage);
  2390. #endif
  2391.     process_commands(cp,m);
  2392.  
  2393.     setflush(m->user,oldflush);
  2394.  
  2395. }
  2396. #endif /* MAILBOX */
  2397.  
  2398. #endif /* CONVERS */
  2399.  
  2400.  
  2401.  
  2402.  
  2403.  
  2404.