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 if (YesNoQuestion("Are you sure you want to exit", 1))
281 Put_message("Continuing input...");
282 return(PromptWithDefault(prompt, buf, buflen, def));
285 (void) strcpy(buf, def);
286 else if (!strcmp(buf, "\"\""))
291 /* Function Name: YesNoQuestion
292 * Description: This prompts the user for the answer to a yes-no or
293 * true-false question.
294 * Arguments: prompt - the prompt for the user.
295 * bool_def - the default value either TRUE or FALSE.
296 * Returns: TRUE or FALSE or -1 on error
300 YesNoQuestion(prompt, bool_def)
307 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
317 Put_message("Please answer 'y' or 'n'.");
322 /* Function Name: YesNoQuitQuestion
323 * Description: This prompts the user for the answer to a yes-no or
324 * true-false question, with a quit option.
325 * Arguments: prompt - the prompt for the user.
326 * bool_def - the default value either TRUE or FALSE.
327 * Returns: TRUE or FALSE or -1 on error or QUIT
328 * NOTE: It is not possible to have quit the default, but then I don't
329 * seem to need this functionality.
333 YesNoQuitQuestion(prompt, bool_def)
340 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
353 Put_message("Please answer 'y', 'n' or 'q'.");
359 /* Function Name: Confirm
360 * Description: This function asks the user to confirm the action
361 * he is about to take, used for things like deleting.
362 * Arguments: prompt - the prompt string.
363 * Returns: TRUE/FALSE - wether or not the confirmation occured.
370 return( !verbose || (YesNoQuestion(prompt,FALSE) == TRUE) );
373 /* Function Name: ValidName
374 * Description: This function checks to see if we have a valid list name.
375 * Arguments: s - the list name.
376 * Returns: TRUE if Valid.
384 Put_message("Please use a non-empty name.");
385 else if (index(s, ' '))
386 Put_message("You cannot use space (' ') in this name.");
387 else if (index(s, WILDCARD))
388 Put_message("Wildcards not accepted here.");
394 /* Function Name: ToggleVerboseMode
395 * Description: This function toggles the verbose mode.
397 * Returns: DM_NORMAL.
407 Put_message("Delete functions will first confirm\n");
409 Put_message("Delete functions will be silent\n");
414 /* Function Name: NullFunc
415 * Description: dummy callback routine
426 /* Function Name: SlipInNewName
427 * Description: Slips the new name into the number 2 slot of a list, and
428 * returns a pointer to the new list.
429 * Arguments: info - list that needs this name slipped into it.
430 * name - the name to slip into the list.
431 * Returns: a pointer to the new list.
432 * NOTE: This screws up the numbers of the elements of the array in a
437 SlipInNewName(info, name)
443 /* This also pushes the NULL down. */
444 for (i = CountArgs(info); i > 1; i--) {
447 info[1] = name; /* now slip in the name. */
450 /* Function Name: GetValueFromUser
451 * Description: This function gets a value from a user for the field
453 * Arguments: prompt - prompt for user.
454 * pointer - pointer to default value, will be returned
456 * Returns: SUB_ERROR if break hit (^C).
460 GetValueFromUser(prompt, pointer)
461 char * prompt, ** pointer;
465 if (PromptWithDefault(prompt, buf, BUFSIZ, *pointer) == -1)
469 * If these are the same then there is no need to allocate a new string.
471 * a difference that makes no difference, IS no difference.
474 if (strcmp(buf, *pointer) != 0) {
475 if (*pointer != NULL)
477 *pointer = Strsave(buf);
482 /* Function Name: GetYesNoValueFromUser
483 * Description: This function gets a value from a user for the field
485 * Arguments: prompt - prompt for user.
486 * pointer - pointer to default value, will be returned
488 * Returns: SUB_ERROR if break hit (^C).
492 GetYesNoValueFromUser(prompt, pointer)
493 char * prompt, ** pointer;
495 char user_prompt[BUFSIZ];
498 if ( strcmp (*pointer, DEFAULT_YES) == 0 )
503 sprintf(user_prompt, "%s (y/n)", prompt);
505 switch (YesNoQuestion(user_prompt, default_val)) {
507 if (*pointer != NULL)
509 *pointer = Strsave(DEFAULT_YES);
512 if (*pointer != NULL)
514 *pointer = Strsave(DEFAULT_NO);
523 /* Function Name: GetFSVal
524 * Description: asks about a specific filesystem value.
525 * Arguments: name - string for this type of filesystem.
526 * mask - mask for this type of filesystem.
527 * current - current filesystem state. (for defaults).
528 * new - new filesystem state.
529 * Returns: TRUE if successful.
533 GetFSVal(name, mask, current, new)
535 int mask, current, *new;
537 char temp_buf[BUFSIZ];
538 sprintf(temp_buf, "Is this a %s filsystem", name);
539 switch (YesNoQuestion(temp_buf, ( (mask & current) == mask) )) {
544 break; /* zero by default. */
551 /* Function Name: GetFSTypes
552 * Description: Allows user to specify filsystem types.
553 * Arguments: current - current value of filsystem, freed here.
554 * Returns: SUB_ERROR on ^C.
561 int c_value, new_val = 0; /* current value of filesys type (int). */
562 char ret_value[BUFSIZ];
564 if (*current == NULL)
567 c_value = atoi(*current);
569 if (GetFSVal("student", SMS_FS_STUDENT, c_value, &new_val) == FALSE)
571 if (GetFSVal("faculty", SMS_FS_FACULTY, c_value, &new_val) == FALSE)
573 if (GetFSVal("staff", SMS_FS_STAFF, c_value, &new_val) == FALSE)
575 if (GetFSVal("miscellaneous", SMS_FS_MISC, c_value, &new_val) == FALSE)
578 FreeAndClear(current, TRUE);
579 sprintf(ret_value, "%d", new_val);
580 *current = Strsave(ret_value);
584 /* Function Name: CanonicalizeHostname
585 * Description: This function takes a machine name and canonicalize's it.
586 * Arguments: machine - name of the machine to work on.
587 * Returns: new name or NULL if nameserver returns error
591 CanonicalizeHostname(machine)
594 struct hostent *hostinfo;
596 hostinfo = gethostbyname(machine);
597 /* If this fails then we just return what we were passed. */
598 if (hostinfo != (struct hostent *) NULL)
599 machine = hostinfo->h_name;
603 /* Function Name: Strsave
604 * Description: save a string.
605 * Arguments: string - the string to save.
606 * Returns: The malloced string, now safely saved, or NULL.
613 register char *newstr = malloc((unsigned) strlen(str) + 1);
615 if (newstr == (char *) NULL)
616 return ((char *) NULL);
618 return (strcpy(newstr, str));
621 /* Function Name: Print
622 * Description: prints out all the arguments on a single line.
623 * Arguments: argc, argv - the standard SMS arguments.
624 * callback - the callback function - NOT USED.
630 Print(argc, argv, callback)
632 char **argv, *callback;
638 (void) strcpy(buf,argv[0]); /* no newline 'cause Put_message adds one */
639 for (i = 1; i < argc; i++)
640 (void) sprintf(buf,"%s %s",buf,argv[i]);
641 (void) Put_message(buf);
646 /* Function Name: PrintByType
647 * Description: This function prints all members of the type specified
648 * by the callback arg, unless the callback is NULL, in which
649 * case it prints all members.
650 * Arguments: argc, argc - normal arguments for sms_callback function.
651 * callback - either a type of member or NULL.
652 * Returns: SMS_CONT or SMS_QUIT.
657 PrintByType(argc, argv, callback)
659 char **argv, *callback;
661 if (callback == NULL)
662 return( Print(argc, argv, callback) );
663 if (strcmp(argv[0], callback) == 0)
664 return( Print(argc, argv, callback) );
668 /* Function Name: PrintHelp
669 * Description: Prints Help Information in a NULL terminated
671 * Arguments: message.
672 * Returns: DM_NORMAL.
679 Print(CountArgs(message), message, (char *) NULL);
683 /* Function Name: Loop
684 * Description: This function goes through the entire queue, and
685 * and executes the given function on each element.
686 * Arguments: elem - top element of the queue.
687 * func - the function to execute.
696 while (elem != NULL) {
697 char ** info = (char **) elem->q_data;
704 /* Function Name: QueryLoop
705 * Description: This functions loops through a queue containing
706 * information about some item that we want to perform
707 * an operation on, and then calls the correct routine
708 * perform that operation.
709 * Arguments: top - top of the queue of information.
710 * print_func - print function.
711 * op_function - operation to be performed.
712 * query_string - string the prompts the user whether or not
713 * to perform this operation.
716 * print_opt - should expect one arguent, the info array
718 * is expected to return the name of the item.
719 * op_func - should expect two arguments.
720 * 1) the info array of char *'s.
721 * 2) a boolean the is true if there only
722 * one item in this queue, used for delete
724 * query_string - this should be of such a form that when the
725 * name of the object and '(y/n/q) ?' are appended
726 * then it should still make sense, an example is
731 QueryLoop(elem, print_func, op_func, query_string)
734 FCharStar print_func;
738 char temp_buf[BUFSIZ], *name;
740 one_item = (QueueCount(elem) == 1);
741 while (elem != NULL) {
742 char **info = (char **) elem->q_data;
745 (*op_func) (info, one_item);
747 name = (*print_func) (info); /* call print function. */
748 sprintf(temp_buf,"%s %s (y/n/q)", query_string, name);
749 switch(YesNoQuitQuestion(temp_buf, FALSE)) {
751 (*op_func) (info, one_item);
756 Put_message("Aborting...");
764 /* Function Name: NullPrint
765 * Description: print function that returns nothing.
766 * Arguments: info - a pointer to the info array - Not used.
781 * c-continued-statement-offset: 4
783 * c-argdecl-indent: 4