home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / MBOXGATE.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  18KB  |  670 lines

  1. /* The are the GATECMDS functions */
  2. #include <time.h>
  3. #include <ctype.h>
  4. #ifdef MSDOS
  5. #include <alloc.h>
  6. #endif
  7. #ifdef  UNIX
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #endif
  11. #include "global.h"
  12. #include "timer.h"
  13. #include "proc.h"
  14. #include "socket.h"
  15. #include "usock.h"
  16. #include "session.h"
  17. #include "smtp.h"
  18. #include "dirutil.h"
  19. #include "telnet.h"
  20. #include "ftp.h"
  21. #include "ftpserv.h"
  22. #include "commands.h"
  23. #include "netuser.h"
  24. #include "files.h"
  25. #include "bm.h"
  26. #include "pktdrvr.h"
  27. #include "ax25.h"
  28. #include "mailbox.h"
  29. #include "ax25mail.h"
  30. #include "nr4mail.h"
  31. #include "cmdparse.h"
  32. #include "mailfor.h"
  33.   
  34. /* The dombtelnet(), gw_* functions need to be there if FOQ_CMDS defined
  35.  * they are used by dochat() (Operator), and dombfinger commands - WG7J
  36.  */
  37.   
  38. #if defined GATECMDS || defined FOQ_CMDS
  39.   
  40. int
  41. dombtelnet(argc,argv,p)
  42. int argc;
  43. char *argv[];
  44. void *p;
  45. {
  46.     struct mbx *m;
  47.     int s, len, i;
  48.     char dsocket[MAXSOCKSIZE];
  49.     struct sockaddr_in fsocket;
  50.   
  51.     m = (struct mbx *) p;
  52.     fsocket.sin_family = AF_INET;
  53.     if(argc < 3)
  54.         fsocket.sin_port = IPPORT_TELNET;
  55.     else
  56.         fsocket.sin_port = atoip(argv[2]);
  57.   
  58.     if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  59.         tprintf(Badhost,argv[1]);
  60.         /* Free m->startmsg if set ! - WG7J */
  61.         if(m->startmsg != NULLCHAR) {
  62.             free(m->startmsg);
  63.             m->startmsg = NULLCHAR;
  64.         }
  65.         return 0;
  66.     }
  67.     /* Only local telnets to the ttylink port are are allowed
  68.      * to the unprivileged user
  69.      * If the first letter of the command is 'Q', then it was
  70.      * the QUERY command !
  71.      */
  72.     if(*argv[0] != 'Q') {
  73.         if( !(m->privs & TELNET_CMD) &&
  74.             !(ismyaddr(fsocket.sin_addr.s_addr) &&
  75.         fsocket.sin_port == IPPORT_TTYLINK) ){
  76.             tputs(Noperm);
  77. #ifdef MAILERROR
  78.             mail_error("%s: Telnet denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
  79. #endif
  80.             /* Free m->starmsg if set ! - WG7J */
  81.             /* Shouldn't happen here, but just in case */
  82.             if(m->startmsg != NULLCHAR) {
  83.                 free(m->startmsg);
  84.                 m->startmsg = NULLCHAR;
  85.             }
  86.             return 0;
  87.         }
  88.     }
  89.     /* See if we have a route to this address */
  90.     if(rt_lookup(fsocket.sin_addr.s_addr) == NULL &&
  91.     !ismyaddr(fsocket.sin_addr.s_addr)) {
  92.         tprintf("No route to %s!\n",psocket(&fsocket));
  93.         return 0;
  94.     }
  95.     if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  96.         tputs(Nosock);
  97.         /* Free m->starmsg if set ! - WG7J */
  98.         if(m->startmsg != NULLCHAR) {
  99.             free(m->startmsg);
  100.             m->startmsg = NULLCHAR;
  101.         }
  102.         return 0;
  103.     }
  104. #ifdef GWTRACE
  105.     log(m->user,"MBOX TELNET: %s to %s:%d",m->name,argv[1],fsocket.sin_port);
  106. #endif
  107.     if(fsocket.sin_port == IPPORT_TTYLINK) {
  108.         m->startmsg = mallocw(80);
  109.         len = MAXSOCKSIZE;
  110.         i = getpeername(m->user,dsocket,&len);
  111.         sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
  112.         m->name,i != -1 ? psocket(dsocket): Hostname);
  113.     }
  114.     m->state = MBX_GATEWAY;
  115.     return gw_connect(m,s,(struct sockaddr *)&fsocket,SOCKSIZE);
  116. }
  117.   
  118. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  119.  * when the connection has been established unless it a null pointer.
  120.  */
  121. int
  122. gw_connect(m,s,fsocket,len)
  123. struct mbx *m;
  124. int s;
  125. struct sockaddr *fsocket;
  126. int len;
  127. {
  128.     int c,timeout;
  129.     char *cp, *cp1;
  130.     struct proc *child;
  131.     struct gwalarm *gwa;
  132.     char *node, *tocall, whereto[128], buf[80];
  133.     char temp[AXBUF];
  134.     struct nrroute_tab *rp;
  135.   
  136.     sockmode(s,SOCK_ASCII);
  137.     child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
  138.     tputs("Trying...");
  139.     if(m->privs & NO_ESCAPE)
  140.         tputc('\n');
  141.     else {
  142.         tputs("  The escape character is: ");
  143.         if(m->escape < 32)
  144.             tprintf("CTRL-%c\n",m->escape+'A'-1);
  145.         else
  146.             tprintf("'%c'\n",m->escape);
  147.     }
  148.     usflush(Curproc->output);
  149.   
  150.     /*find out where we're going to*/
  151.     tocall = strdup(psocket(fsocket));
  152.     if((cp1 = strchr(tocall,' ')) != NULLCHAR)
  153.         *cp1 = '\0';
  154. #if defined GATECMDS && defined NETROM
  155.     if(fsocket->sa_family == AF_NETROM) {
  156.         /*find the node alias*/
  157.         setcall(temp,tocall);
  158.         rp = find_nrroute(temp);
  159.         node = strdup(rp->alias);
  160.         if((cp1 = strchr(node,' ')) != NULLCHAR)
  161.             *cp1 = '\0';
  162.         sprintf(whereto,"%s:%s",node,tocall);
  163.         free(node);
  164.     } else
  165. #endif
  166.         strcpy(whereto,tocall);
  167.     free(tocall);
  168.   
  169.     if(connect(s,(char *)fsocket,len) == -1){
  170.         if((cp = sockerr(s)) != NULLCHAR) {
  171.             switch(cp[0]) {
  172.                 case 'R':
  173.                     sprintf(buf,"%susy from",
  174.                     (m->family == AF_NETROM)?"B":"*** b");
  175.                     break;
  176.                 case 'T':
  177.                     if(m->family != AF_NETROM) {
  178.                         sprintf(buf,"*** timeout with");
  179.                         break;
  180.                     }
  181.                 default:
  182.                     sprintf(buf,"%sailure with",
  183.                     (m->family == AF_NETROM)?"F":"*** f");
  184.                     break;
  185.             }
  186.             tprintf("%s%s %s\n\n",
  187.             (m->family == AF_NETROM) ? Mbnrid : "",buf,whereto);
  188.         }
  189.         shutdown(s,2);  /* HB9RWM suggestion */
  190.         close_s(s);
  191.         killproc(child);
  192.         /* Free m->starmsg if set ! - WG7J */
  193.         if(m->startmsg != NULLCHAR) {
  194.             free(m->startmsg);
  195.             m->startmsg = NULLCHAR;
  196.         }
  197.         return 0;
  198.     }
  199.     /* The user did not type the escape character */
  200.     killproc(child);
  201.   
  202.     tprintf("%s%sonnected to %s\n",
  203.     (m->family == AF_NETROM) ? Mbnrid : "",
  204.     (m->family == AF_NETROM) ? "C" : "*** c",
  205.     whereto);
  206.   
  207.     if(m->startmsg != NULLCHAR){
  208.         usputs(s,m->startmsg);
  209.         free(m->startmsg);
  210.         m->startmsg = NULLCHAR;
  211.     }
  212.   
  213.     /* Since NOS does not flush the output socket after a certain
  214.      * period of time, we have to arrange that ourselves.
  215.      */
  216.     gwa = (struct gwalarm *) mallocw(sizeof(struct gwalarm));
  217.     gwa->s1 = Curproc->output;
  218.     gwa->s2 = s;
  219.     set_timer(&gwa->t,2*1000L);
  220.     gwa->t.func = gw_alarm;
  221.     gwa->t.arg = (void *) gwa;
  222.     start_timer(&gwa->t);
  223.     /* Fork off the receive process */
  224.     child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
  225.   
  226.     timeout = 0;
  227.     for(;;){
  228.         alarm(Mbtdiscinit*1000L);
  229.         if((c = recvchar(Curproc->input)) == EOF) {
  230.             timeout = (errno == EALARM);
  231.             break;
  232.         }
  233.         alarm(0L);
  234.         /* Only check ESCAPE char if that is currently turned on */
  235.         if( !(m->privs & NO_ESCAPE) && c == m->escape){
  236.             if(socklen(Curproc->input,0))
  237.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  238.             break;
  239.         }
  240.         if(usputc(s,c) == EOF)
  241.             break;
  242.     }
  243.     stop_timer(&gwa->t);
  244.     free((char *)gwa);
  245.     close_s(s);
  246.     killproc(child); /* get rid of the receive process */
  247.     if(m->family == AF_INET)
  248.         tprintf("%c%c%c\n",IAC,WONT,TN_ECHO);
  249.     if(timeout)
  250.         return EOF;
  251.     return 0;
  252. }
  253.   
  254. void
  255. gw_input(s,notused,p)
  256. int s;
  257. void *notused;
  258. void *p;
  259. {
  260.     int c;
  261.     struct proc *parent;
  262.     struct mbx *m;
  263.     char *cp, *cp1;
  264.     char response[4];
  265.   
  266.     parent = (struct proc *) p;
  267.     m = (struct mbx *) notused;
  268.   
  269.     cp1 = strdup(Mbnrid);
  270.     if((cp = strchr(cp1,'}')) != NULLCHAR)
  271.         *cp = '\0';
  272.     strupr(cp1);
  273.   
  274. #ifdef notdef
  275.     while((c = recvchar(s)) != EOF)
  276.         tputc(c);
  277. #endif
  278.     while((c = recvchar(s)) != EOF){
  279.         if(c != IAC){
  280.             tputc((char)c);
  281.             continue;
  282.         }
  283.         /* IAC received, get command sequence */
  284.         c = recvchar(s);
  285.         switch(c){
  286.             case WILL:
  287.                 response[0] = IAC;
  288.                 response[1] = DONT;
  289.                 response[2] = recvchar(s);
  290.                 response[3] = '\0';
  291.                 usputs(s,response);
  292.                 break;
  293.             case WONT:
  294.             case DONT:
  295.                 c = recvchar(s);
  296.                 break;
  297.             case DO:
  298.                     response[0] = IAC;
  299.                     response[1] = WONT;
  300.                     response[2] = recvchar(s);
  301.                     response[3] = '\0';
  302.                     usputs(s,response);
  303.                     break;
  304.             case IAC:       /* Escaped IAC */
  305.                 usputc(s,IAC);
  306.                 break;
  307.         }
  308.     }
  309.   
  310.     if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
  311.         switch(cp[0]) {
  312.             case 'T':
  313.                 usprintf(m->user,"\n*** %s: Link failure",cp1);
  314.                 break;
  315.             case 'R':
  316.                 usputs(m->user,"*** DM received");
  317.                 break;
  318.         }
  319.     }
  320.     usprintf(m->user,"\n%s%seconnected to %s\n\n",
  321.     (m->family == AF_NETROM) ? Mbnrid : "",
  322.     (m->family == AF_NETROM) ? "R" : "*** r",
  323.     cp1);
  324.   
  325.     free(cp1);
  326.     cp1 = NULLCHAR;
  327.   
  328.     /* Tell the parent that we are no longer connected */
  329.     alert(parent,ENOTCONN);
  330.     pwait(Curproc); /* Now wait to be killed */
  331. }
  332.   
  333. /* Check if the escape character is typed while the parent process is busy
  334.  * doing other things.
  335.  */
  336. void
  337. gw_superv(null,proc,p)
  338. int null;
  339. void *proc;
  340. void *p;
  341. {
  342.     struct proc *parent;
  343.     struct mbx *m;
  344.     int c;
  345.     parent = (struct proc *) proc;
  346.     m = (struct mbx *) p;
  347.     while((c = recvchar(Curproc->input)) != EOF)
  348.         if(c == m->escape){
  349.             /* flush anything in the input queue */
  350.             if(socklen(Curproc->input,0))
  351.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  352.             break;
  353.         }
  354.     alert(parent,EINTR);     /* Tell the parent to quit */
  355.     pwait(Curproc);          /* Please kill me */
  356. }
  357.   
  358. void
  359. gw_alarm(p)
  360. void *p;
  361. {
  362.     struct gwalarm *gwa = (struct gwalarm *)p;
  363.     char oldbl;
  364.     struct usock *up;
  365.   
  366.     /* Flush sockets s1 and s2, but first make sure that the socket
  367.      * is set to non-blocking mode, to prevent the flush from blocking
  368.      * if the high water mark has been reached.
  369.      */
  370.     if((up = itop(gwa->s1)) != NULLUSOCK) {
  371.         oldbl = up->noblock;
  372.         up->noblock = 1;
  373.         usflush(gwa->s1);
  374.         up->noblock = oldbl;
  375.     }
  376.     if((up = itop(gwa->s2)) != NULLUSOCK) {
  377.         oldbl = up->noblock;
  378.         up->noblock = 1;
  379.         usflush(gwa->s2);
  380.         up->noblock = oldbl;
  381.     }
  382.     start_timer(&gwa->t);
  383. }
  384. #endif /* GATECMDS || FOQ_CMDS */
  385.   
  386. #ifdef GATECMDS
  387.   
  388. /*Enlighten them a bit!
  389.  */
  390. static char Mbconnecthelp[] =
  391. "Syntax:\n"
  392. #ifdef NETROM
  393. "'C <node>'        for NET/ROM connects\n"
  394. #endif
  395. #ifdef AX25
  396. "'C <port> <call>' for AX.25 connects\n"
  397. #endif
  398. #ifdef CONVERS
  399. "'CONV [channel]'  to access conference bridge\n"
  400. #endif
  401. "\n";
  402.   
  403. #ifdef NETROM
  404.   
  405. int
  406. dombnrneighbour(argc,argv,p)
  407. int argc;
  408. char *argv[];
  409. void *p;
  410. {
  411.     struct mbx *m;
  412.   
  413.     m = (struct mbx *)p;
  414.   
  415.     if(!(m->privs & NETROM_CMD)) {
  416.         tputs(Noperm);
  417.         return 0;
  418.     }
  419.     return donrneighbour(argc,argv,NULL);
  420. }
  421.   
  422. int
  423. dombnrnodes(argc,argv,p)
  424. int argc;
  425. char *argv[];
  426. void *p;
  427. {
  428.     struct mbx *m;
  429.   
  430.     m = (struct mbx *)p;
  431.   
  432.     if(!(m->privs & NETROM_CMD)) {
  433.         tputs(Noperm);
  434.         return 0;
  435.     }
  436.     if(argc < 2)
  437.         return doroutedump();
  438.     if(*argv[1] == '*')
  439.         argc = 1;
  440.     return dorouteinfo(argc,argv,p);
  441. }
  442. #endif /* NETROM */
  443.   
  444. int
  445. dombescape(argc,argv,p)
  446. int argc;
  447. char *argv[];
  448. void *p;
  449. {
  450.     struct mbx *m;
  451.   
  452.     m = (struct mbx *)p;
  453.     if(argc < 2){
  454.         tprintf("Escape is %s, Escape char: ",
  455.         (m->privs & NO_ESCAPE) ? "OFF" : "ON");
  456.         if(m->escape < 32)
  457.             tprintf("CTRL-%c\n",m->escape+'A'-1);
  458.         else
  459.             tprintf("'%c'\n",m->escape);
  460.         return 0;
  461.     }
  462.     if(strlen(argv[1]) > 1) {
  463.         if(isdigit(*argv[1]))
  464.             m->escape = (char) atoi(argv[1]);
  465.         else {
  466.             if( !strnicmp(argv[1],"OFF",3) || !strnicmp(argv[1],"dis",3) )
  467.                 m->privs |= NO_ESCAPE;
  468.             else
  469.                 m->privs &= ~NO_ESCAPE;
  470.         }
  471.     } else
  472.         m->escape = *argv[1];
  473.     return 0;
  474. }
  475.   
  476. int
  477. dombconnect(argc,argv,p)
  478. int argc;
  479. char *argv[];
  480. void *p;
  481. {
  482.     struct mbx *m;
  483.     struct nrroute_tab *np;
  484.     int ndigis,i,s;
  485.     struct sockaddr_nr lsocket,fsocket;
  486.     struct sockaddr_ax alsocket;    /*the local socket*/
  487.     struct sockaddr_ax afsocket;    /*the remote socket*/
  488.     struct iface *ifp;
  489.     char alias[AXBUF];
  490.     char local_call[AXALEN];
  491.     char digis[MAXDIGIS][AXALEN];
  492.     char target[AXALEN];
  493.   
  494.     m = (struct mbx *) p;
  495.   
  496.     if(argc == 1){
  497.         tputs(Mbconnecthelp);
  498.         return 0;
  499.     }
  500.     if(MBSecure)
  501. #ifdef NETROM
  502.         if((m->family != AF_AX25) && (m->family != AF_NETROM)) {
  503. #else
  504.             if(m->family != AF_AX25) {
  505. #endif
  506.                 tputs(Noperm);
  507. #ifdef MAILERROR
  508.                 mail_error("%s: gateway denied (secure mode): %s\n",m->name,cmd_line(argc,argv,m->stype));
  509. #endif
  510.                 return 0;
  511.             }
  512.   
  513.             if (argc == 2) {
  514. #ifndef NETROM
  515.                 tputs(Mbconnecthelp);
  516.                 return 0;
  517.             }
  518. #else
  519.     /*NETROM connection wanted*/
  520.             if(!(m->privs & NETROM_CMD)) {
  521.                 tputs(Noperm);
  522. #ifdef MAILERROR
  523.                 mail_error("%s: NETROM gate to %s denied\n",m->name,argv[1]);
  524. #endif
  525.                 return 0;
  526.             }
  527.   
  528.             if(Nr_iface == NULLIF){
  529.                 tputs("NET/ROM not activated.\n\n");
  530.                 return 0;
  531.             }
  532.     /* See if the requested destination is a known alias or call,
  533.      * use it if it is.  Otherwize give an error message.
  534.      */
  535.             putalias(alias,argv[1],0);
  536.             strupr(argv[1]);    /*make sure it's upper case*/
  537.             if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  538.         /*no such call or node alias*/
  539.                 tputs("no such node\n\n");
  540.                 tputs(Mbconnecthelp);
  541.                 dombports(0,NULL,p);
  542.                 return 0;
  543.             }
  544.   
  545.             if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  546.                 tputs(Nosock);
  547.                 return 0;
  548.             }
  549. #ifdef GWTRACE
  550.             log(m->user,"MBOX NETROM: %s to %s",m->name,argv[1]);
  551. #endif
  552.             lsocket.nr_family = AF_NETROM;
  553.   
  554.     /* Set up our local username, bind would use Mycall instead */
  555.             memcpy(lsocket.nr_addr.user,m->call,AXALEN);
  556.     /* Set up our source address */
  557.             memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  558.   
  559.             bind(s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  560.   
  561.             memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  562.             memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  563.             fsocket.nr_family = AF_NETROM;
  564.             m->state = MBX_GATEWAY;
  565.             return gw_connect(m,s,(struct sockaddr *)&fsocket, sizeof(struct sockaddr_nr));
  566.         }
  567. #endif /*NETROM*/
  568.   
  569. #ifdef AX25
  570.     if(argc > 2) {
  571.     /*AX25 gateway connection wanted*/
  572.         if(!(m->privs & AX25_CMD)) {
  573.             tputs(Noperm);
  574. #ifdef MAILERROR
  575.             mail_error("%s: AX.25 gate to %s on %s denied\n",m->name,argv[2],argv[1]);
  576. #endif
  577.             return 0;
  578.         }
  579.   
  580.         if( ((ifp = if_lookup(argv[1])) == NULLIF) ||
  581.             ((ifp->flags & HIDE_PORT) && !(m->privs & SYSOP_CMD)) ||
  582.         (ifp->type != CL_AX25) ) {
  583.             tprintf("Unknown port %s\n",argv[1]);
  584.             dombports(0,NULL,p);
  585.             return 0;
  586.         }
  587.         if(setcall(target,argv[2]) == -1){
  588.             tprintf("Bad call %s\n",argv[2]);
  589.             return 0;
  590.         }
  591.     /* If digipeaters are given, put them in the routing table */
  592.         if(argc > 3){
  593.             ndigis = argc - 3;
  594.             if(ndigis > MAXDIGIS){
  595.                 tputs("Too many digipeaters\n");
  596.                 return 0;
  597.             }
  598.             for(i=0;i<ndigis;i++){
  599.                 if(setcall(digis[i],argv[i+3]) == -1){
  600.                     tprintf("Bad digipeater %s\n",argv[i+3]);
  601.                     return 0;
  602.                 }
  603.             }
  604.             if(ax_add(target,AX_AUTO,digis,ndigis,ifp) == NULLAXR){
  605.                 tputs("AX25 route add failed\n");
  606.                 return 0;
  607.             }
  608.         }
  609.         if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  610.             tputs(Nosock);
  611.             return 0;
  612.         }
  613. #ifdef GWTRACE
  614.         log(m->user,"MBOX AX25: %s to %s on %s",m->name,argv[2],argv[1]);
  615. #endif
  616.   
  617.     /*fill in the known stuff*/
  618.         alsocket.sax_family = afsocket.sax_family= AF_AX25;
  619.   
  620.     /*the remote call to connect to*/
  621.         setcall(afsocket.ax25_addr,argv[2]);
  622.   
  623.     /*the outgoing interface*/
  624.         strncpy(afsocket.iface,argv[1],ILEN);
  625.   
  626.     /*now set local user call, invert ssid*/
  627.         memcpy(local_call,m->call,AXALEN);
  628.         local_call[AXALEN-1] ^= 0x1e;
  629.         memcpy(alsocket.ax25_addr,local_call,AXALEN);
  630.     /*and bind it (otherwize Mycall will be used!)*/
  631.         bind(s,(char *)&alsocket,sizeof(struct sockaddr_ax));
  632.         m->state = MBX_GATEWAY;
  633.         return gw_connect(m,s,(struct sockaddr *)&afsocket, sizeof(struct sockaddr_ax));
  634.     }
  635. #endif /* AX25 */
  636.   
  637.     return 0;
  638. }
  639.   
  640. #ifdef AX25
  641. int
  642. dombports(argc,argv,p)
  643. int argc;
  644. char *argv[];
  645. void *p;
  646. {
  647.     struct iface *ifp;
  648.     struct mbx *m = (struct mbx *)p;
  649.   
  650.     if(m->privs & NO_LISTS) {
  651.         tputs(Noperm);
  652.         return 0;
  653.     }
  654.     tputs("Available ports:\n");
  655.     for(ifp=Ifaces;ifp!=NULLIF;ifp=ifp->next)
  656.         if(ifp->type == CL_AX25 && \
  657.         (!(ifp->flags & HIDE_PORT) || (m->privs & SYSOP_CMD)) ) {
  658.             tprintf("%-7s",ifp->name);
  659.             if(ifp->descr != NULLCHAR)
  660.                 tprintf(":  %s",ifp->descr);
  661.             else
  662.                 tputc('\n');
  663.         }
  664.     tputc('\n');
  665.     return 0;
  666. }
  667. #endif /* AX25 */
  668.   
  669. #endif /* GATECMDS */
  670.