]> andersk Git - moira.git/blob - clients/moira/utils.c
5b2fc949dfd449af58e945e987f0de36e30346d5
[moira.git] / clients / moira / utils.c
1 #if (!defined(lint) && !defined(SABER))
2   static char rcsid_module_c[] = "$Header$";
3 #endif lint
4
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.
8  *      
9  *      Created:        4/25/88
10  *      By:             Chris D. Peterson
11  *
12  *      $Source$
13  *      $Author$
14  *      $Header$
15  *      
16  *      Copyright 1988 by the Massachusetts Institute of Technology.
17  *
18  *      For further information on copyright and distribution 
19  *      see the file mit-copyright.h
20  */
21
22 #include <stdio.h>
23 #include <strings.h>
24 #include <sms.h>
25 #include <menu.h>
26 #include <ctype.h>
27
28 #include "mit-copyright.h"
29 #include "defs.h"
30 #include "f_defs.h"
31 #include "globals.h"
32 #include "infodefs.h"
33
34 #include <netdb.h>              /* for gethostbyname. */
35
36 /*      Function Name: AddQueue
37  *      Description: Adds an element to a queue
38  *      Arguments: elem, pred - element and its predecessor.
39  *      Returns: none.
40  */
41
42 static void
43 AddQueue(elem, pred)
44 struct qelem * elem, *pred;
45 {
46     if (pred == NULL) {
47         elem->q_forw = NULL;
48         elem->q_back = NULL;
49         return;
50     }
51     elem->q_back = pred;
52     elem->q_forw = pred->q_forw;
53     pred->q_forw = elem;
54 }
55
56 /*      Function Name: RemoveQueue
57  *      Description: removes an element from a queue.
58  *      Arguments: elem.
59  *      Returns: none.
60  */
61
62 static void
63 RemoveQueue(elem)
64 struct qelem *elem;
65 {
66     if (elem->q_forw != NULL) 
67         (elem->q_forw)->q_back = elem->q_back;
68     if (elem->q_back != NULL)
69         (elem->q_back)->q_forw = elem->q_forw;
70 }
71
72 /*      Function Name: FreeInfo
73  *      Description: Frees all elements of a NULL terminated arrary of char*'s
74  *      Arguments: info - array who's elements we are to free.
75  *      Returns: none.
76  */
77
78 void
79 FreeInfo(info)
80 char ** info;
81 {
82     while (*info != NULL)
83         FreeAndClear(info++, TRUE);
84 }
85
86 /*      Function Name: FreeAndClear        - I couldn't resist the name.
87  *      Description: Clears pointer and optionially frees it.
88  *      Arguments: pointer - pointer to work with.
89  *                 free_it - if TRUE then free pointer.
90  *      Returns: none.
91  */
92
93 void
94 FreeAndClear(pointer, free_it)
95 char ** pointer;
96 Bool free_it;
97 {
98     if (*pointer == NULL)
99         return;
100     else if (free_it)
101         free(*pointer);
102     *pointer = NULL;
103 }
104
105 /*      Function Name: QueueTop
106  *      Description: returns a qelem pointer that points to the top of
107  *                   a queue.
108  *      Arguments: elem - any element of a queue.
109  *      Returns: top element of a queue.
110  */
111     
112 struct qelem * 
113 QueueTop(elem)
114 struct qelem * elem;
115 {
116     if (elem == NULL)           /* NULL returns NULL.  */
117         return(NULL);
118     while (elem->q_back != NULL) 
119         elem = elem->q_back;
120     return(elem);
121 }
122
123 /*      Function Name: FreeQueueElem
124  *      Description: Frees one element of the queue.
125  *      Arguments: elem - the elem to free.
126  *      Returns: none
127  */
128
129 static void
130 FreeQueueElem(elem)
131 struct qelem * elem;
132 {
133     char ** info = (char **) elem->q_data;
134
135     if (info != (char **) NULL) {
136         FreeInfo( info ); /* free info fields */
137         free(elem->q_data);             /* free info array itself. */
138     }
139     RemoveQueue(elem);          /* remove this element from the queue */
140     free(elem);                 /* free its space. */
141 }
142
143 /*      Function Name: FreeQueue
144  *      Description: Cleans up the queue
145  *      Arguments: elem - any element of the queue.
146  *      Returns: none.
147  */
148
149 void
150 FreeQueue(elem)
151 struct qelem * elem;
152 {
153     struct qelem *temp, *local = QueueTop(elem); 
154
155     while(local != NULL) {
156         temp = local->q_forw;
157         FreeQueueElem(local);
158         local = temp;
159     }
160 }
161
162 /*      Function Name: QueueCount
163  *      Description: Counts the number of elements in a queue
164  *      Arguments: elem - any element in the queue.
165  *      Returns: none.
166  */
167
168 int
169 QueueCount(elem)
170 struct qelem * elem;
171 {
172     int count = 0;
173     elem = QueueTop(elem);
174     while (elem != NULL) {
175         count ++;
176         elem = elem->q_forw;
177     }
178     return(count);
179 }
180
181 /*      Function Name: StoreInfo
182  *      Description: Stores information from an sms query into a queue.
183  *      Arguments: argc, argv, - information returned from the query returned
184  *                               in argv.
185  *                 data - the previous element on the queue, this data will be
186  *                        stored in a qelem struct immediatly after this elem.
187  *                        If NULL then a new queue will be created.  This value
188  *                        is updated to the current element at the end off the
189  *                        call.
190  *      Returns: SMS_CONT, or SMS_ABORT if it has problems.
191  */
192
193 int
194 StoreInfo(argc, argv, data)
195 int argc;
196 char ** argv;
197 char * data;
198 {
199     char ** info = (char **) malloc( MAX_ARGS_SIZE * sizeof(char *));
200     struct qelem ** old_elem = (struct qelem **) data;
201     struct qelem * new_elem = (struct qelem *) malloc (sizeof (struct qelem));
202     int count;
203
204     if ( (new_elem == (struct qelem *) NULL) || (info == (char **) NULL) ) {
205         Put_message("Could Not allocate more memory.");
206         FreeQueue(*old_elem);
207         *old_elem = (struct qelem *) NULL;
208         return(SMS_ABORT);
209     }
210
211     for (count = 0; count < argc; count++)
212         info[count] = Strsave(argv[count]);
213     info[count] = NULL;         /* NULL terminate this sucker. */
214
215     new_elem->q_data = (char *) info;
216     AddQueue(new_elem, *old_elem);
217
218     *old_elem = new_elem;
219     return(SMS_CONT);
220 }
221
222 /*      Function Name: CountArgs
223  *      Description:  Retrieve the number of args in a null terminated
224  *                     arglist.
225  *      Arguments: info - the argument list.
226  *      Returns: number if args in the list.
227  */
228
229 int
230 CountArgs(info)
231 char ** info;
232 {
233     int number = 0;
234     
235     while (*info != NULL) {
236         number++;
237         info++;
238     }
239
240     return(number);
241 }    
242
243 /*      Function Name: Scream
244  *      Description: Bitch Loudly and exit, it is intended as a callback
245  *                   function for queries that should never return a value.
246  *      Arguments: none
247  *      Returns: doesn't exit.
248  */
249
250 int
251 Scream()
252 {
253     com_err(program_name, 0,
254             "\nAn SMS update returned a value -- programmer botch\n");
255     sms_disconnect();
256     exit(1);
257 }
258
259 /*      Function Name: PromptWithDefault
260  *      Description: allows a user to be prompted for input, and given a 
261  *                   default choice.
262  *      Arguments: prompt - the prompt string.
263  *                 buf, buflen - buffer to be returned and its MAX size?
264  *                 default value for the answer.
265  *      Returns: the value returned by prompt_input.
266  */
267
268 int
269 PromptWithDefault(prompt, buf, buflen, def)
270 char *prompt, *buf;
271 int buflen;
272 char *def;
273 {
274     char tmp[BUFSIZ];
275     int ans;
276
277     (void) sprintf(tmp, "%s [%s]: ", prompt, def ? def : "");
278     ans = Prompt_input(tmp, buf, buflen);
279     if (ans == 0) {
280         if (YesNoQuestion("Are you sure you want to exit", 1)) {
281             Cleanup_menu();
282             exit(0);
283         }
284         Put_message("Continuing input...");
285         return(PromptWithDefault(prompt, buf, buflen, def));
286     }
287     if (IS_EMPTY(buf))
288         (void) strcpy(buf, def);
289     else if (!strcmp(buf, "\"\""))
290         *buf = 0;
291     return(ans);
292 }
293
294 /*      Function Name: YesNoQuestion
295  *      Description: This prompts the user for the answer to a yes-no or
296  *                   true-false question.
297  *      Arguments: prompt - the prompt for the user.
298  *                 bool_def - the default value either TRUE or FALSE.
299  *      Returns: TRUE or FALSE or -1 on error
300  */
301
302 Bool
303 YesNoQuestion(prompt, bool_def)
304 char *prompt;
305 int bool_def;
306 {
307     char ans[2];
308
309     while (TRUE) {
310         if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
311             return(-1);
312         switch (ans[0]) {
313         case 'n':
314         case 'N':
315             return(FALSE);
316         case 'y':
317         case 'Y':
318             return(TRUE);
319         default:
320             Put_message("Please answer 'y' or 'n'.");
321             break;
322         }
323     }
324 }
325 /*      Function Name: YesNoQuitQuestion
326  *      Description: This prompts the user for the answer to a yes-no or
327  *                   true-false question, with a quit option.
328  *      Arguments: prompt - the prompt for the user.
329  *                 bool_def - the default value either TRUE or FALSE.
330  *      Returns: TRUE or FALSE or -1 on error or QUIT
331  *      NOTE: It is not possible to have quit the default, but then I don't
332  *            seem to need this functionality.
333  */
334
335 Bool
336 YesNoQuitQuestion(prompt, bool_def)
337 char *prompt;
338 int bool_def;
339 {
340     char ans[2];
341
342     while (TRUE) {
343         if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
344             return(-1);
345         switch (ans[0]) {
346         case 'n':
347         case 'N':
348             return(FALSE);
349         case 'y':
350         case 'Y':
351             return(TRUE);
352         case 'q':
353         case 'Q':
354             return(-1);
355         default:
356             Put_message("Please answer 'y', 'n' or 'q'.");
357             break;
358         }
359     }
360 }
361
362 /*      Function Name: Confirm
363  *      Description:   This function asks the user to confirm the action
364  *                     he is about to take, used for things like deleting.
365  *      Arguments: prompt - the prompt string.
366  *      Returns:   TRUE/FALSE - wether or not the confirmation occured.
367  */
368
369 Bool
370 Confirm(prompt)
371 char * prompt;
372 {
373   return( !verbose || (YesNoQuestion(prompt,FALSE) == TRUE) );
374 }
375
376 /*      Function Name: ValidName
377  *      Description: This function checks to see if we have a valid list name.
378  *      Arguments: s - the list name.
379  *      Returns: TRUE if Valid.
380  */
381
382 Bool
383 ValidName(s)
384 char *s;
385 {
386     if (IS_EMPTY(s))
387         Put_message("Please use a non-empty name.");
388     else if (index(s, ' '))
389         Put_message("You cannot use space (' ') in this name.");
390     else if (index(s, WILDCARD))
391         Put_message("Wildcards not accepted here.");
392     else
393         return TRUE;
394     return FALSE;
395 }
396
397 /*      Function Name: ToggleVerboseMode
398  *      Description: This function toggles the verbose mode.
399  *      Arguments: none
400  *      Returns: DM_NORMAL.
401  */
402
403 int 
404 ToggleVerboseMode()
405 {
406
407   verbose = !verbose;
408
409   if (verbose)
410     Put_message("Delete functions will first confirm\n");
411   else
412     Put_message("Delete functions will be silent\n");
413     
414   return(DM_NORMAL);
415 }
416
417 /*      Function Name: NullFunc
418  *      Description:  dummy callback routine 
419  *      Arguments: none
420  *      Returns: SMS_CONT
421  */
422
423 int
424 NullFunc()
425 {
426     return(SMS_CONT);
427 }
428
429 /*      Function Name: SlipInNewName
430  *      Description: Slips the new name into the number 2 slot of a list, and
431  *                   returns a pointer to the new list.
432  *      Arguments: info - list that needs this name slipped into it.
433  *                 name - the name to slip into the list.
434  *      Returns: a pointer to the new list.
435  *      NOTE:  This screws up the numbers of the elements of the array in a
436  *             big way.
437  */
438
439 void
440 SlipInNewName(info, name)
441 char ** info;
442 char * name;
443 {
444     register int i;
445
446     /* This also pushes the NULL down. */
447     for (i = CountArgs(info); i > 1; i--) { 
448         info[i] = info[i-1];
449     }
450     info[1] = name;     /* now slip in the name. */
451 }
452
453 /*      Function Name: GetValueFromUser
454  *      Description: This function gets a value from a user for the field
455  *                   specified.
456  *      Arguments: prompt - prompt for user.
457  *                 pointer - pointer to default value, will be returned
458  *                          as new value.
459  *      Returns: SUB_ERROR if break hit (^C).
460  */
461
462 int
463 GetValueFromUser(prompt, pointer)
464 char * prompt, ** pointer;
465 {
466     char buf[BUFSIZ];
467
468     if (PromptWithDefault(prompt, buf, BUFSIZ, *pointer) == -1)
469         return(SUB_ERROR);
470
471 /* 
472  * If these are the same then there is no need to allocate a new string.
473  *
474  * a difference that makes no difference, IS no difference.
475  */
476
477     if (strcmp(buf, *pointer) != 0) { 
478         if (*pointer != NULL)
479             free(*pointer);
480         *pointer = Strsave(buf);
481     }
482     return(SUB_NORMAL);
483 }
484
485 /*      Function Name: GetYesNoValueFromUser
486  *      Description: This function gets a value from a user for the field
487  *                   specified.
488  *      Arguments: prompt - prompt for user.
489  *                 pointer - pointer to default value, will be returned
490  *                          as new value.
491  *      Returns: SUB_ERROR if break hit (^C).
492  */
493
494 int
495 GetYesNoValueFromUser(prompt, pointer)
496 char * prompt, ** pointer;
497 {
498     char user_prompt[BUFSIZ];
499     Bool default_val;
500
501     if ( strcmp (*pointer, DEFAULT_YES) == 0 )
502         default_val = TRUE;
503     else
504         default_val = FALSE;
505     
506     sprintf(user_prompt, "%s (y/n)", prompt);
507
508     switch (YesNoQuestion(user_prompt, default_val)) {
509     case TRUE:
510         if (*pointer != NULL)
511             free(*pointer);
512         *pointer = Strsave(DEFAULT_YES);
513         break;
514     case FALSE:
515         if (*pointer != NULL)
516             free(*pointer);
517         *pointer = Strsave(DEFAULT_NO);
518         break;
519     case -1:
520     default:
521         return(SUB_ERROR);
522     }
523     return(SUB_NORMAL);
524 }
525
526 /*      Function Name: GetFSVal
527  *      Description: asks about a specific filesystem value.
528  *      Arguments: name - string for this type of filesystem.
529  *                 mask - mask for this type of filesystem.
530  *                 current - current filesystem state. (for defaults).
531  *                 new - new filesystem state.
532  *      Returns: TRUE if successful.
533  */
534
535 static Bool
536 GetFSVal(name, mask, current, new)
537 char * name;
538 int mask, current, *new;
539 {
540     char temp_buf[BUFSIZ];
541     sprintf(temp_buf, "Is this a %s filsystem", name);
542     switch (YesNoQuestion(temp_buf, ( (mask & current) == mask) )) {
543     case TRUE:
544         *new |= mask;
545         break;
546     case FALSE:
547         break;                  /* zero by default. */
548     default:
549         return(FALSE);
550     }
551     return(TRUE);
552 }
553
554 /*      Function Name: GetFSTypes
555  *      Description: Allows user to specify filsystem types.
556  *      Arguments: current - current value of filsystem, freed here.
557  *      Returns: SUB_ERROR on ^C.
558  */
559
560 int
561 GetFSTypes(current)
562 char **  current;
563 {
564     int c_value, new_val = 0;   /* current value of filesys type (int). */
565     char ret_value[BUFSIZ];
566
567     if (*current == NULL)
568         c_value = 0;
569     else 
570         c_value = atoi(*current);
571
572     if (GetFSVal("student", SMS_FS_STUDENT, c_value, &new_val) == FALSE)
573         return(SUB_ERROR);
574     if (GetFSVal("faculty", SMS_FS_FACULTY, c_value, &new_val) == FALSE)
575         return(SUB_ERROR);
576     if (GetFSVal("staff", SMS_FS_STAFF, c_value, &new_val) == FALSE)
577         return(SUB_ERROR);
578     if (GetFSVal("miscellaneous", SMS_FS_MISC, c_value, &new_val) == FALSE)
579         return(SUB_ERROR);
580
581     FreeAndClear(current, TRUE);
582     sprintf(ret_value, "%d", new_val);
583     *current = Strsave(ret_value);
584     return(SUB_NORMAL);
585 }
586
587 /*      Function Name: CanonicalizeHostname
588  *      Description: This function takes a machine name and canonicalize's it.
589  *      Arguments: machine - name of the machine to work on.
590  *      Returns: new name or NULL if nameserver returns error
591  */
592
593 char *
594 CanonicalizeHostname(machine)
595 char *machine;
596 {
597     struct hostent *hostinfo;
598
599     hostinfo = gethostbyname(machine);
600 /* If this fails then we just return what we were passed. */
601     if (hostinfo != (struct hostent *) NULL)
602         machine = hostinfo->h_name;
603     return (machine);
604 }
605
606 /*      Function Name: Strsave
607  *      Description: save a string.
608  *      Arguments: string  - the string to save.
609  *      Returns: The malloced string, now safely saved, or NULL.
610  */
611
612 char *
613 Strsave(str)
614 char *str;
615 {
616     register char *newstr = malloc((unsigned) strlen(str) + 1);
617
618     if (newstr == (char *) NULL)
619         return ((char *) NULL);
620     else
621         return (strcpy(newstr, str));
622 }
623
624 /*      Function Name: Print
625  *      Description: prints out all the arguments on a single line.
626  *      Arguments: argc, argv - the standard SMS arguments.
627  *                 callback - the callback function - NOT USED.
628  *      Returns: SMS_CONT
629  */
630
631 /* ARGSUSED */
632 int
633 Print(argc, argv, callback)
634 int argc;
635 char **argv, *callback;
636 {
637     char buf[BUFSIZ];
638     register int i;
639
640     found_some = TRUE;
641     (void) strcpy(buf,argv[0]); /* no newline 'cause Put_message adds one */
642     for (i = 1; i < argc; i++)
643         (void) sprintf(buf,"%s %s",buf,argv[i]);
644     (void) Put_message(buf);
645
646     return (SMS_CONT);
647 }
648
649 /*      Function Name: PrintByType
650  *      Description: This function prints all members of the type specified
651  *                   by the callback arg, unless the callback is NULL, in which
652  *                   case it prints all members.
653  *      Arguments: argc, argc - normal arguments for sms_callback function. 
654  *                 callback - either a type of member or NULL.
655  *      Returns: SMS_CONT or SMS_QUIT.
656  */
657
658 /*ARGSUSED*/
659 int
660 PrintByType(argc, argv, callback)
661 int argc;
662 char **argv, *callback;
663 {
664     if (callback == NULL)
665         return( Print(argc, argv, callback) );
666     if (strcmp(argv[0], callback) == 0) 
667         return( Print(argc, argv, callback) );
668     return(SMS_CONT);
669 }
670
671 /*      Function Name: PrintHelp
672  *      Description: Prints Help Information in a NULL terminated
673  *                   char **.
674  *      Arguments: message.
675  *      Returns: DM_NORMAL.
676  */
677
678 int
679 PrintHelp(message)
680 char ** message;
681 {
682     Print(CountArgs(message), message, (char *) NULL);
683     return(DM_NORMAL);
684 }
685
686 /*      Function Name: Loop
687  *      Description: This function goes through the entire queue, and
688  *                   and executes the given function on each element.
689  *      Arguments: elem - top element of the queue.
690  *                 func - the function to execute.
691  *      Returns: none.
692  */
693
694 void
695 Loop(elem, func)
696 FVoid func;
697 struct qelem * elem;
698 {
699     while (elem != NULL) {
700         char ** info = (char **) elem->q_data;
701         (*func) (info);
702         elem = elem->q_forw;
703     }
704 }
705
706
707 /*      Function Name: QueryLoop
708  *      Description: This functions loops through a queue containing
709  *                   information about some item that we want to perform
710  *                   an operation on, and then calls the correct routine
711  *                   perform that operation.
712  *      Arguments: top - top of the queue of information.
713  *                 print_func - print function.
714  *                 op_function - operation to be performed.
715  *                 query_string - string the prompts the user whether or not
716  *                                to perform this operation.
717  *      Returns: none.
718  *      NOTES:
719  *               print_opt - should expect one arguent, the info array
720  *                           of char *'s.
721  *                           is expected to return the name of the item.
722  *               op_func   - should expect two arguments.
723  *                           1) the info array of char *'s.
724  *                           2) a boolean the is true if there only
725  *                              one item in this queue, used for delete
726  *                              confirmation.
727  *               query_string - this should be of such a form that when the
728  *                              name of the object and '(y/n/q) ?' are appended
729  *                              then it should still make sense, an example is
730  *                              "Delete the list"
731  */
732
733 void
734 QueryLoop(elem, print_func, op_func, query_string)
735 struct qelem *elem;
736 FVoid op_func;
737 FCharStar print_func;
738 char * query_string;
739 {
740     Bool one_item;
741     char temp_buf[BUFSIZ], *name;
742
743     one_item = (QueueCount(elem) == 1);
744     while (elem != NULL) {
745         char **info = (char **) elem->q_data;
746         
747         if (one_item)
748             (*op_func) (info, one_item);
749         else {
750             name = (*print_func) (info); /* call print function. */
751             sprintf(temp_buf,"%s %s (y/n/q)", query_string, name);
752             switch(YesNoQuitQuestion(temp_buf, FALSE)) {
753             case TRUE:
754                 (*op_func) (info, one_item);
755                 break;
756             case FALSE:
757                 break;
758             default:            /* Quit. */
759                 Put_message("Aborting...");
760                 return;
761             }
762         }
763         elem = elem->q_forw;
764     }
765 }
766
767 /*      Function Name: NullPrint
768  *      Description: print function that returns nothing.
769  *      Arguments: info - a pointer to the info array - Not used.
770  *      Returns: none.
771  */
772
773 char *
774 NullPrint(info)
775 char ** info;
776 {
777     return(info[NAME]);
778 }
779
780
781 /*      Function Name: GetTypeValues
782  *      Description: gets legal values for a typed object, keeping a cache
783  *      Arguments: type name
784  *      Returns: argv of values
785  */
786
787 struct qelem *
788 GetTypeValues(tname)
789 char *tname;
790 {
791     int stat;
792     char *argv[3], *p, **pp, *strsave();
793     struct qelem *elem, *oelem;
794     static struct qelem *cache = NULL;
795     struct cache_elem { char *cache_name; struct qelem *cache_data; } *ce;
796
797     for (elem = cache; elem; elem = elem->q_forw) {
798         ce = (struct cache_elem *)elem->q_data;
799         if (!strcmp(ce->cache_name, tname))
800             return(ce->cache_data);
801     }
802
803     argv[0] = tname;
804     argv[1] = "TYPE";
805     argv[2] = "*";
806     elem = NULL;
807     if (stat = do_sms_query("get_alias", 3, argv, StoreInfo, (char *)&elem)) {
808         com_err(program_name, stat, " in GetTypeValues");
809         return(NULL);
810     }
811     oelem = elem;
812     for (elem = QueueTop(elem); elem; elem = elem->q_forw) {
813         pp = (char **) elem->q_data;
814         p = strsave(pp[2]);
815         FreeInfo(pp);
816         elem->q_data = p;
817     }
818     elem = (struct qelem *) malloc(sizeof(struct qelem));
819     ce = (struct cache_elem *) malloc(sizeof(struct cache_elem));
820     ce->cache_name = tname;
821     ce->cache_data = QueueTop(oelem);
822     elem->q_data = (char  *)ce;
823     AddQueue(elem, cache);
824     cache = QueueTop(elem);
825     return(ce->cache_data);
826 }
827
828
829 /*      Function Name: GetTypeFromUser
830  *      Description: gets a typed value from the user
831  *      Arguments: prompt string, type name, buffer pointer
832  *      Returns: 
833  */
834
835 GetTypeFromUser(prompt, tname, pointer)
836 char *prompt;
837 char *tname;
838 char  **pointer;
839 {
840     char def[BUFSIZ], buffer[BUFSIZ], *p, *argv[3];
841     struct qelem *elem;
842     int stat;
843
844     strcpy(def, *pointer);
845     strcpy(buffer, prompt);
846     strcat(buffer, " (");
847     for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
848         strcat(buffer, elem->q_data);
849         if (elem->q_forw)
850             strcat(buffer, ", ");
851     }
852     strcat(buffer, ")");
853     if (strlen(buffer) > 64)
854         sprintf(buffer, "%s (? for help)", prompt);
855     GetValueFromUser(buffer, pointer);
856     if (**pointer == '?') {
857         sprintf(buffer, "Type %s is one of:", tname);
858         Put_message(buffer);
859         for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
860             Put_message(elem->q_data);
861         }
862         *pointer = strsave(def);
863         return(GetTypeFromUser(prompt, tname, pointer));
864     }
865     for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
866         if (!cistrcmp(elem->q_data, *pointer))
867             return(SUB_NORMAL);
868     }
869     sprintf(buffer, "\"%s\" is not a legal value for %s.  Use one of:",
870             *pointer, tname);
871     Put_message(buffer);
872     for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
873         Put_message(elem->q_data);
874     }
875     sprintf(buffer, "Are you sure you want \"%s\" to be a legal %s",
876             *pointer, tname);
877     if (YesNoQuestion("Do you want this to be a new legal value", 0) &&
878         YesNoQuestion(buffer, 0)) {
879         argv[0] = tname;
880         argv[1] = "TYPE";
881         argv[2] = *pointer;
882         for (p = argv[2]; *p; p++)
883             if (islower(*p))
884                 *p = toupper(*p);
885         if (stat = do_sms_query("add_alias", 3, argv, Scream, NULL)) {
886             com_err(program_name, stat, " in add_alias");
887         } else {
888             elem = (struct qelem *) malloc(sizeof(struct qelem));
889             elem->q_data = strsave(*pointer);
890             AddQueue(elem, GetTypeValues(tname));
891             Put_message("Done.");
892         }
893     }
894     *pointer = strsave(def);
895     return(GetTypeFromUser(prompt, tname, pointer));
896 }
897
898
899 do_sms_query(name, argc, argv, proc, hint)
900 char *name;
901 int argc;
902 char **argv;
903 int (*proc)();
904 char *hint;
905 {
906     int status;
907     extern char *whoami;
908
909     status = sms_query(name, argc, argv, proc, hint);
910     if (status != SMS_ABORTED && status != SMS_NOT_CONNECTED)
911       return(status);
912     status = sms_connect();
913     if (status) {
914         com_err(whoami, status, " while re-connecting to server");
915         return(SMS_ABORTED);
916     }
917     status = sms_auth(whoami);
918     if (status) {
919         com_err(whoami, status, " while re-authenticating to server");
920         sms_disconnect();
921         return(SMS_ABORTED);
922     }
923     status = sms_query(name, argc, argv, proc, hint);
924     return(status);
925 }
926
This page took 0.329288 seconds and 3 git commands to generate.