1 #if (!defined(lint) && !defined(SABER))
2 static char rcsid_module_c[] = "$Header$";
5 /* This is the file utils.c for the SMS Client, which allows a nieve
6 * user to quickly and easily maintain most parts of the SMS database.
7 * It Contains: Many useful utility functions.
10 * By: Chris D. Peterson
16 * Copyright 1988 by the Massachusetts Institute of Technology.
18 * For further information on copyright and distribution
19 * see the file mit-copyright.h
27 #include "mit-copyright.h"
33 #include <netdb.h> /* for gethostbyname. */
35 /* Function Name: AddQueue
36 * Description: Adds an element to a queue
37 * Arguments: elem, pred - element and its predecessor.
43 struct qelem * elem, *pred;
51 elem->q_forw = pred->q_forw;
55 /* Function Name: RemoveQueue
56 * Description: removes an element from a queue.
65 if (elem->q_forw != NULL)
66 (elem->q_forw)->q_back = elem->q_back;
67 if (elem->q_back != NULL)
68 (elem->q_back)->q_forw = elem->q_forw;
71 /* Function Name: FreeInfo
72 * Description: Frees all elements of a NULL terminated arrary of char*'s
73 * Arguments: info - array who's elements we are to free.
82 FreeAndClear(info++, TRUE);
85 /* Function Name: FreeAndClear - I couldn't resist the name.
86 * Description: Clears pointer and optionially frees it.
87 * Arguments: pointer - pointer to work with.
88 * free_it - if TRUE then free pointer.
93 FreeAndClear(pointer, free_it)
104 /* Function Name: QueueTop
105 * Description: returns a qelem pointer that points to the top of
107 * Arguments: elem - any element of a queue.
108 * Returns: top element of a queue.
115 if (elem == NULL) /* NULL returns NULL. */
117 while (elem->q_back != NULL)
122 /* Function Name: FreeQueueElem
123 * Description: Frees one element of the queue.
124 * Arguments: elem - the elem to free.
132 char ** info = (char **) elem->q_data;
134 if (info != (char **) NULL) {
135 FreeInfo( info ); /* free info fields */
136 free(elem->q_data); /* free info array itself. */
138 RemoveQueue(elem); /* remove this element from the queue */
139 free(elem); /* free its space. */
142 /* Function Name: FreeQueue
143 * Description: Cleans up the queue
144 * Arguments: elem - any element of the queue.
152 struct qelem *temp, *local = QueueTop(elem);
154 while(local != NULL) {
155 temp = local->q_forw;
156 FreeQueueElem(local);
161 /* Function Name: QueueCount
162 * Description: Counts the number of elements in a queue
163 * Arguments: elem - any element in the queue.
172 elem = QueueTop(elem);
173 while (elem != NULL) {
180 /* Function Name: StoreInfo
181 * Description: Stores information from an sms query into a queue.
182 * Arguments: argc, argv, - information returned from the query returned
184 * data - the previous element on the queue, this data will be
185 * stored in a qelem struct immediatly after this elem.
186 * If NULL then a new queue will be created. This value
187 * is updated to the current element at the end off the
189 * Returns: SMS_CONT, or SMS_ABORT if it has problems.
193 StoreInfo(argc, argv, data)
198 char ** info = (char **) malloc( MAX_ARGS_SIZE * sizeof(char *));
199 struct qelem ** old_elem = (struct qelem **) data;
200 struct qelem * new_elem = (struct qelem *) malloc (sizeof (struct qelem));
203 if ( (new_elem == (struct qelem *) NULL) || (info == (char **) NULL) ) {
204 Put_message("Could Not allocate more memory.");
205 FreeQueue(*old_elem);
206 *old_elem = (struct qelem *) NULL;
210 for (count = 0; count < argc; count++)
211 info[count] = Strsave(argv[count]);
212 info[count] = NULL; /* NULL terminate this sucker. */
214 new_elem->q_data = (char *) info;
215 AddQueue(new_elem, *old_elem);
217 *old_elem = new_elem;
221 /* Function Name: CountArgs
222 * Description: Retrieve the number of args in a null terminated
224 * Arguments: info - the argument list.
225 * Returns: number if args in the list.
234 while (*info != NULL) {
242 /* Function Name: Scream
243 * Description: Bitch Loudly and exit, it is intended as a callback
244 * function for queries that should never return a value.
246 * Returns: doesn't exit.
252 com_err(program_name, 0,
253 "\nAn SMS update returned a value -- programmer botch\n");
258 /* Function Name: PromptWithDefault
259 * Description: allows a user to be prompted for input, and given a
261 * Arguments: prompt - the prompt string.
262 * buf, buflen - buffer to be returned and its MAX size?
263 * default value for the answer.
264 * Returns: the value returned by prompt_input.
268 PromptWithDefault(prompt, buf, buflen, def)
276 (void) sprintf(tmp, "%s [%s]: ", prompt, def ? def : "");
277 ans = Prompt_input(tmp, buf, buflen);
279 (void) strcpy(buf, def);
283 /* Function Name: YesNoQuestion
284 * Description: This prompts the user for the answer to a yes-no or
285 * true-false question.
286 * Arguments: prompt - the prompt for the user.
287 * bool_def - the default value either TRUE or FALSE.
288 * Returns: TRUE or FALSE or -1 on error
292 YesNoQuestion(prompt, bool_def)
299 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
309 Put_message("Please answer 'y' or 'n'.");
314 /* Function Name: YesNoQuitQuestion
315 * Description: This prompts the user for the answer to a yes-no or
316 * true-false question, with a quit option.
317 * Arguments: prompt - the prompt for the user.
318 * bool_def - the default value either TRUE or FALSE.
319 * Returns: TRUE or FALSE or -1 on error or QUIT
320 * NOTE: It is not possible to have quit the default, but then I don't
321 * seem to need this functionality.
325 YesNoQuitQuestion(prompt, bool_def)
332 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
345 Put_message("Please answer 'y', 'n' or 'q'.");
351 /* Function Name: Confirm
352 * Description: This function asks the user to confirm the action
353 * he is about to take, used for things like deleting.
354 * Arguments: prompt - the prompt string.
355 * Returns: TRUE/FALSE - wether or not the confirmation occured.
362 return( !verbose || (YesNoQuestion(prompt,FALSE) == TRUE) );
365 /* Function Name: ValidName
366 * Description: This function checks to see if we have a valid list name.
367 * Arguments: s - the list name.
368 * Returns: TRUE if Valid.
376 Put_message("Please use a non-empty name.");
377 else if (index(s, ' '))
378 Put_message("You cannot use space (' ') in this name.");
379 else if (index(s, WILDCARD))
380 Put_message("Wildcards not accepted here.");
386 /* Function Name: ToggleVerboseMode
387 * Description: This function toggles the verbose mode.
389 * Returns: DM_NORMAL.
399 Put_message("Delete functions will first confirm\n");
401 Put_message("Delete functions will be silent\n");
406 /* Function Name: NullFunc
407 * Description: dummy callback routine
418 /* Function Name: SlipInNewName
419 * Description: Slips the new name into the number 2 slot of a list, and
420 * returns a pointer to the new list.
421 * Arguments: info - list that needs this name slipped into it.
422 * name - the name to slip into the list.
423 * Returns: a pointer to the new list.
424 * NOTE: This screws up the numbers of the elements of the array in a
429 SlipInNewName(info, name)
435 /* This also pushes the NULL down. */
436 for (i = CountArgs(info); i > 1; i--) {
439 info[1] = name; /* now slip in the name. */
442 /* Function Name: GetValueFromUser
443 * Description: This function gets a value from a user for the field
445 * Arguments: prompt - prompt for user.
446 * pointer - pointer to default value, will be returned
448 * Returns: SUB_ERROR if break hit (^C).
452 GetValueFromUser(prompt, pointer)
453 char * prompt, ** pointer;
457 if (PromptWithDefault(prompt, buf, BUFSIZ, *pointer) == -1)
461 * If these are the same then there is no need to allocate a new string.
463 * a difference that makes no difference, IS no difference.
466 if (strcmp(buf, *pointer) != 0) {
467 if (*pointer != NULL)
469 *pointer = Strsave(buf);
474 /* Function Name: GetYesNoValueFromUser
475 * Description: This function gets a value from a user for the field
477 * Arguments: prompt - prompt for user.
478 * pointer - pointer to default value, will be returned
480 * Returns: SUB_ERROR if break hit (^C).
484 GetYesNoValueFromUser(prompt, pointer)
485 char * prompt, ** pointer;
487 char user_prompt[BUFSIZ];
490 if ( strcmp (*pointer, DEFAULT_YES) == 0 )
495 sprintf(user_prompt, "%s (y/n)", prompt);
497 switch (YesNoQuestion(user_prompt, default_val)) {
499 if (*pointer != NULL)
501 *pointer = Strsave(DEFAULT_YES);
504 if (*pointer != NULL)
506 *pointer = Strsave(DEFAULT_NO);
515 /* Function Name: GetFSVal
516 * Description: asks about a specific filesystem value.
517 * Arguments: name - string for this type of filesystem.
518 * mask - mask for this type of filesystem.
519 * current - current filesystem state. (for defaults).
520 * new - new filesystem state.
521 * Returns: TRUE if successful.
525 GetFSVal(name, mask, current, new)
527 int mask, current, *new;
529 char temp_buf[BUFSIZ];
530 sprintf(temp_buf, "Is this a %s filsystem", name);
531 switch (YesNoQuestion(temp_buf, ( (mask & current) == mask) )) {
536 break; /* zero by default. */
543 /* Function Name: GetFSTypes
544 * Description: Allows user to specify filsystem types.
545 * Arguments: current - current value of filsystem, freed here.
546 * Returns: SUB_ERROR on ^C.
553 int c_value, new_val = 0; /* current value of filesys type (int). */
554 char ret_value[BUFSIZ];
556 if (*current == NULL)
559 c_value = atoi(*current);
561 if (GetFSVal("student", SMS_FS_STUDENT, c_value, &new_val) == FALSE)
563 if (GetFSVal("faculty", SMS_FS_FACULTY, c_value, &new_val) == FALSE)
565 if (GetFSVal("staff", SMS_FS_STAFF, c_value, &new_val) == FALSE)
567 if (GetFSVal("miscellaneous", SMS_FS_MISC, c_value, &new_val) == FALSE)
570 FreeAndClear(current, TRUE);
571 sprintf(ret_value, "%d", new_val);
572 *current = Strsave(ret_value);
576 /* Function Name: CanonicalizeHostname
577 * Description: This function takes a machine name and canonicalize's it.
578 * Arguments: machine - name of the machine to work on.
579 * Returns: new name or NULL if nameserver returns error
583 CanonicalizeHostname(machine)
586 struct hostent *hostinfo;
588 hostinfo = gethostbyname(machine);
589 /* If this fails then we just return what we were passed. */
590 if (hostinfo != (struct hostent *) NULL)
591 machine = hostinfo->h_name;
595 /* Function Name: Strsave
596 * Description: save a string.
597 * Arguments: string - the string to save.
598 * Returns: The malloced string, now safely saved, or NULL.
605 register char *newstr = malloc((unsigned) strlen(str) + 1);
607 if (newstr == (char *) NULL)
608 return ((char *) NULL);
610 return (strcpy(newstr, str));
613 /* Function Name: Print
614 * Description: prints out all the arguments on a single line.
615 * Arguments: argc, argv - the standard SMS arguments.
616 * callback - the callback function - NOT USED.
622 Print(argc, argv, callback)
624 char **argv, *callback;
630 (void) strcpy(buf,argv[0]); /* no newline 'cause Put_message adds one */
631 for (i = 1; i < argc; i++)
632 (void) sprintf(buf,"%s %s",buf,argv[i]);
633 (void) Put_message(buf);
638 /* Function Name: PrintByType
639 * Description: This function prints all members of the type specified
640 * by the callback arg, unless the callback is NULL, in which
641 * case it prints all members.
642 * Arguments: argc, argc - normal arguments for sms_callback function.
643 * callback - either a type of member or NULL.
644 * Returns: SMS_CONT or SMS_QUIT.
649 PrintByType(argc, argv, callback)
651 char **argv, *callback;
653 if (callback == NULL)
654 return( Print(argc, argv, callback) );
655 if (strcmp(argv[0], callback) == 0)
656 return( Print(argc, argv, callback) );
660 /* Function Name: PrintHelp
661 * Description: Prints Help Information in a NULL terminated
663 * Arguments: message.
664 * Returns: DM_NORMAL.
671 Print(CountArgs(message), message, (char *) NULL);
675 /* Function Name: Loop
676 * Description: This function goes through the entire queue, and
677 * and executes the given function on each element.
678 * Arguments: elem - top element of the queue.
679 * func - the function to execute.
688 while (elem != NULL) {
689 char ** info = (char **) elem->q_data;
696 /* Function Name: QueryLoop
697 * Description: This functions loops through a queue containing
698 * information about some item that we want to perform
699 * an operation on, and then calls the correct routine
700 * perform that operation.
701 * Arguments: top - top of the queue of information.
702 * print_func - print function.
703 * op_function - operation to be performed.
704 * query_string - string the prompts the user whether or not
705 * to perform this operation.
708 * print_opt - should expect one arguent, the info array
710 * is expected to return the name of the item.
711 * op_func - should expect two arguments.
712 * 1) the info array of char *'s.
713 * 2) a boolean the is true if there only
714 * one item in this queue, used for delete
716 * query_string - this should be of such a form that when the
717 * name of the object and '(y/n/q) ?' are appended
718 * then it should still make sense, an example is
723 QueryLoop(elem, print_func, op_func, query_string)
726 FCharStar print_func;
730 char temp_buf[BUFSIZ], *name;
732 one_item = (QueueCount(elem) == 1);
733 while (elem != NULL) {
734 char **info = (char **) elem->q_data;
737 (*op_func) (info, one_item);
739 name = (*print_func) (info); /* call print function. */
740 sprintf(temp_buf,"%s %s (y/n/q)", query_string, name);
741 switch(YesNoQuitQuestion(temp_buf, FALSE)) {
743 (*op_func) (info, one_item);
748 Put_message("Aborting...");
756 /* Function Name: NullPrint
757 * Description: print function that returns nothing.
758 * Arguments: info - a pointer to the info array - Not used.
773 * c-continued-statement-offset: 4
775 * c-argdecl-indent: 4