home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / KILLCO.ZIP / KILLCONN.C next >
C/C++ Source or Header  |  1991-04-09  |  22KB  |  704 lines

  1. /******************************   KILLCONN.C      ******************************
  2. **    
  3. ** KILLCONN is a program which selectively clears workstation connections
  4. **    to fileservers running under Netware versions 2.x and up. It has
  5. **    one mandatory command line parameter (an indication of who it is you want
  6. **    to kill) and a number of optional parameters.  The possible parameters
  7. **    are:
  8. **
  9. **        -help, -h, or /h: produces a help message.
  10. **        user=SOMEBODY   : kill connection for user SOMEBODY.
  11. **                               This parameter may contain Novell-type wildcards,
  12. **                                but I recommend using the group parameter instead,
  13. **                                since it keeps things cleaner administratively.
  14. **        group=SOMEGROUP : kill connections for all members of SOMEGROUP
  15. **        server=MYSERVE  : by default, KILLCONN will go after the named victims
  16. **                                on all the file servers it can find.  Specifying a
  17. **                                server will only break the victim's connection on
  18. **                                the named server.  Useful on internetworks when you
  19. **                                only want to kill one.
  20. **        confirm=YES|NO  : if confirm=YES is specified, KILLCONN will pause
  21. **                                and prompt you before disconnecting each user.
  22. **                      Default is NO; KILLCONN is intended for unattended
  23. **                                operation.
  24. **        log=filename    : writes a logfile of KILLCONN actions.  A full DOS path
  25. **                                can be specified.  If a file with the name 'filename'
  26. **                                exists, it will be overwritten.
  27. **        logadd=filename : same as log=, except that if the logfile exists,
  28. **                                KILLCONN will append to it.
  29. **
  30. **      Two new features added 4-9-91: RETRIES and WARNING
  31. **
  32. **        warning=nn         : gives user nn seconds warning before disconnecting
  33. **    retries=nn         : retries the disconnect nn times before giving up.
  34. **                                intended for slower networks.
  35. **
  36. **        ...and another thing: you may optionally create a group called
  37. **    IMMORTAL on any or all file servers; KILLCONN will ignore them.
  38. **        KILLCON also ignores any attempt to disconnect any station logged in
  39. **        with the same login_name as the station running KILLCONN.
  40. **
  41. */
  42. /**************************************************************************
  43.    Some technoid stuff (I imagine if you're reading this you're at least
  44.     a little bit interested):
  45.  
  46.     KILLCONN was built using BORLAND C/C++ 2.0, the TXCL interface library,
  47.     and of course the Netware API for C.  The TCXL library is cheap,
  48.     excellent, and highly recommended. If for some reason you're rebuilding
  49.     this code without it (tsk-tsk: better contact the author first....)
  50.     it's only used in the do_titles, do_the_help_thing, and in
  51.     process_list to let the user know what the hell is happening.  You
  52.     could easily substitute windowing routines of your own design.
  53.  
  54.     The overall program strategy works like this:  we first set up a loop
  55.     which will check each of the eight possible server connections at the
  56.     workstation running KILLCONN. If it finds a server, good: we proceed to
  57.     determine the maximum number of workstations which might be connected
  58.     to that server, and then check each one to see if the user connected to
  59.     it is a worthy victim as determined by the command-line parameters. We
  60.     always reject ourselves and anyone belonging to the group IMMORTAL. This
  61.     latter protects us from situations where a wildcard might be a little
  62.     too wild.  If we have a worthy victim, the appropriate information is
  63.     added to a singly-linked list.  After victim scanning, we walk through
  64.     the list laying waste as we go; as Arnold Schwarzenegger so aptly put
  65.     it in _Conan the Barbarian_, "We drive our enemies before us and hear
  66.     the lamentations of their women."  If confirmation and logging options
  67.     are set, the program behaves accordingly.
  68.  
  69.     While this probably seems like a lot of iterations, we have to account
  70.     for situations where we might have one user logged in with multiple
  71.     connections (often the case where someone is using generic login_names
  72.     for a student lab or other public facility, or where there might be
  73.     "holes" in the controlling workstation's server table or the server's
  74.     connection table caused by a connection being established and dropped
  75.     sometime prior to the life of KILLCONN.
  76.  
  77.     Needless to say, the program IS copyrighted and the author, Thomas R.
  78.     Bruce, cannot be held liable for any damage you do with it.  Any changes
  79.     to program code or function must be approved by the author:
  80.  
  81.     Thomas R. Bruce
  82.     147 Chestnut Street E-22
  83.     Ithaca, NY 14850                607-255-1221 or 273-2661
  84.     
  85.     In cyberspace:
  86.  
  87.     lemuel!tom @ cs.cornell.edu
  88.     or (infrequently checked) Compuserve 75360,542
  89. ***************************************************************************/
  90.     
  91.  
  92.  
  93. /* assorted includes */
  94. #ifndef _STDIO_H
  95. #include <stdio.h>
  96. #endif
  97.  
  98. #ifndef _STRING_H
  99. #include <string.h>
  100. #endif
  101.  
  102. #ifndef _CONIO_H
  103. #include <conio.h>
  104. #endif
  105.  
  106. #ifndef _DOS_H
  107. #include <dos.h>
  108. #endif
  109.  
  110. #ifndef _STDLIB_H
  111. #include <stdlib.h>
  112. #endif
  113.  
  114.  
  115. /* TCXL headers           */
  116.  
  117. #include <TCXLdef.h>
  118. #include <TCXLwin.h>
  119. #include <TCXLinp.h>
  120.  
  121. /* Novell API headers */
  122.  
  123. #include <nit.h>
  124. #include <nxt.h>
  125. #include <niterror.h>
  126.  
  127. /* assorted defines */
  128.  
  129. /* Novell API data types from their headers. Included here in the
  130. ** interest of clarity.
  131. */
  132.  
  133. #ifndef BYTE
  134. #define BYTE        unsigned char
  135. #endif
  136.  
  137. #ifndef WORD
  138. #define WORD        unsigned short
  139. #endif
  140.  
  141. #ifndef LONG
  142. #define LONG        unsigned long
  143. #endif
  144.  
  145. /* useful stuff local to this program */
  146.  
  147. #ifndef YES
  148. #define YES         1
  149. #endif
  150.  
  151. #ifndef NO
  152. #define NO            0
  153. #endif
  154.  
  155. #define    SINGLE_USER    1
  156. #define    WILD_USER   2
  157. #define  USER_GROUP    3
  158.  
  159. #define    NEW_LOG        4
  160. #define  APPEND_LOG  5
  161. #define  NO_LOG        6
  162.  
  163. #define  ALL_SERVERS 7
  164. #define  ONE_SERVER  8
  165.  
  166. #define  TITLES        10
  167. #define  NOTITLES        11
  168.  
  169. #define    CONFIRM        12
  170. #define  NOCONFIRM   13
  171.  
  172. #define     WARNINGS        14
  173. #define    NOWARNINGS  15
  174.  
  175. #define     ASTERISK        42                /* Yep, you got it: ASCII codes */
  176. #define     QUESMARK        63
  177. #define  SPACE            32
  178. #define  HVYCHECK        178
  179.  
  180. /* typedefs and whatnot */
  181.  
  182. typedef struct userinfo{            /* Struct to hold info about a victim */
  183.     char *username;
  184.     long objectID;
  185.     WORD connectionNumber;
  186.     struct userinfo *next;
  187.     }_userinfo;
  188.  
  189. typedef _userinfo *USERPTR;
  190.  
  191. /* function prototypes */
  192.  
  193. void parse_cmd_line(int _argc, char *_argv[]);
  194.                                                     /* parses the command line (no kidding) */
  195. void do_titles(void);                         /* takes care of screen setup, etc.     */
  196. void do_the_help_thing(int mode);         /* guess what?                                 */
  197.  
  198. USERPTR getnode(void);                         /* memory allocation for list node         */
  199. void freenode(USERPTR the_ptr);            /* free a list node                             */
  200. void add_to_list(USERPTR targ_user);    /* adds user info to the victim list     */
  201. void listzap(USERPTR list_start);        /* destroys list */
  202.  
  203. void process_list(void);                     /* processes the victim list                 */
  204.  
  205. int is_user_in_group(USERPTR targ_user, char *groupname);
  206.                                                     /* well, is she? */
  207. int is_wild_match(USERPTR targ_user, char *wildstring);
  208.                                                     /* does username match wildcard? */
  209.  
  210. /*    global variables */
  211.  
  212. USERPTR list_head;
  213.  
  214. /* program control. initialization here sets defaults */
  215.  
  216. int scope=            ALL_SERVERS;
  217. char targ_server[48];                 /* target server if doing just one     */ 
  218.  
  219. int search_type=    SINGLE_USER;
  220. char search_string[48];                 /* who (all) we're looking for             */ 
  221.  
  222. int log_type=        NO_LOG;
  223. int do_confirm=    NOCONFIRM;
  224. char log_file[256];                     /* 256 is the max under Netware         */
  225.  
  226. int warnings=NOWARNINGS;
  227. int warn_time=0;
  228.  
  229. int retry_count=5;
  230.  
  231. char curr_server[48];                  /* current server we're looking at     */
  232. WndT mainWin;                              /* handle for the main window            */
  233.                                              /* WndT is a TCXL data type.                */
  234.  
  235. void main(int argc, char *argv[]){
  236.     
  237.     int i,j,k;                              /* typical dumb index variable(s)     */
  238.  
  239.     WORD serverConnID;                 /* connection ID of current server     */
  240.     FILE_SERV_INFO *serverInfo;     /* all we could want to know and more */
  241.     USERPTR this_user;                 /* struct for current user                */
  242.     WORD objType;                         /* junk variable used in NWare calls    */
  243.     BYTE loginTime[7];
  244.     WORD testConn;                          /* more junk                             */
  245.     char retname[48];
  246.  
  247. /*    a couple of initializations */
  248.  
  249.     this_user=getnode();
  250.     
  251.  
  252. /* get the preliminaries out of the way */
  253.  
  254.     do_titles();
  255.     parse_cmd_line(argc,argv);
  256.  
  257. /* test for IPX installation */
  258.  
  259.     if (IPXInitialize() == IPX_NOT_INSTALLED) {
  260.         fprintf(stderr,"\n\tKILLCONN finds no IPX interface loaded.  Aborting.\n");
  261.         exit(2);
  262.     }
  263.  
  264. /* check to see if the workstation is actually logged in to something */
  265.     
  266.     serverConnID = GetPrimaryConnectionID();
  267.     if (serverConnID == 0) {
  268.         fprintf(stderr,"\n\tKILLCONN finds no primary file server. Aborting.\n");
  269.         exit(3);
  270.     }
  271.  
  272.  
  273.     /* Per-server loop. */
  274.  
  275.     for(i=1;i<=8;i++){        /* Novell table numbering starts at 1 */
  276.  
  277.     /* figure out where the hell we are */
  278.  
  279.         GetFileServerName((WORD)i,curr_server);
  280.  
  281.         if ((curr_server==NULL) || (strcmp(curr_server,"")==0)) continue;
  282.         if ((scope==ONE_SERVER)&& (strcmp(targ_server,curr_server)!=0)) continue;
  283.         SetPreferredConnectionID((BYTE)i);
  284.         SetPrimaryConnectionID((BYTE)i);
  285.  
  286.         if(CheckConsolePrivileges()!=0){
  287.             fprintf(stderr,"\n\nNo console privileges on server %s. Aborting.", curr_server);
  288.             exit(1);
  289.             }
  290.  
  291.         GetServerInformation(128,serverInfo);
  292.  
  293.     /*    Build the victim list. This strategy was selected over others because
  294.         it would seem that the usual environment for the program will be one
  295.         where not a lot of users are logged in.  However, there is no
  296.         guarantee that the logged-in connections will be sequential, or that
  297.         one user is not logged in more than once on the file server, which
  298.         makes all the iteration necessary.  */ 
  299.         
  300.         list_head=NULL;     /* zero out the list */
  301.  
  302.         for (j=1;j <= serverInfo->maxConnectionsSupported; j++){
  303.             testConn=j;        /* stupid way to force a type conversion,but mine own */
  304.             GetConnectionInformation(testConn,retname,
  305.                 &objType,&(this_user->objectID),loginTime);
  306.             this_user->connectionNumber=j;
  307.  
  308.     /* find out if the user is a worthy victim or not */
  309.     /* if there's nobody using the connection, skip onward */
  310.  
  311.             if (this_user->objectID==0) continue;
  312.  
  313.     /* if the user is in the IMMORTAL group, skip onward */
  314.  
  315.             strcpy(this_user->username,retname);
  316.             if (is_user_in_group(this_user,"IMMORTAL")==YES) continue;
  317.             
  318.             switch (search_type){
  319.                 
  320.                 case SINGLE_USER:
  321.                     if(strcmp(this_user->username,search_string)!=0) continue;
  322.                     add_to_list(this_user);
  323.                     break;
  324.                 
  325.                 case WILD_USER:
  326.                     if(is_wild_match(this_user, search_string)==YES) add_to_list(this_user);
  327.                     break;
  328.  
  329.                 case USER_GROUP:
  330.                     if(is_user_in_group(this_user, search_string)==YES) add_to_list(this_user);
  331.                     break;
  332.                 
  333.                 }        /* end switch on search type */
  334.         }                /* end of the per-connection loop */
  335.  
  336.     if (list_head != NULL) process_list();        /* g'wan and kill 'em */
  337.     listzap(list_head);                                /* liberate the list  */
  338.     
  339.     }    /* end of per-server loop */
  340.     clrscr();
  341.    exit(0);
  342. }        /* end of main () */
  343.  
  344.  
  345.  
  346. void process_list(void){
  347.  
  348.     USERPTR q;                         /* all purpose victim pointer  */
  349.     int maxstr;
  350.     FILE *out_file;                          /* handle for log file, if any */
  351.     char *conf_string;                    /* junk string for messages    */
  352.     WORD myConnection;                    /* connection number of workstation
  353.                                                    running this mess */
  354.     WORD msgConnList[100];
  355.     BYTE *resultList;
  356.     char *msg;
  357.     int j, k;
  358.     int confirmed;
  359.  
  360.     char myname[48];
  361.     WORD myobjType;
  362.     long myobjID;
  363.     BYTE mylogTime[7];                    /* all this just to find out who I am */
  364.     BYTE dateAndTime[7];
  365.     char *timeStr;
  366.  
  367.     timeStr=(char *)calloc(24,sizeof(char));
  368.  
  369.     myConnection=GetConnectionNumber();
  370.     GetConnectionInformation(myConnection,myname,(WORD *) &myobjType,(long *)&myobjID,(BYTE *)&mylogTime);
  371.     
  372.     GetFileServerDateAndTime(dateAndTime);
  373.     sprintf(timeStr,"%02d/%02d/%02d %02d:%02d:%02d:%02d",dateAndTime[1],dateAndTime[2],dateAndTime[0],dateAndTime[3],dateAndTime[4],dateAndTime[5],dateAndTime[6]);
  374.  
  375.     conf_string=(char *)calloc(128,sizeof(char));
  376.     msg=(char *)calloc(56,sizeof(char));
  377.  
  378.     switch (log_type){
  379.  
  380.         case NEW_LOG:
  381.                 if((out_file=fopen(log_file,"wt"))==NULL)
  382.                     log_type=NO_LOG;
  383.                 break;
  384.  
  385.         case APPEND_LOG:
  386.                 if((out_file=fopen(log_file,"at"))==NULL)
  387.                     log_type=NO_LOG;
  388.                 break;
  389.         }
  390.     
  391.     if (warnings==WARNINGS){     /* warn the little buggers */
  392.             sprintf(conf_string," User warnings being sent. Please wait.", q->username);
  393.             maxstr=max(strlen(conf_string),strlen(curr_server));
  394.             WpopUp(CNT_CNT, 0, 0, 4, maxstr+5, BOX_EXP, WHITE |_RED, WHITE|_RED);
  395.             Wshadow(_BLACK | DGREY);
  396.             Wtitle(" Warning users....",TTL_CNT,LIGHTCYAN|_RED|INTENSE|BLINK);
  397.             WprtCen(0,WHITE|_RED, curr_server);
  398.             WprtCen(1,WHITE|_RED, conf_string);
  399.             for (q=list_head; q!= NULL; q=q->next){
  400.                 msgConnList[0]=q->connectionNumber;
  401.                 sprintf(msg,"You will be disconnected in %d seconds.  Log out.", warn_time);
  402.                 SendBroadcastMessage(msg,msgConnList,resultList,(WORD)1);
  403.                 }
  404.  
  405.             delay(1000*warn_time); /* hang on to your hat */
  406.             Wclose();
  407.  
  408.     
  409.     }
  410.  
  411.  
  412.     for(q=list_head;q != NULL; q=q->next){
  413.  
  414.         if (strcmp(q->username,myname)==0)
  415.             continue;        /* wouldn't want to disconnect myself- or would I? */
  416.         if (do_confirm==CONFIRM){                    /* pop up a confirmation window */
  417.             sprintf(conf_string," OK to disconnect %s (y/N)?", q->username);
  418.             maxstr=max(strlen(conf_string),strlen(curr_server));
  419.             WpopUp(CNT_CNT, 0, 0, 4, maxstr+5, BOX_EXP, WHITE |_RED, WHITE|_RED);
  420.             Wshadow(_BLACK | DGREY);
  421.             Wtitle(" Are you sure? ",TTL_CNT,LIGHTCYAN|_RED|INTENSE|BLINK);
  422.             WprtCen(0,WHITE|_RED, curr_server);
  423.             WprtCen(1,WHITE|_RED, conf_string);
  424.     
  425.     /* manual-abort handler */
  426.             
  427.             if(KwGetYn(NO)!='Y'){
  428.                 Wclose();
  429.                 sprintf(conf_string,"Disconnect of %s aborted.",q->username);
  430.                 maxstr=max(strlen(conf_string),strlen(curr_server));
  431.                 WpopUp(CNT_CNT, 0, 0, 4, maxstr+5, BOX_EXP, WHITE |_RED, WHITE|_RED);
  432.                 Wshadow(_BLACK | DGREY);
  433.                 Wtitle(" Cancelling... ",TTL_CNT,LIGHTCYAN|_RED|INTENSE|BLINK);
  434.                 WprtCen(0,WHITE|_RED, curr_server);
  435.                 WprtCen(1,WHITE|_RED, conf_string);
  436.                 if(log_type != NO_LOG) fprintf(out_file,"%s\tDisconnect of %s from %s was aborted by operator.\n",timeStr,q->username,curr_server);
  437.                 delay(2000);
  438.                 continue;
  439.                 }
  440.  
  441.             Wclose();
  442.             }
  443.  
  444.         /* leave some evidence at the workstation */
  445.  
  446.         msgConnList[0]=q->connectionNumber;
  447.         sprintf(msg,"Station cleared by KILLCONN at %s",timeStr);
  448.         SendBroadcastMessage(msg,msgConnList,resultList,(WORD)1);
  449.         confirmed=1;
  450.         for(j=0;j < retry_count && confirmed!=0; ++j){
  451.             
  452.           sprintf(conf_string,"Disconnecting %s.", q->username);
  453.             maxstr=max(strlen(conf_string),strlen(curr_server));
  454.             WpopUp(CNT_CNT, 0, 0, 4, maxstr+5, BOX_EXP, WHITE |_RED, WHITE|_RED);
  455.             Wshadow(_BLACK | DGREY);
  456.             Wtitle(" Clearing connection... ",TTL_CNT,LIGHTCYAN | _RED|INTENSE|BLINK);
  457.             WprtCen(0,WHITE|_RED, curr_server);
  458.             WprtCen(1,WHITE|_RED, conf_string);
  459.             delay(3000);    /* to permit message to arrive */
  460.  
  461.             confirmed=ClearConnectionNumber(q->connectionNumber);         /* He's dead, Jim */
  462.             }
  463.         
  464.         if((log_type != NO_LOG) && (confirmed==0)) fprintf(out_file,"%s\t %s was disconnected from %s.\n",timeStr,q->username,curr_server);
  465.         if((log_type != NO_LOG) && (confirmed!=0)) fprintf(out_file,"%s\t %s disconnect from %s failed.\n",timeStr,q->username,curr_server);
  466.         if (confirmed!=0){
  467.             Wclose();
  468.             sprintf(conf_string,"Attempted disconnect of %s failed.", q->username);
  469.             maxstr=max(strlen(conf_string),strlen(curr_server));
  470.             WpopUp(CNT_CNT, 0, 0, 4, maxstr+5, BOX_EXP, WHITE |_RED, WHITE|_RED);
  471.             Wshadow(_BLACK | DGREY);
  472.             Wtitle(" Disconnect failed ",TTL_CNT,LIGHTCYAN | _RED|INTENSE|BLINK);
  473.             WprtCen(0,WHITE|_RED, curr_server);
  474.             WprtCen(1,WHITE|_RED, conf_string);
  475.             }
  476.         }
  477.     /* clean up for this server-pass */
  478.  
  479.     free (conf_string);
  480.     free (timeStr);
  481.     fcloseall();
  482.     if(Wisactiv(mainWin)==FALSE) Wclose();
  483. }
  484.  
  485. int is_user_in_group(USERPTR targ_user, char *groupname){
  486.  
  487.     int retcode;
  488.  
  489.     retcode = IsBinderyObjectInSet(groupname, OT_USER_GROUP, "GROUP_MEMBERS",targ_user->username, OT_USER);
  490.     if (retcode == 0) return (YES);
  491.     else return (NO);
  492. }
  493.  
  494.  
  495. int is_wild_match(USERPTR targ_user, char *wildstring){
  496.  
  497.     int cCode=0;
  498.  
  499.     WORD srchObjType;                        /* type of object we're scanning for;
  500.                                                    the name can be wildcarded,
  501.                                                     which is why we're using this
  502.                                                     API call */
  503.     long objID= -1L;
  504.     char retName[48];                        /* name returned by scanning function */
  505.     WORD objType;                            /* better damn well be OT_USER and not
  506.                                                     a group or something else */
  507.     char objHasProperties;
  508.     char objFlag;
  509.     char objSecurity;
  510.  
  511.     while (cCode==0){
  512.         cCode=ScanBinderyObject(wildstring, OT_USER, &objID,
  513.             retName, &objType, &objHasProperties, &objFlag, &objSecurity);
  514.         if ((strcmp(retName,targ_user->username)==0)&& (objType==OT_USER))
  515.             return(YES);
  516.         }
  517.     return(NO);
  518. }
  519.  
  520. void do_titles(void){
  521.  
  522.     TcxlInit();
  523.     WsetFil(HVYCHECK);
  524.     mainWin=Wopen(0,0,24,79,BOX_EXP,WHITE|_BLUE,CYAN|_BLUE);
  525.     WsetFil(SPACE);
  526.     Wopen(0,0,7,28,BOX_EXP,WHITE|_BLUE,WHITE|_BLUE);
  527.     Wshadow(_BLACK | DGREY);
  528.     WprtCen(1,WHITE|_BLUE,"KILLCONN");
  529.     WprtCen(2,WHITE|_BLUE,"A Connection-Killer");
  530.     WprtCen(3,WHITE|_BLUE,"for Novell Netware");
  531.     WprtCen(5,WHITE|_BLUE,"(C) 1991 Thomas R. Bruce");
  532.     Wslide(17,49);
  533.     Wslide(2,49);
  534.     Wslide(17,2);
  535.     Wcenter(CNT_CNT);
  536.     delay(3000);
  537.     Wclose();
  538.     Wopen(1,1,1,78,BOX_SPA,WHITE|_BLUE,WHITE|_BLUE);
  539.     WprtCen(0,WHITE|_BLUE,"KILLCONN copyright (C)1991 Thomas R. Bruce");
  540.     Wactiv(mainWin);
  541.     return;
  542.     }
  543.  
  544. void do_the_help_thing(int mode){
  545.  
  546.     if (mode==TITLES)do_titles();
  547.     WpopUp(CNT_CNT,0,0,16,60,BOX_EXP,WHITE|_RED,WHITE|_RED);
  548.     Wshadow(_BLACK | DGREY);
  549.     Wtitle(" Help! ", TTL_CNT,WHITE|_RED);
  550.     Wprts(0,4,LCYAN|_RED,"Command line syntax:");
  551.     Wprts(2,4,WHITE|_RED,"killconn who-options [other-options]");
  552.     Wprts(4,4,LCYAN|_RED,"where who-options is one of:");
  553.     Wprts(6,8,WHITE|_RED,"user=SOMEBODY (can contain wildcard chars)");
  554.     Wprts(7,8,WHITE|_RED,"group=USERGROUP");
  555.     Wprts(9,4,LCYAN|_RED,"and [other-options] are:");
  556.     Wprts(11,8,WHITE|_RED,"server=MYSERVE (for a single server)");
  557.     Wprts(12,8,WHITE|_RED,"confirm=YES to check before disconnecting");
  558.     Wprts(13,8,WHITE|_RED,"log=filename to log to a new text file");
  559.     Wprts(14,8,WHITE|_RED,"logadd=filename to append to an existing log");
  560.     KwGetCh();
  561.     exit(0);
  562.     }
  563.  
  564. void parse_cmd_line(int _argc, char *_argv[])
  565. {
  566.     int j;
  567.     char *arg_lead;    /* server= or whatever */
  568.     char *arg_targ;    /* actual 'content' of argument specification */
  569.     char *arg_temp;
  570.  
  571.     /* No args. Indicates confused user.  Give 'em help, quick */
  572.     /* Leaving this structured this way provides a socket for a
  573.         possible menu-driven version someday */
  574.  
  575.     if (_argc==1) do_the_help_thing(NOTITLES);
  576.  
  577.     for (j = 1; j < _argc; ++j) {
  578.  
  579.         arg_temp = (char *) strupr(_argv[j]);
  580.  
  581.         if ((strcmp(arg_temp, "-H") == 0)||(strcmp(arg_temp, "/H") == 0)||
  582.             (strcmp(arg_temp, "HELP") == 0)) do_the_help_thing(NOTITLES);
  583.  
  584.         /* now the slightly more complex ones */
  585.  
  586.         arg_lead = (char *) strupr(strtok(_argv[j], "="));
  587.         if (!arg_lead){
  588.             fprintf(stderr,"\nBad command line argument. Terminating.");
  589.             exit(4);
  590.             }
  591.  
  592.         arg_targ = (char *) strupr(strtok(NULL, "="));
  593.  
  594.         if (strcmp(arg_lead, "USER") == 0) {
  595.             if ((strchr(arg_targ,ASTERISK)!=NULL) ||
  596.                 (strchr(arg_targ,QUESMARK)!=NULL)) search_type=WILD_USER;
  597.             else search_type= SINGLE_USER;
  598.             strcpy(search_string, arg_targ);
  599.             continue;
  600.         }
  601.         if (strcmp(arg_lead, "GROUP") == 0) {
  602.             search_type=USER_GROUP;
  603.             strcpy(search_string, arg_targ);
  604.             continue;
  605.         }
  606.  
  607.     if (strcmp(arg_lead, "SERVER") == 0) {
  608.             scope=ONE_SERVER;
  609.             strcpy(targ_server,arg_targ);
  610.             continue;
  611.         }
  612.         if (strcmp(arg_lead, "CONFIRM") == 0) {
  613.             if (strcmp(arg_targ,"YES")==0) do_confirm=CONFIRM;
  614.             continue;
  615.         }
  616.         if (strcmp(arg_lead, "LOG") == 0) {
  617.             log_type=NEW_LOG;
  618.             strcpy(log_file, arg_targ);
  619.             continue;
  620.         }
  621.         if (strcmp(arg_lead, "LOGADD") == 0) {
  622.             log_type=APPEND_LOG;
  623.             strcpy(log_file, arg_targ);
  624.             continue;
  625.         }
  626.  
  627. /* Code added 4-9-91 to accomodate two new features: retries and
  628.    warnings */
  629.  
  630.         if (strcmp(arg_lead, "WARNING") == 0) {
  631.             warnings=WARNINGS;
  632.             warn_time=atoi(arg_targ);
  633.             continue;
  634.         }
  635.  
  636.         if (strcmp(arg_lead, "RETRIES") == 0) {
  637.             retry_count=atoi(arg_targ);
  638.             continue;
  639.         }
  640.  
  641.  
  642.         printf("Incomprehensible command line argument type ");
  643.         printf(arg_lead);
  644.         printf(" entered. Shame on you. Any key terminates.");
  645.         getch();
  646.         exit(1);
  647.     }
  648. }
  649.  
  650.  
  651. /* Function to add nodes to the victim list */ 
  652.  
  653. void add_to_list(USERPTR targ_user){
  654.  
  655.     USERPTR p,q;
  656.  
  657.     p=getnode();
  658.     strcpy(p->username,targ_user->username);
  659.     p->objectID=targ_user->objectID;
  660.     p->connectionNumber=targ_user->connectionNumber;
  661.     q=list_head;
  662.     list_head=p;
  663.     p->next=q;
  664.     
  665.     }
  666.  
  667.  
  668. /* Function which allocates memory for the victim list nodes */ 
  669.  
  670. USERPTR getnode(void){
  671.  
  672.     USERPTR p;
  673.  
  674.     p=(USERPTR)malloc(sizeof(struct userinfo));
  675.     p->username=(char *)calloc(48,sizeof(char));
  676.     return (p);
  677.     }
  678.  
  679. /* Function to free up nodes */
  680.  
  681. void freenode(USERPTR the_ptr){
  682.     free(the_ptr->username);
  683.     free(the_ptr);
  684.     }
  685.  
  686. /* Function to zap a whole list */
  687. void listzap(USERPTR list_start){
  688.  
  689.     USERPTR p,q;
  690.     
  691.     for (p=list_start;p==NULL;p=q){
  692.         q=p->next;
  693.         freenode(p);
  694.         }
  695.     return;
  696.     }
  697.  
  698. /****************************************************************************
  699.  
  700. That's all, folks.
  701. Completed 04/06/91 by TRB.
  702.  
  703. *****************************************************************************/
  704.