]>
Commit | Line | Data |
---|---|---|
3d8d4b36 | 1 | @Comment($Header$) |
2 | @Make(Manual) | |
3 | @Device(PostScript) | |
4 | @PageFooting(center "Draft of @value(date)") | |
5 | @style(spacing = 1.5, indent 5, FontFamily = TimesRoman, size = 12) | |
6 | @style(LeftMargin 1 inch, RightMargin 1 inch) | |
7 | ||
8 | @Begin(TitlePage) | |
9 | @Begin(TitleBox) | |
10 | @b[The Athena Service Management System] | |
11 | @blankspace ( 1 line ) | |
12 | @b[SMS Client Internals Document] | |
13 | @blankspace ( 1 line ) | |
14 | @i[Chris D. Peterson] | |
15 | @End(TitleBox) | |
16 | @CopyrightNotice(Massachusetts Institute of Technology) | |
17 | @End(TitlePage) | |
18 | ||
19 | @Chapter(Introduction) | |
20 | ||
21 | The @i(Sms Client) program was designed to allow ordinary users a | |
22 | simple method of performing all database manipulations common here at | |
23 | @i(Project Athena). The user interacts with the program through a | |
24 | terminal based menu. This allows use of sms on a wide variety of | |
25 | platforms. Unlike previous packages where many different clients were | |
26 | necessary to perform all these tasks, the @i(Sms Client) program | |
27 | allows all operations to be performed from one application. This | |
28 | saves the user time and effort by having all common operations in one | |
29 | convenient place. I have spent a good deal of time cleaning up the | |
30 | code to make it uniform throughout the entire client and am writing | |
31 | this document to explain some of the decisions. My hope is that this | |
32 | will allow you to add features with a minimum of amount effort, as | |
33 | well as easing the transition between your code and mine. | |
34 | ||
35 | @Chapter(Overview) | |
36 | ||
37 | This section presents general concepts that hold throughout the code. | |
38 | Some of the items may seem trivial, but together they keep the code | |
39 | consistent and understandable. | |
40 | ||
41 | @Section(File Organization) | |
42 | ||
43 | Most files correspond to one type of item in the @i(SMS) database, | |
44 | such as lists, machines, clusters, etc. These files are self | |
45 | contained so that you can pick and choose which of these you would | |
46 | like to use in any new client you decide to build. There are a few | |
47 | special files that do not follow this convention. | |
48 | @begin(description) | |
49 | ||
50 | @i[util.c]@\Utility functions used by many of the other files. | |
51 | ||
52 | @i[menu.c]@\Menu definitions for the entire application. | |
53 | ||
54 | @i[main.c]@\The main driver that handles application start up. | |
55 | ||
56 | @i[delete.c]@\Functions that handle deletion of lists and users. | |
57 | ||
58 | @i[globals.c]@\All global variable definitions. | |
59 | @end(description) | |
60 | ||
61 | @Section(Command Organization) | |
62 | ||
63 | Each menu item has one and only one function associated with it, | |
64 | although the same function may be used by two identical menu items. | |
65 | The arguments passed to these functions from the menu package are an | |
66 | array of character strings and the number of strings in the array. | |
67 | The first argument in the array (argv[0]) is the name of the menu item | |
68 | that has been selected. Thus the actual user specified arguments are | |
69 | passed starting at the second argument (argv[1]). | |
70 | ||
71 | @Section(Naming and Comment Conventions) | |
72 | ||
73 | @Index(Variables) | |
74 | @Index(Functions) | |
75 | ||
76 | I use all capital letters for constants, while variables are all small | |
77 | letters, and functions are represented by mixing capital and small | |
78 | letters, capitalizing each word in the function name. I use long | |
79 | function names as functions are usually not called often, and long | |
80 | names are much more descriptive. There are a few functions that do | |
81 | not follow the mixed caps and small convention, these are generally | |
82 | those I called out of @i(SMSLib), @i[CLib], or the menu package. | |
83 | ||
84 | @Index(Comments) | |
85 | ||
86 | Each file has a header containing the Revision Control System (RCS) | |
87 | modification time and some history information, as well as some | |
88 | information about the file. The template for this is a file named | |
89 | 'header'. Each function has a comment preceding it describing the | |
90 | function, all variables used, and the value that this function | |
91 | returns. Notes of special concern for this function are also listed | |
92 | here. The function template is in a file called, surprisingly enough, | |
93 | 'function'. Other comments are placed where appropriate. | |
94 | ||
95 | @Section(Retrieving data from the server) | |
96 | @Label(queue-def) | |
97 | ||
98 | Since one of the limitations of @i[SMS] is that no query may be | |
99 | executed recursively, all information returned by a query must be | |
100 | received before another query can be executed. To facilitate | |
101 | programming simplicity I store the information returned from each | |
102 | query into a queue as soon as it is received. This allows a simple, | |
103 | although rather memory intensive, method of getting around this | |
104 | problem. Another advantage of this method is that since no operations | |
105 | are taking place on the data as it comes back from the server the time | |
106 | that the server spends sending the data to the clients is kept to a | |
107 | minimum, a necessity in large-scale environments. | |
108 | ||
109 | @Chapter[Application Wide Definitions] | |
110 | ||
111 | This section will cover all items that cross function boundaries, | |
112 | including global variables, structure definitions, and constant | |
113 | definitions. | |
114 | ||
115 | @Section[Global Variables] | |
116 | ||
117 | @Label(Globals)The @i[SMS Client] has a few global variables. Since | |
118 | you will run into them throughout the application they warrant mention | |
119 | here. | |
120 | @Index(program_name) | |
121 | @Index(user) | |
122 | @Index(verbose) | |
123 | @Index(found_some) | |
124 | @begin(description) | |
125 | @i[program_name] @\This is the name of the program currently being | |
126 | executed, and is retrieved from argv[0] in @i[main.c]. | |
127 | ||
128 | @i[user] @\This is the name of the user currently executing the program, | |
129 | and is also set in @i[main.c]. | |
130 | ||
131 | @i[verbose] @\This is a boolean value that, when FALSE turns off the | |
132 | delete confirmation. For more information see section @ref(confirm). | |
133 | ||
134 | @i[found_some] @\This is a boolean that allows the @b[PrintByType()] | |
135 | (sect. @ref(pbytype) function to be able to communicate with the | |
136 | function calling the query that invokes it, as well as among calls to | |
137 | itself. | |
138 | @end(description) | |
139 | ||
140 | @Section[Structure Definitions] | |
141 | ||
142 | @Index(qelem) | |
143 | ||
144 | The only global structure definition is the one for the queue element. | |
145 | What I will refer to as the queue is actually a doubly linked list | |
146 | that all my queue manipulation functions (sect. @ref(queuecount)) | |
147 | treat as a true queue. | |
148 | ||
149 | @begin(Format) | |
150 | struct qelem { | |
151 | struct qelem *q_forw; | |
152 | struct qelem *q_back; | |
153 | char * q_data; | |
154 | }; | |
155 | @end(Format) | |
156 | ||
157 | The queue data need not be a string; @i[char *] is used as a generic | |
158 | pointer here. | |
159 | ||
160 | @Section[Definitions] | |
161 | ||
162 | @Index(FVoid) | |
163 | @Index(FInt) | |
164 | @Index(FCharStar) | |
165 | ||
166 | For readability there are a few important global definitions. | |
167 | Function pointers in @i[C] tend to be tough to read so I have typedef'ed the | |
168 | function pointers; FVoid, FInt, and FCharStar. These refer to functions | |
169 | that return nothing, integers, and strings, respectively. | |
170 | ||
171 | @Index(MOD_FORMAT) | |
172 | ||
173 | Another global definition, MOD_FORMAT, is used to format the | |
174 | modification information of an item for printing. It is important that | |
175 | all modification information is presented to the user with this | |
176 | format, to keep the @i[SMS Client] consistent. | |
177 | ||
178 | @Index(Infodefs) | |
179 | @Label(infodefs) | |
180 | ||
181 | Information about an item in the database is returned by sms_query() | |
182 | in an array of strings. Remembering what @i[info][7] is can be | |
183 | difficult and it is possible that in future updates of the @i[SMS | |
184 | Server] @i[info][7] may contain completely different information. To | |
185 | solve both of these problems I have created a set of definitions for | |
186 | each element of the argument list of each data type that the @i[SMS | |
187 | Client] uses. A list of these can be found in appendix | |
188 | @ref(a_infodefs), as well as the file @i[infodefs.h]. | |
189 | ||
190 | @Chapter(Utility Functions) | |
191 | ||
192 | I created several utility functions that handle common operations used | |
193 | by many of the functions in the @i[SMS Client]. These functions | |
194 | perform things like the storing of information in a queue as it comes | |
195 | in from the @i(SMS Server), queue manipulation, querying the user, | |
196 | and printing information. | |
197 | ||
198 | @Section(Storing and Freeing the Queue) | |
199 | ||
200 | As noted in section @ref(queue-def), all incoming information from the | |
201 | @i(SMS Server) is stored in a queue as soon as it is received. The | |
202 | function that does this, @b[StoreInfo()], as well the one that frees the | |
203 | queue when we are finished with it, @b[FreeQueue()], are described here. | |
204 | ||
205 | @Index(StoreInfo) | |
206 | ||
207 | Use the function @b[StoreInfo()] to store all information received | |
208 | from the @i[SMS Server] into a queue. Space for this queue is | |
209 | dynamically allocated using malloc(). The actual information is | |
210 | stored in a NULL terminated array of strings. The number of strings | |
211 | in this array can be easily found with the function @b[CountArgs()] | |
212 | (sect. @ref(countargs)). | |
213 | @begin(format) | |
214 | ||
215 | int | |
216 | StoreInfo(@i[argc, argv, data]) | |
217 | int @i[argc]; | |
218 | char ** @i[argv]; | |
219 | char * @i[data]; | |
220 | @end(format) | |
221 | @begin(Description) | |
222 | ||
223 | @i[argc] @\The number of strings passed in argv. | |
224 | ||
225 | @i[argv] @\An array of strings to be stored in the queue. | |
226 | ||
227 | @i[data] @\A pointer to the previous element in this queue, or NULL if@\it | |
228 | should create a new queue. This is updated with each call to @b[StoreInfo()] | |
229 | and the value associated with this pointer is the last element in the | |
230 | queue. | |
231 | ||
232 | @end(Description) | |
233 | @blankspace(1 line) | |
234 | Here is an example of an @i[SMS] query that would use this function to store | |
235 | its arguments. | |
236 | ||
237 | @Begin[Format] | |
238 | ||
239 | struct qelem * elem = NULL; | |
240 | status = sms_query("query handle", num_args, args, StoreInfo, &elem); | |
241 | ||
242 | @End[Format] | |
243 | ||
244 | The variable elem must initially be set to NULL, or @b[StoreInfo()] | |
245 | will try to add the first element of this queue to a currently | |
246 | existing queue that is really just the garbage left on the stack. The | |
247 | value of elem when this query returns is the last element in the | |
248 | queue, and the function @b[QueueTop()] (section @ref(queuetop)) should | |
249 | be used to get the top element of the queue, which is expected by most | |
250 | other queue operations. | |
251 | ||
252 | @Center(________) | |
253 | ||
254 | @Index(FreeQueue) | |
255 | ||
256 | To free the queue and any data associated with it, the function | |
257 | @b[FreeQueue()] is used. This function expects a queue similar to the | |
258 | one created by the @b[StoreInfo()] function. @b[FreeQueue()] frees | |
259 | all memory associated with this particular queue, and will do bad | |
260 | things if the information stored in the queue is not a NULL | |
261 | terminated, allocated array of allocated strings. All allocations | |
262 | are assumed to have been done with the @i[C] malloc() function. | |
263 | ||
264 | @begin(Format) | |
265 | ||
266 | void | |
267 | FreeQueue(@i[elem]) | |
268 | struct qelem * @i[elem]; | |
269 | @end(Format) | |
270 | @begin(Description) | |
271 | ||
272 | @i[elem] @\Any element in the queue. The entire queue will be freed | |
273 | regardless of the element passed. | |
274 | @end(Description) | |
275 | ||
276 | @Section[Queue Manipulation] | |
277 | ||
278 | The following group of functions perform common tasks that involve | |
279 | retrieving information from or manipulating a queue. All these functions | |
280 | will handle NULL passed to them in an appropriate manner, either returning | |
281 | zero, or NULL. | |
282 | ||
283 | @Label(queuetop) | |
284 | @Index(QueueTop) | |
285 | ||
286 | To find the top element of a queue use the function @b[QueueTop()]. | |
287 | ||
288 | @begin(Format) | |
289 | ||
290 | struct qelem * | |
291 | QueueTop(@i[elem]) | |
292 | struct qelem * @i[elem]; | |
293 | @end(Format) | |
294 | @begin(Description) | |
295 | @i[elem] @\Any element in the queue. | |
296 | @end(Description) | |
297 | ||
298 | @blankspace(1 line) | |
299 | ||
300 | @b[QueueTop()] returns the top element of the queue defined by its | |
301 | argument. | |
302 | ||
303 | @Center(________) | |
304 | ||
305 | ||
306 | @label(queuecount) | |
307 | @Index(QueueCount) | |
308 | ||
309 | The function @b[QueueCount()] counts the number of elements in a queue. | |
310 | ||
311 | @begin(Format) | |
312 | int | |
313 | QueueCount(@i[elem]) | |
314 | struct qelem * @i[elem]; | |
315 | @end(Format) | |
316 | @begin(Description) | |
317 | @i[elem] @\Any element in the queue. | |
318 | @end(Description) | |
319 | ||
320 | @blankspace(1 line) | |
321 | ||
322 | @b[QueueCount()] returns the number of elements in the queue defined | |
323 | by it argument, it need not be the top element, any | |
324 | element will do. | |
325 | ||
326 | @Section[Array Manipulation] | |
327 | ||
328 | The arrays of strings have some manipulation functions of their own. | |
329 | All arrays used in the @i[SMS Client] are assumed to be NULL terminated. | |
330 | In general this is no problem as @b[StoreInfo()] creates NULL terminated | |
331 | arrays. | |
332 | ||
333 | @Label(countargs) | |
334 | @Index(CountArgs) | |
335 | ||
336 | @b[CountArgs()] counts the number of elements in a NULL | |
337 | terminated array of strings. | |
338 | ||
339 | @begin(Format) | |
340 | int | |
341 | CountArgs(@i[info]) | |
342 | char ** @i[info]; | |
343 | @end(Format) | |
344 | @begin(description) | |
345 | info @\A NULL terminated array of character strings. | |
346 | @end(description) | |
347 | ||
348 | @blankspace(1 line) | |
349 | ||
350 | @b[CountArgs()] returns the number of strings in the NULL terminated array | |
351 | of strings passed to it. A common use of @b[CountArgs()] is to tell | |
352 | sms_query() how many items are in the argument list passed to the | |
353 | query, as shown below. | |
354 | @begin(format) | |
355 | ||
356 | status = sms_query("query", CountArgs(args), args, StoreInfo, &elem); | |
357 | @end(format) | |
358 | ||
359 | @Center(________) | |
360 | @Index(FreeInfo) | |
361 | ||
362 | To free all elements in a NULL terminated array of strings use the | |
363 | @b[FreeInfo()] function. | |
364 | ||
365 | @begin(Format) | |
366 | void | |
367 | FreeInfo(@i[info]) | |
368 | char ** @i[info]; | |
369 | @end(Format) | |
370 | ||
371 | @begin(Description) | |
372 | ||
373 | @i[info] @\A NULL terminated array of strings allocated with malloc(), | |
374 | to be freed. | |
375 | @end(Description) | |
376 | ||
377 | @Center(________) | |
378 | ||
379 | ||
380 | @Label(sinn) | |
381 | @Index(SlipInNewName) | |
382 | ||
383 | Most update queries use the same argument list that is returned by the | |
384 | information query for the database item is question. For instance, | |
385 | update_list uses almost the same arguments that get_list_info returns. | |
386 | The difference in these arguments lists is that update queries expect | |
387 | the new name to be the second element in the list. The | |
388 | @b[SlipInNewName()] function adds the new name as the second argument | |
389 | in the list passed to it, bumping all the other arguments down one | |
390 | slot. | |
391 | ||
392 | @begin(Format) | |
393 | void | |
394 | SlipInNewName(@i[info, name]) | |
395 | char ** @i[info]; | |
396 | char * @i[name]; | |
397 | @end(Format) | |
398 | ||
399 | @begin(Description) | |
400 | @i[info] @\A NULL terminated array of strings. | |
401 | ||
402 | @i[name] @\The new name to be slipped into @i[info] at position @i[info][1]. | |
403 | @end(Description) | |
404 | ||
405 | @Blankspace(1 line) | |
406 | ||
407 | Once @b[SlipInNewName()] has been performed on a argument list do not | |
408 | try to use the definitions for that type of element, as they will be | |
409 | wrong. Don't use @i[info][L_ACE] to try to retrieve the ace of the | |
410 | list, as this function has shifted all the items except the old name | |
411 | down one element. | |
412 | ||
413 | @Section[Special Queue Functions] | |
414 | ||
415 | The following two functions @b[Loop()] and @b[QueryLoop()] are used | |
416 | when an operation needs to be performed on every element of the queue. | |
417 | The difference between these two functions is that @b[QueryLoop()] | |
418 | presents a method of asking the user if the operation should be | |
419 | performed, while @b[Loop()] just performs it on each element. | |
420 | ||
421 | @Index(Loop) | |
422 | @Index(LoopFunc) | |
423 | ||
424 | To perform an operation on every element in the queue use the | |
425 | @b[Loop()] function. | |
426 | ||
427 | @begin(Format) | |
428 | void | |
429 | Loop(@i[top, LoopFunc]) | |
430 | struct qelem * @i[top]; | |
431 | FVoid @i[LoopFunc]; | |
432 | @end(Format) | |
433 | @begin(Description) | |
434 | @i[top] @\The top element of the queue. | |
435 | ||
436 | @i[LoopFunc] @\The function to perform on each element of the queue. | |
437 | @end(Description) | |
438 | ||
439 | @blankspace(1 line) | |
440 | ||
441 | The @i[LoopFunc] has the following format and is performed with the | |
442 | data of each element in the queue. | |
443 | ||
444 | @begin(Format) | |
445 | void | |
446 | LoopFunc(@i[info]) | |
447 | char ** @i[info]; | |
448 | @end(Format) | |
449 | @begin(Description) | |
450 | @i[info] @\The array of strings that is stored as the @i[q_data] of each element | |
451 | of the queue. | |
452 | @end(Description) | |
453 | ||
454 | @blankspace(1 line) | |
455 | ||
456 | No provision is made for the @i[LoopFunc] function to return a value. | |
457 | ||
458 | @Center(________) | |
459 | ||
460 | ||
461 | @Label(qloop) | |
462 | @Index(QueryLoop) | |
463 | @Index(PrintFunc) | |
464 | @Index(QueryLoopFunc) | |
465 | ||
466 | If you want to query the user before your function is called on each | |
467 | element of the queue, use the @b[QueryLoop()] routine. | |
468 | ||
469 | @Begin[Format] | |
470 | void | |
471 | QueryLoop(@i[top, PrintFunc, QueryLoopFunc, query_string]) | |
472 | struct qelem * @i[top]; | |
473 | FCharStar @i[PrintFunc]; | |
474 | FVoid @i[QueryLoopFunc]; | |
475 | char * @i[query_string]; | |
476 | @End[Format] | |
477 | @begin(Description) | |
478 | @i[top] @\The top element of the queue. | |
479 | ||
480 | @i[PrintFunc] @\The function that will print information to the user | |
481 | about each specific element of the queue, its return value is appended | |
482 | to the query string, and asked as a @b[YesNoQuitQuestion()] (sect. | |
483 | @ref[ynqquestion]) of the user. | |
484 | ||
485 | @i[QueryLoopFunc] @\This function is called if the user answers yes to the | |
486 | question asked of him, or if there is only one element in the queue. | |
487 | ||
488 | query_string @\Basic prompt for the @b[YesNoQuitQuestion()] asked of | |
489 | the user, the string returned by the @i[PrintFunc] is appended to this | |
490 | string to form the full prompt. | |
491 | @end(Description) | |
492 | ||
493 | @blankspace(1 line) | |
494 | ||
495 | @Index(PrintFunc) | |
496 | ||
497 | @i[PrintFunc] is called using the data stored in each element of the | |
498 | queue, unless there is only one element in the queue, in which case | |
499 | @i[QueryLoopFunc] is called without querying the user. @i[PrintFunc] | |
500 | has the following format. | |
501 | ||
502 | @begin(Format) | |
503 | char * | |
504 | PrintFunc(@i[info]) | |
505 | char ** @i[info]; | |
506 | @end(Format) | |
507 | @begin(Description) | |
508 | ||
509 | @i[info] @\The array of strings that is stored as the @i[q_data] of | |
510 | each element in the queue. | |
511 | @end(Description) | |
512 | ||
513 | @blankspace(1 line) | |
514 | ||
515 | The @i[PrintFunc] returns a string that is to be appended to the | |
516 | query_string() of the @b[QueryLoop()] function. This string is then | |
517 | used to ask the user if the @i[QueryLoopFunc] should be called. The | |
518 | return string from the @i[PrintFunc] is usually just the name of the | |
519 | item contained in the data field of each queue element. | |
520 | ||
521 | @Index(QueryLoopFunc) | |
522 | ||
523 | @i[QueryLoopFunc] is called each time the user answers 'yes' to the | |
524 | question asked of him, with the current element's information. The | |
525 | only exception to this is if the queue has only one element, in which | |
526 | case @i[QueryLoopFunc] is called immediately with @i[one_item] set to TRUE. | |
527 | @i[QueryLoopFunc] has this format. | |
528 | ||
529 | @begin(Format) | |
530 | void | |
531 | QueryLoopFunc(@i[info, one_item]) | |
532 | char ** @i[info]; | |
533 | Bool @i[one_item] | |
534 | @end(Format) | |
535 | @begin(Description) | |
536 | ||
537 | @i[info] @\The array of strings that is stored as the @i[q_data] of | |
538 | each element in the queue. | |
539 | ||
540 | @i[one_item] @\This is TRUE if this function is being called without asking | |
541 | the user, because there is only one item in the queue. | |
542 | @end(Description) | |
543 | ||
544 | @blankspace(1 line) | |
545 | ||
546 | No provision is made for the @b[QueryLoop()] function to return a value. | |
547 | ||
548 | @b[QueryLoop()] automatically performs the @i[QueryLoopFunc] without | |
549 | calling the @i[PrintFunc] if there is only one item in the queue, but | |
550 | the @i[QueryLoopFunc] is alerted to this fact by the @i[one_item] | |
551 | variable. If there is more than one item on the queue the the | |
552 | @i[PrintFunc] is executed, and the user is prompted, as in the | |
553 | following example. | |
554 | ||
555 | @begin(format) | |
556 | @tabset(10) | |
557 | ||
558 | @b[Source Code:] | |
559 | ||
560 | QueryLoop(top_of_queue, PrintListInfo, UpdateList, "Would you like to update list"); | |
561 | ||
562 | @tabclear() | |
563 | @tabset(50, 60) | |
564 | @b[User Sees:] | |
565 | ||
566 | List: foo @\Members: @\35 | |
567 | This list is a group@\GID: @\9803 | |
568 | ||
569 | Would you like to update list foo (y/n/q) [n]: | |
570 | @end(format) | |
571 | ||
572 | This question is asked of the user for every item in the queue, and if | |
573 | the answer is yes then the @i[QueryLoopFunc] is called. If the answer | |
574 | is no then it continues onto the next element, quit drops out of the | |
575 | loop entirely. | |
576 | ||
577 | @Index(NullPrint) | |
578 | ||
579 | The return value of the @i[PrintFunc] is the name of the list in the | |
580 | above example (i.e. foo). A simple print function, @b[Nullprint()], | |
581 | is detailed in section @ref(nullprint). If @b[Nullprint()] were used | |
582 | in the above example following would be the result: | |
583 | ||
584 | @blankspace(1 line) | |
585 | ||
586 | @begin(Format) | |
587 | Would you like to update list foo (y/n/q) [n]: | |
588 | @end(Format) | |
589 | ||
590 | @Section[Generic @i{SMS} query routines] | |
591 | ||
592 | These two very common routines are used as sms_query() callbacks. | |
593 | Using these common routines helps other programmers immediately | |
594 | identify what type of tuples your query is expected to return. | |
595 | ||
596 | @Index(Scream) | |
597 | ||
598 | Use the @b[Scream()] function when you do not expect any tuples to be | |
599 | returned by the @i[SMS Server], as in an update, add, or delete query. | |
600 | ||
601 | @begin(Format) | |
602 | int | |
603 | Scream() | |
604 | @end(Format) | |
605 | ||
606 | A Sample use of this function. | |
607 | ||
608 | @begin(Format) | |
609 | status = sms_query("update_list", CountArgs(args), args, Scream, NULL); | |
610 | @end(Format) | |
611 | ||
612 | @Center(________) | |
613 | ||
614 | ||
615 | @Index(NullFunc) | |
616 | ||
617 | @b[NullFunc()] does nothing at all with the tuples, it just ignores them. | |
618 | ||
619 | @begin(Format) | |
620 | int | |
621 | NullFunc() | |
622 | @end(Format) | |
623 | ||
624 | @b[NullFunc()] is useful when you are expecting tuples to be returned, | |
625 | but are not interested in their contents, I used it when I was testing | |
626 | for existence of a list by performing a count_members_of_list query | |
627 | and then testing the return value, but was not interested in the | |
628 | tuples. A sample use of this @b[NullFunc()]. | |
629 | ||
630 | @begin(Format) | |
631 | status = sms_query("get_list_info", CountArgs(args), args, NullFunc, NULL); | |
632 | @end(Format) | |
633 | ||
634 | @Section[Retrieving User Input] | |
635 | ||
636 | To keep a consistent user interface across the entire application, the | |
637 | @i[SMS Client] uses the following functions to handle most user input. | |
638 | The only other accepted method of retrieving user input is by making | |
639 | a call to @b[Prompt_input()], which is in the menu library, and the | |
640 | basis for all these functions. | |
641 | ||
642 | @Index(PromptWithDefault) | |
643 | ||
644 | Use @b[PromptWithDefault()] when you need to prompt the user for a value | |
645 | and you want to provide him with a default value. | |
646 | ||
647 | @begin(Format) | |
648 | int | |
649 | PromptWithDefault(@i[prompt, buf, buflen, def]) | |
650 | char * @i[prompt], * @i[buf]; | |
651 | int @i[buflen]; | |
652 | char * @i[def]; | |
653 | @end(Format) | |
654 | ||
655 | @begin(Description) | |
656 | prompt @\The string to prompt the user with. | |
657 | ||
658 | buf @\The buffer to return the answer in. | |
659 | ||
660 | buflen @\The length of the return buffer. | |
661 | ||
662 | def @\The default return value (if NULL then "" is the default). | |
663 | ||
664 | @End[Description] | |
665 | ||
666 | @Blankspace( 1 line) | |
667 | ||
668 | A typical call to this function is as follows: | |
669 | @begin(format) | |
670 | ||
671 | @b[Source Code:] | |
672 | ||
673 | PromptWithDefault("Input a value for the string", buf, BUFSIZ, "foo"); | |
674 | ||
675 | @b[User Sees:] | |
676 | ||
677 | Input a value for the string [foo]: | |
678 | ||
679 | @end(format) | |
680 | ||
681 | @b[PromptWithDefault()] will return (-1) if the user breaks out of this | |
682 | prompt with control-C or some other break character. | |
683 | ||
684 | @Center(________) | |
685 | ||
686 | ||
687 | @Label(ynquestion) | |
688 | @Index(YesNoQuestion) | |
689 | ||
690 | @b[YesNoQuestion()] is used to ask the user a question that is best | |
691 | answered with a response of either yes or no. It also gives the user | |
692 | a default value in the same form as @b[PromptWithDefault()]. | |
693 | ||
694 | @begin(Format) | |
695 | Bool | |
696 | YesNoQuestion(@i[prompt, bool_def]) | |
697 | char @i[*prompt]; | |
698 | Bool @i[bool_def]; | |
699 | @end(Format) | |
700 | ||
701 | @begin(Description) | |
702 | @i[prompt] @\The string to prompt the user with. | |
703 | ||
704 | @i[bool_def] @\The default value, either TRUE or FALSE. | |
705 | @end(Description) | |
706 | ||
707 | @blankspace(1 line) | |
708 | ||
709 | @b[YesNoQuestion()] returns either TRUE or FALSE, or possibly (-1) on | |
710 | a break by the user. The only accepted values from the user are 'y', | |
711 | 'Y', 'n', and 'N'. All other values prompt the user with "Please | |
712 | answer 'y' or 'n'." and ask the question again. | |
713 | ||
714 | @Center(________) | |
715 | ||
716 | ||
717 | @Label(ynqquestion) | |
718 | @Index(YesNoQuitQuestion) | |
719 | ||
720 | Use @b[YesNoQuitQuestion()] when you want the user to have the option to | |
721 | quit as well as answer yes or no. | |
722 | ||
723 | @begin(Format) | |
724 | Bool | |
725 | YesNoQuitQuestion(@i[prompt, bool_def]) | |
726 | char @i[*prompt]; | |
727 | Bool @i[bool_def]; | |
728 | @end(Format) | |
729 | ||
730 | @begin(Description) | |
731 | ||
732 | @i[prompt] @\The string to prompt the user with. | |
733 | ||
734 | @i[bool_def] @\The default value, either TRUE or FALSE. | |
735 | @end(Description) | |
736 | ||
737 | @blankspace(1 line) | |
738 | ||
739 | @b[YesNoQuitQuestion()] is very similar to @b[YesNoQuestion()], in | |
740 | fact the only difference is that this function interprets the keys 'q' | |
741 | and 'Q' the same as hitting a break, causing | |
742 | @b[YesNoQuitQuestion()] to return (-1). | |
743 | ||
744 | @Center(________) | |
745 | ||
746 | ||
747 | @Label(confirm) | |
748 | @Index(Confirm) | |
749 | ||
750 | When you want to ask the user for delete confirmation use the @b[Confirm()] | |
751 | function. | |
752 | ||
753 | @begin(Format) | |
754 | Bool | |
755 | Confirm(@i[prompt]) | |
756 | char * @i[prompt]; | |
757 | @end(Format) | |
758 | @begin(Description) | |
759 | @i[prompt] @\The string to prompt the user with. | |
760 | @end(Description) | |
761 | ||
762 | @blankspace(1 line) | |
763 | ||
764 | @b[Confirm()] is a specialized user input function. This function is | |
765 | meant to be used only when making delete confirmation. It will | |
766 | immediately return TRUE if the verbose global variable (see section | |
767 | @ref(globals)) is FALSE, implying that no confirmation is wanted. | |
768 | Otherwise it asks the user a @b[YesNoQuestion()] using its argument as | |
769 | the prompt, with a default value of FALSE. If the user answers yes | |
770 | then the function will return TRUE, otherwise FALSE is returned. | |
771 | ||
772 | @Center(________) | |
773 | ||
774 | ||
775 | @Label(gvfu) | |
776 | @Index(GetValueFromUser) | |
777 | ||
778 | The @b[GetValueFromUser()] routine is used to update a string that was | |
779 | previously allocated with malloc(). | |
780 | ||
781 | @begin(format) | |
782 | int | |
783 | GetValueFromUser(@i[prompt, pointer]) | |
784 | char * @i[prompt], ** pointer; | |
785 | @end(format) | |
786 | @begin(Description) | |
787 | @i[prompt] @\The string to prompt the user with. | |
788 | ||
789 | @i[pointer] @\A pointer to the malloced item that is to be updated, or a | |
790 | pointer to NULL. | |
791 | @end(Description) | |
792 | ||
793 | @Blankspace( 1 line ) | |
794 | ||
795 | @b[GetValueFromUser()] returns SUB_ERROR if the user broke out of the | |
796 | prompt with control-C, else SUB_NORMAL. The old value is freed, | |
797 | unless it is NULL, and the new value is allocated and pointed to by | |
798 | @i[pointer]. | |
799 | ||
800 | @Center(________) | |
801 | ||
802 | ||
803 | @Index(GetYesNoValueFromUser) | |
804 | ||
805 | If the value to be updated is an @i[SMS] style boolean ("0" or "1") | |
806 | then use the the @b[GetYesNoValueFromUser()] function, which asks the | |
807 | user a @b[YesNoQuestion()]. | |
808 | ||
809 | @begin(Format) | |
810 | int | |
811 | GetYesNoValueFromUser(@i[prompt, pointer]) | |
812 | char * @i[prompt], ** @i[pointer]; | |
813 | @end(Format) | |
814 | ||
815 | @begin(Description) | |
816 | @i[prompt] @\The string to prompt the user with. | |
817 | ||
818 | @i[pointer] @\A pointer to the malloced item that is to be updated, or a | |
819 | pointer to NULL. | |
820 | @end(Description) | |
821 | ||
822 | @Blankspace( 1 line) | |
823 | ||
824 | @b[GetYesNoValueFromUser()] also returns SUB_ERROR if the user broke | |
825 | out of the prompt with control-C, and SUB_NORMAL otherwise. | |
826 | @i[pointer] is freed - Unless it is NULL - and reset to point to a | |
827 | properly allocated value of "0" or "1" depending upon the user's answer | |
828 | to the question. | |
829 | ||
830 | @Center(________) | |
831 | ||
832 | ||
833 | @Index(GetFSTypes) | |
834 | ||
835 | The @i[SMS Server] expects file types to be passed as an integer bit | |
836 | mask. Use the @b[GetFSTypes()] function to query the user about the | |
837 | new value of this field. | |
838 | ||
839 | @begin(Format) | |
840 | int | |
841 | GetFSTypes(@i[pointer]) | |
842 | char ** @i[pointer]; | |
843 | @end(Format) | |
844 | ||
845 | @begin(Description) | |
846 | @i[pointer] @\A pointer to the current allocated filesystem type that | |
847 | is to be updated, or a pointer to NULL. | |
848 | @end(Description) | |
849 | ||
850 | @Blankspace( 1 line) | |
851 | ||
852 | @b[GetFSTypes()] returns SUB_ERROR if the user broke out of the prompt | |
853 | with control-C, and SUB_NORMAL otherwise. It also constructs the | |
854 | correct bit field by asking the user about each type, providing a | |
855 | default value, of course. The new filesystem type is passed back as | |
856 | the new value pointed to by @i[pointer]. If non-NULL the old pointer | |
857 | is freed. | |
858 | ||
859 | @Section[Printing Routines] | |
860 | ||
861 | Here are a few general printing routines. Most printing is done with | |
862 | routines that are specific to the type of database item we are dealing | |
863 | with, but these few printing functions are general enough to describe | |
864 | here. | |
865 | ||
866 | @Label(print) | |
867 | @Index(Print) | |
868 | ||
869 | Use the @b[Print()] function to print out all elements in each tuple | |
870 | returned by a call to sms_query(). | |
871 | ||
872 | @begin(Format) | |
873 | int | |
874 | Print(@i[argc, argv, callback]); | |
875 | int @i[argc]; | |
876 | char ** @i[argv], * @i[callback]; | |
877 | @end(Format) | |
878 | ||
879 | @begin(Description) | |
880 | @i[argc] @\The number if strings passed in argv. | |
881 | ||
882 | @i[argv] @\An array of strings that is the data to be stored in the queue. | |
883 | ||
884 | @i[callback] @\Not Used. | |
885 | @end(Description) | |
886 | ||
887 | @blankspace(1 line) | |
888 | ||
889 | @b[Print()] returns SMS_CONT. Every time this function is called it | |
890 | sets the global variable @i[found_some] to TRUE. | |
891 | ||
892 | @Center(________) | |
893 | ||
894 | @Label(pbytype) | |
895 | @Index(PrintByType) | |
896 | ||
897 | If you want something a bit more specialized then try | |
898 | @b[PrintByType()]. If a string compare of @i[argv][0] and | |
899 | @i[callback] shows them to be equal then the tuple is printed. If | |
900 | @i[callback] is NULL then it acts exactly like @b[Print()]. | |
901 | ||
902 | @begin(Format) | |
903 | int | |
904 | PrintByType(@i[argc, argv, callback]); | |
905 | int @i[argc]; | |
906 | char ** @i[argv], * @i[callback]; | |
907 | @end(Format) | |
908 | ||
909 | @begin(Description) | |
910 | @i[argc] @\The number if strings passed in argv. | |
911 | ||
912 | @i[argv] @\An array of strings that is the data to be stored in the queue. | |
913 | ||
914 | @i[callback] @\@i[Argv][0] is compared to this with strcmp() and if | |
915 | they are equal then the tuple printed. In the special case where | |
916 | callback is NULL all tuples are printed. | |
917 | @end(Description) | |
918 | ||
919 | @blankspace(1 line) | |
920 | ||
921 | @b[PrintByType()] returns SMS_CONT. Every time this function is | |
922 | called it sets the global variable found_some to TRUE. | |
923 | ||
924 | @Center(________) | |
925 | ||
926 | ||
927 | @Index(PrintHelp) | |
928 | ||
929 | If the help information is stored in a NULL terminated array of strings | |
930 | then use the @b[PrintHelp()] function to print the information for the user. | |
931 | ||
932 | @begin(Format) | |
933 | int | |
934 | PrintHelp(@i[message]) | |
935 | char ** @i[message]; | |
936 | @end(Format) | |
937 | ||
938 | @begin(Description) | |
939 | @i[message] @\The help message stored in a NULL terminated array of strings. | |
940 | @end(Description) | |
941 | ||
942 | @blankspace(1 line) | |
943 | ||
944 | @b[PrintHelp()] returns DM_NORMAL to allow help routines to remain as | |
945 | simple as possible. | |
946 | ||
947 | @Center(________) | |
948 | ||
949 | ||
950 | @Index(NullPrint) | |
951 | @Label(nullprint) | |
952 | ||
953 | When using the @b[QueryLoop()] function (sect. @ref(qloop)) there are | |
954 | times when all the @i[PrintFunc] needs to return is the name of the item, if | |
955 | the item's name is the first element of the tuple then use the @b[NullPrint()] | |
956 | function to retrieve this name. | |
957 | ||
958 | @begin(Format) | |
959 | char * | |
960 | NullPrint(@i[info]) | |
961 | char ** @i[info]; | |
962 | @end(Format) | |
963 | @begin(Description) | |
964 | info@\ An array of strings. | |
965 | @end(Description) | |
966 | ||
967 | @blankspace(1 line) | |
968 | ||
969 | @b[NullPrint()] returns the first element in the array passed to it, | |
970 | @i[info][0]. | |
971 | ||
972 | @Section[Miscellaneous Utility Functions] | |
973 | ||
974 | This section contains the rest of the utility functions, these don't | |
975 | really fit into a category. | |
976 | ||
977 | @Index(FreeAndClear) | |
978 | ||
979 | Use @b[FreeAndClear()] to free a pointer and set it to NULL. | |
980 | ||
981 | @Begin[Format] | |
982 | void | |
983 | FreeAndClear(@i[pointer, free_it]) | |
984 | char ** @i[pointer]; | |
985 | Bool @i[free_it]; | |
986 | @End[Format] | |
987 | ||
988 | @begin(Description) | |
989 | ||
990 | @i[pointer] @\A pointer to the item to free or clear, if this item is | |
991 | NULL then the function does not try to free it. | |
992 | ||
993 | @i[free_it] @\This function always sets the item to NULL, but only if | |
994 | this is TRUE is it freed. | |
995 | ||
996 | @end(Description) | |
997 | ||
998 | @Blankspace(1 line) | |
999 | @Center(________) | |
1000 | ||
1001 | ||
1002 | @Index(ValidName) | |
1003 | ||
1004 | @b[ValidName()] check to see if string is a valid name for a new | |
1005 | item in the database. | |
1006 | ||
1007 | @begin(Format) | |
1008 | Bool | |
1009 | ValidName(@i[s]) | |
1010 | char * @i[s]; | |
1011 | @end(Format) | |
1012 | ||
1013 | @begin(Description) | |
1014 | @i[s] @\The string to check. | |
1015 | @end(Description) | |
1016 | ||
1017 | @Blankspace( 1 line ) | |
1018 | ||
1019 | If the name is not valid, @b[ValidName()] alerts the user to the | |
1020 | problems encountered and returns FALSE. Checks are made to see if | |
1021 | this name contains a wildcard, contains spaces, or has no characters | |
1022 | at all. This is by no means an exhaustive search, but does handle some | |
1023 | common things that confuse the database. | |
1024 | ||
1025 | @Center(________) | |
1026 | ||
1027 | ||
1028 | @Index(ToggelVerboseMode) | |
1029 | ||
1030 | The @b[ToggleVerboseMode()] function is associated with the menu items | |
1031 | that allows the user to toggle the verbose global variable (see sect. | |
1032 | @ref(globals)). | |
1033 | ||
1034 | @Center(________) | |
1035 | ||
1036 | ||
1037 | @Index(Strsave) | |
1038 | ||
1039 | Use the @b[Strsave()] function to allocate space for a new string. | |
1040 | ||
1041 | @begin(Format) | |
1042 | char * | |
1043 | Strsave(@i[str]) | |
1044 | char * @i[str]; | |
1045 | @end(Format) | |
1046 | ||
1047 | @begin(Description) | |
1048 | @i[str] @\The string that needs to have space allocated for it. | |
1049 | @end(Description) | |
1050 | ||
1051 | @Blankspace( 1 line ) | |
1052 | ||
1053 | @b[Strsave()] returns an allocated copy of the string passed to it. | |
1054 | ||
1055 | @Center(________) | |
1056 | ||
1057 | ||
1058 | @Index(EncryptMITID) | |
1059 | @Index(RemoveHyphens) | |
1060 | ||
1061 | To save an MIT ID number two functions are needed, @b[EncryptMITID()] and | |
1062 | @b[RemoveHyphens()]. | |
1063 | ||
1064 | @begin(Format) | |
1065 | void | |
1066 | EncryptMITID(@i[sbuf], @i[idnumber], @i[first], @i[last]) | |
1067 | char * @i[sbuf], * @i[idnumber], * @i[first], * @i[last]; | |
1068 | @end(Format) | |
1069 | ||
1070 | @begin(Description) | |
1071 | @i[spbuf] @\The buffer used to return the encrypted id number. | |
1072 | ||
1073 | @i[idnumber] @\The unencrypted id number. | |
1074 | ||
1075 | @i[first, last] @\The name of the user whose id number we are encrypting. | |
1076 | ||
1077 | @end(Description) | |
1078 | ||
1079 | @Blankspace(1 line) | |
1080 | @Center(________) | |
1081 | ||
1082 | ||
1083 | @begin(Format) | |
1084 | void | |
1085 | RemoveHyphens(@i[str)] | |
1086 | char * @i[str]; | |
1087 | @end(Format) | |
1088 | ||
1089 | @begin(Description) | |
1090 | ||
1091 | @i[str] @\This is the string with hyphens to remove, when the function | |
1092 | returns it will no longer have hyphens. | |
1093 | @end(Description) | |
1094 | ||
1095 | @Chapter[Function Organization within Files] | |
1096 | ||
1097 | The functions within each of the files tend to be quite similar. I | |
1098 | have organized these so that at the top of the file are all the | |
1099 | general routines for the type of element currently being worked upon. | |
1100 | In @i[attach.c], for example, there is a @b[PrintFSInfo()] function, an | |
1101 | @b[AskFSInfo()] function, and a @b[GetFSInfo()] function. Each of the | |
1102 | item types will have a file that contains very similar functions, and | |
1103 | all will be grouped near the top of the file. As an example consider the | |
1104 | general functions in @i[attach.c]. | |
1105 | ||
1106 | @b[PrintFSInfo()] is used to print out all the information about a filesystem. | |
1107 | ||
1108 | @begin(Format) | |
1109 | static char * | |
1110 | PrintFSInfo(@i[info]) | |
1111 | char ** @i[info]; | |
1112 | @end(Format) | |
1113 | ||
1114 | @begin(Description) | |
1115 | @i[info] @\A NULL terminated array of strings that contains all information | |
1116 | about a filesystem. | |
1117 | @end(Description) | |
1118 | ||
1119 | @blankspace(1 line) | |
1120 | ||
1121 | @b[PrintFSInfo()] has the same format as @i[PrintFunc] (sect. | |
1122 | @ref(qloop)) and can be used as the @i[PrintFunc] for @b[QueryLoop()] | |
1123 | calls in the functions that update and delete filesystems. | |
1124 | ||
1125 | @Center(________) | |
1126 | ||
1127 | ||
1128 | @b[AskFSInfo()] is used to ask the user to update the current filesystem | |
1129 | information. | |
1130 | ||
1131 | @begin(Format) | |
1132 | static char ** | |
1133 | AskFSInfo(@i[info, name]) | |
1134 | char ** @i[info]; | |
1135 | Bool @i[name]; | |
1136 | @end(Format) | |
1137 | ||
1138 | @begin(Description) | |
1139 | ||
1140 | @i[info] @\A NULL terminated array of malloced strings that contains | |
1141 | all information about a filesystem. When the function is called this | |
1142 | array contains the default values to present to the user, and when the | |
1143 | function is returned this array contains the argument list for the | |
1144 | update or add query. | |
1145 | ||
1146 | @i[name] @\A boolean value that when TRUE tells this function to ask | |
1147 | the user for a new value for the name of this filesystem, and then | |
1148 | slip it into the @i[info] list, using @b[SlipInNewName()] (sect. | |
1149 | @ref(sinn)) | |
1150 | @end(Description) | |
1151 | ||
1152 | @Blankspace( 1 line ) | |
1153 | ||
1154 | The return value of @b[AskFSInfo()] is just the @i[info] array after | |
1155 | it has been updated with the new values. This function is used to | |
1156 | perform most of the information gathering in the update and add | |
1157 | filesystem queries. For an update query the information returned from | |
1158 | a @i[get_filesys_by_label] can be used for the @i[info] array, but for | |
1159 | an add filesystem, the program must come up with a reasonable set | |
1160 | default values for the @i[info] array. | |
1161 | ||
1162 | If the @i[name] flag is set then the @b[SlipInNewName()] function is | |
1163 | called to add a new name to the @i[info] array, this causes the array | |
1164 | indices for most values to be changed and thus the predefined values | |
1165 | used to access the information in this array can no longer be used | |
1166 | (see sections @ref(infodefs) and @Ref(sinn)). | |
1167 | ||
1168 | @Center(________) | |
1169 | ||
1170 | ||
1171 | The @b[GetFSInfo()] function is used to to perform common information | |
1172 | gathering @i[SMS] queries for a filesystem. | |
1173 | ||
1174 | @begin(Format) | |
1175 | static struct qelem * | |
1176 | GetFSInfo(@i[type, name]) | |
1177 | int @i[type]; | |
1178 | char * @i[name]; | |
1179 | @end(Format) | |
1180 | ||
1181 | @begin(Description) | |
1182 | @i[type] @\The type of filesystem query to make, can be one of; | |
1183 | LABEL, MACHINE, GROUP or ALIAS. The valid names for @i[type] are | |
1184 | typedef'ed at the beginning of each file. | |
1185 | ||
1186 | @i[name] @\The name to pass as the argument to the query. | |
1187 | @end(Description) | |
1188 | ||
1189 | @Blankspace(1 line) | |
1190 | ||
1191 | The @b[GetFSInfo()] function is a simple method of making the most | |
1192 | common information gathering @i[SMS] queries, it handles all return | |
1193 | values from the call to sms_query() and returns the top element of a | |
1194 | queue containing all information returned by the server. If an error | |
1195 | is detected then NULL is returned and an error message is printed to | |
1196 | the user. | |
1197 | ||
1198 | After this group of general functions come those that actually | |
1199 | correspond to items in the menu. These commonly perform get, add, | |
1200 | update, and delete operations. For more information on the functions | |
1201 | in each of the files see the appendix @ref(fqlist). | |
1202 | ||
1203 | @Appendix(The @i[SMS] Query String Array Definitions) | |
1204 | ||
1205 | @Label(a_infodefs) | |
1206 | ||
1207 | @Begin[Format] | |
1208 | ||
1209 | /* | |
1210 | * This file contains all definitions that allow easy access to | |
1211 | * elements returned by most of the @i[SMS] queries. | |
1212 | * | |
1213 | * If the order of the arguments in the @i[SMS] queries change (again) | |
1214 | * then all that needs to be changed are the values of these items | |
1215 | * and all should be well, (hopefully :-). | |
1216 | * | |
1217 | * Chris D. Peterson - kit@@athena | |
1218 | * 6/8/88 | |
1219 | */ | |
1220 | ||
1221 | @Begin[Verbatim] | |
1222 | ||
1223 | #ifndef _infodefs_ | |
1224 | #define _infodefs_ | |
1225 | ||
1226 | #include "mit-copyright.h" | |
1227 | ||
1228 | #define NAME 0 | |
1229 | ||
1230 | /* get_ace_use */ | |
1231 | ||
1232 | #define ACE_TYPE 0 | |
1233 | #define ACE_NAME 1 | |
1234 | #define ACE_END 2 | |
1235 | ||
1236 | /* alias queries. */ | |
1237 | ||
1238 | #define ALIAS_NAME 0 | |
1239 | #define ALIAS_TYPE 1 | |
1240 | #define ALIAS_TRANS 2 | |
1241 | #define ALIAS_END 3 | |
1242 | ||
1243 | /* Cluster information queries */ | |
1244 | ||
1245 | #define C_NAME 0 | |
1246 | #define C_DESCRIPT 1 | |
1247 | #define C_LOCATION 2 | |
1248 | #define C_MODTIME 3 | |
1249 | #define C_MODBY 4 | |
1250 | #define C_MODWITH 5 | |
1251 | #define C_END 6 | |
1252 | ||
1253 | /* Cluster Data information queries */ | |
1254 | ||
1255 | #define CD_NAME 0 | |
1256 | #define CD_LABEL 1 | |
1257 | #define CD_DATA 2 | |
1258 | #define CD_END 3 | |
1259 | ||
1260 | /* Delete Member from list queries. */ | |
1261 | ||
1262 | #define DM_LIST 0 | |
1263 | #define DM_TYPE 1 | |
1264 | #define DM_MEMBER 2 | |
1265 | #define DM_END 3 | |
1266 | ||
1267 | /* Filesys queries */ | |
1268 | ||
1269 | #define FS_NAME 0 | |
1270 | #define FS_TYPE 1 | |
1271 | #define FS_MACHINE 2 | |
1272 | #define FS_PACK 3 | |
1273 | #define FS_M_POINT 4 | |
1274 | #define FS_ACCESS 5 | |
1275 | #define FS_COMMENTS 6 | |
1276 | #define FS_OWNER 7 | |
1277 | #define FS_OWNERS 8 | |
1278 | #define FS_CREATE 9 | |
1279 | #define FS_L_TYPE 10 | |
1280 | #define FS_MODTIME 11 | |
1281 | #define FS_MODBY 12 | |
1282 | #define FS_MODWITH 13 | |
1283 | #define FS_END 14 | |
1284 | ||
1285 | /* Get List Of Member queries. */ | |
1286 | ||
1287 | #define GLOM_NAME 0 | |
1288 | #define GLOM_ACTIVE 1 | |
1289 | #define GLOM_PUBLIC 2 | |
1290 | #define GLOM_HIDDEN 3 | |
1291 | #define GLOM_MAILLIST 4 | |
1292 | #define GLOM_GROUP 5 | |
1293 | #define GLOM_END 6 | |
1294 | ||
1295 | /* General List information queries. */ | |
1296 | ||
1297 | #define L_NAME 0 | |
1298 | #define L_ACTIVE 1 | |
1299 | #define L_PUBLIC 2 | |
1300 | #define L_HIDDEN 3 | |
1301 | #define L_MAILLIST 4 | |
1302 | #define L_GROUP 5 | |
1303 | #define L_GID 6 | |
1304 | #define L_ACE_TYPE 7 | |
1305 | #define L_ACE_NAME 8 | |
1306 | #define L_DESC 9 | |
1307 | #define L_MODTIME 10 | |
1308 | #define L_MODBY 11 | |
1309 | #define L_MODWITH 12 | |
1310 | #define L_END 13 | |
1311 | ||
1312 | /* List Member information queries. */ | |
1313 | ||
1314 | #define LM_LIST 0 | |
1315 | #define LM_TYPE 1 | |
1316 | #define LM_MEMBER 2 | |
1317 | #define LM_END 3 | |
1318 | ||
1319 | /* Machine information queries */ | |
1320 | ||
1321 | #define M_NAME 0 | |
1322 | #define M_TYPE 1 | |
1323 | #define M_MODTIME 2 | |
1324 | #define M_MODBY 3 | |
1325 | #define M_MODWITH 4 | |
1326 | #define M_END 5 | |
1327 | ||
1328 | /* Machine to cluster Mapping */ | |
1329 | ||
1330 | #define MAP_MACHINE 0 | |
1331 | #define MAP_CLUSTER 1 | |
1332 | #define MAP_END 2 | |
1333 | ||
1334 | /* NFS phys. queries. */ | |
1335 | ||
1336 | #define NFS_NAME 0 | |
1337 | #define NFS_DIR 1 | |
1338 | #define NFS_DEVICE 2 | |
1339 | #define NFS_STATUS 3 | |
1340 | #define NFS_ALLOC 4 | |
1341 | #define NFS_SIZE 5 | |
1342 | #define NFS_MODTIME 6 | |
1343 | #define NFS_MODBY 7 | |
1344 | #define NFS_MODWITH 8 | |
1345 | #define NFS_END 9 | |
1346 | ||
1347 | /* PO box information queries */ | |
1348 | ||
1349 | #define PO_NAME 0 | |
1350 | #define PO_TYPE 1 | |
1351 | #define PO_BOX 2 | |
1352 | #define PO_END 3 | |
1353 | ||
1354 | /* Quota queries */ | |
1355 | ||
1356 | #define Q_FILESYS 0 | |
1357 | #define Q_LOGIN 1 | |
1358 | #define Q_QUOTA 2 | |
1359 | #define Q_DIRECTORY 3 | |
1360 | #define Q_MACHINE 4 | |
1361 | #define Q_MODTIME 5 | |
1362 | #define Q_MODBY 6 | |
1363 | #define Q_MODWITH 7 | |
1364 | #define Q_END 8 | |
1365 | ||
1366 | /* User information queries */ | |
1367 | ||
1368 | #define U_NAME 0 | |
1369 | #define U_UID 1 | |
1370 | #define U_SHELL 2 | |
1371 | #define U_LAST 3 | |
1372 | #define U_FIRST 4 | |
1373 | #define U_MIDDLE 5 | |
1374 | #define U_STATE 6 | |
1375 | #define U_MITID 7 | |
1376 | #define U_CLASS 8 | |
1377 | #define U_MODTIME 9 | |
1378 | #define U_MODBY 10 | |
1379 | #define U_MODWITH 11 | |
1380 | #define U_END 12 | |
1381 | ||
1382 | #endif _infodefs_ /* Do not add anything after this line. */ | |
1383 | ||
1384 | @End[Verbatim] | |
1385 | ||
1386 | @End[Format] | |
1387 | ||
1388 | @Appendix(List of Menus, Functions, and Query Names) | |
1389 | ||
1390 | @Label(fqlist) | |
1391 | ||
1392 | @blankspace(2 lines) | |
1393 | ||
1394 | The menu tree for the @i[SMS Client] has three levels, the root, tier | |
1395 | 1 and tier 2. A diagram of the menu tree is show in appendix @ref(tree). | |
1396 | The root of the tree is composed of calls to other menus. | |
1397 | ||
1398 | @blankspace(2 lines) | |
1399 | ||
1400 | @begin(Group) | |
1401 | @Center(Sms Database Manipulation) | |
1402 | @begin(Verbatim) | |
1403 | ||
1404 | 1. (cluster) Cluster Menu. | |
1405 | 2. (filesys) Filesystem Menu. | |
1406 | 3. (list) Lists and Group Menu. | |
1407 | 4. (machine) Machine Menu. | |
1408 | 5. (nfs) Physical NFS Menu. | |
1409 | 6. (user) User Menu. | |
1410 | t. (toggle) Toggle logging on and off. | |
1411 | q. (quit) Quit. | |
1412 | ||
1413 | @end(Verbatim) | |
1414 | @Hinge() | |
1415 | @Section[First Tier Menus] | |
1416 | ||
1417 | @Center{ @b[Cluster Menu] } | |
1418 | ||
1419 | @begin(Verbatim) | |
1420 | ||
1421 | 1. (show) Get cluster information. | |
1422 | 2. (add) Add a new cluster. | |
1423 | 3. (update) Update cluster information. | |
1424 | 4. (delete) Delete this cluster. | |
1425 | 5. (mappings) Machine To Cluster Mappings Menu. | |
1426 | 6. (c_data) Cluster Data Menu. | |
1427 | 7. (verbose) Toggle Verbosity of Delete. | |
1428 | r. (return) Return to previous menu. | |
1429 | t. (toggle) Toggle logging on and off. | |
1430 | q. (quit) Quit. | |
1431 | ||
1432 | @end(Verbatim) | |
1433 | ||
1434 | @Begin(Format) | |
1435 | @tabset(20,40,60) | |
1436 | show@\get_cluster | |
1437 | add@\get_cluster@\add_cluster | |
1438 | update@\get_cluster@\update_cluster | |
1439 | delete@\get_cluster@\delete_cluster | |
1440 | ||
1441 | @End[Format] | |
1442 | @Hinge() | |
1443 | @Center{ @b[Filesystem Menu] } | |
1444 | ||
1445 | @begin(Verbatim) | |
1446 | ||
1447 | 1. (get) Get Filesystem Name Information. | |
1448 | 2. (add) Add New Filesystem to Database. | |
1449 | 3. (change) Update Filesystem Information. | |
1450 | 4. (delete) Delete Filesystem. | |
1451 | 5. (check) Check An Association. | |
1452 | 6. (alias) Associate with a Filesystem. | |
1453 | 7. (unalias) Dissociate from a Filesystem. | |
1454 | 8. (quotas) Quota Menu. | |
1455 | 9. (verbose) Toggle Verbosity of Delete. | |
1456 | 10. (help) Help ... | |
1457 | r. (return) Return to previous menu. | |
1458 | t. (toggle) Toggle logging on and off. | |
1459 | q. (quit) Quit. | |
1460 | ||
1461 | @end(Verbatim) | |
1462 | ||
1463 | @begin(Format) | |
1464 | @tabset(20,40,60) | |
1465 | get@\get_filesys_by_label | |
1466 | add@\get_filesys_by_label@\add_filesys | |
1467 | change@\get_filesys_by_label@\update_filesys | |
1468 | delete@\get_filesys_by_label@\delete_filesys | |
1469 | check@\get_alias | |
1470 | alias@\get_alias@\add_alias | |
1471 | unalias@\get_alias@\delete_alias | |
1472 | ||
1473 | @end(Format) | |
1474 | @Hinge() | |
1475 | @Center{ @b[List Menu] } | |
1476 | ||
1477 | @begin(Verbatim) | |
1478 | ||
1479 | 1. (show) Display information about a list. | |
1480 | 2. (add) Create new List. | |
1481 | 3. (update) Update characteristics of a list. | |
1482 | 4. (delete) Delete a List. | |
1483 | 5. (query_remove) Interactively remove an item from all lists. | |
1484 | 6. (members) Member Menu - Change/Show Members of a List. | |
1485 | 7. (list_info) List Info Menu. | |
1486 | 8. (quotas) Quota Menu. | |
1487 | 9. (verbose) Toggle Verbosity of Delete. | |
1488 | 10. (help) Print Help. | |
1489 | r. (return) Return to previous menu. | |
1490 | t. (toggle) Toggle logging on and off. | |
1491 | q. (quit) Quit. | |
1492 | ||
1493 | @end(Verbatim) | |
1494 | ||
1495 | @begin(Format) | |
1496 | @tabset(20,40,60) | |
1497 | show@\get_list_info | |
1498 | add@\get_list_info@\add_list | |
1499 | update@\get_list_info@\update_list | |
1500 | delete@\get_list_info@\get_ace_use | |
1501 | @\count_members_of_list@\get_lists_of_member | |
1502 | @\get_members_of_list@\delete_list | |
1503 | @\delete_member_from_list | |
1504 | query_remove@\get_lists_of_member@\delete_member_from_list | |
1505 | ||
1506 | @end(Format) | |
1507 | @Hinge() | |
1508 | @Center{ @b[Machine Menu] } | |
1509 | ||
1510 | @begin(Verbatim) | |
1511 | ||
1512 | 1. (show) Get machine information. | |
1513 | 2. (add) Add a new machine. | |
1514 | 3. (update) Update machine information. | |
1515 | 4. (delete) Delete this machine. | |
1516 | 5. (mappings) Machine To Cluster Mappings Menu. | |
1517 | 6. (verbose) Toggle Verbosity of Delete. | |
1518 | r. (return) Return to previous menu. | |
1519 | t. (toggle) Toggle logging on and off. | |
1520 | q. (quit) Quit. | |
1521 | ||
1522 | @end(Verbatim) | |
1523 | ||
1524 | @begin(Format) | |
1525 | @tabset(20,40, 60) | |
1526 | show@\get_machine | |
1527 | add@\get_machine@\add_machine | |
1528 | update@\get_machine@\update_machine | |
1529 | delete@\get_machine@\delete_machine | |
1530 | ||
1531 | @end(Format) | |
1532 | ||
1533 | Delete machine needs to make some other checks. For lack of time these | |
1534 | have not been implemented. | |
1535 | @begin(Itemize) | |
1536 | @tabset(45) | |
1537 | Is the machine a server@\get_server_host_info | |
1538 | ||
1539 | Is the machine an NFS server@\get_nfsphys | |
1540 | ||
1541 | Are there any ACE's that this machine references@\get_server_host_access | |
1542 | @end(Itemize) | |
1543 | ||
1544 | @Hinge() | |
1545 | ||
1546 | @Center{ @b[NFS Physical Menu] } | |
1547 | ||
1548 | @begin(Verbatim) | |
1549 | ||
1550 | 1. (show) Show an NFS server. | |
1551 | 2. (add) Add NFS server. | |
1552 | 3. (update) Update NFS server. | |
1553 | 4. (delete) Delete NFS server. | |
1554 | 5. (quotas) Quota Menu. | |
1555 | 6. (verbose) Toggle Verbosity of Delete. | |
1556 | r. (return) Return to previous menu. | |
1557 | t. (toggle) Toggle logging on and off. | |
1558 | q. (quit) Quit. | |
1559 | ||
1560 | @end(Verbatim) | |
1561 | ||
1562 | @begin(Format) | |
1563 | @tabset(20,40, 60) | |
1564 | show@\get_nfsphys | |
1565 | add@\get_nfsphys@\add_nfsphys | |
1566 | update@\get_nfsphys@\update_nfsphys | |
1567 | delete@\get_nfsphys@\get_filesys_by_nfsphys | |
1568 | @\delete_nfsphys | |
1569 | ||
1570 | @end(Format) | |
1571 | @Hinge() | |
1572 | @Center{ @b[User Menu] } | |
1573 | ||
1574 | @begin(Verbatim) | |
1575 | ||
1576 | 1. (login) Show user information by login name. | |
1577 | 2. (name) Show user information by name. | |
1578 | 3. (class) Show names of users in a given class. | |
1579 | 4. (modify) Change all user fields. | |
1580 | 5. (adduser) Add a new user to the database. | |
1581 | 6. (register) Register a user. | |
1582 | 7. (delete) Delete user. | |
1583 | 8. (udelete) Delete user by uid. | |
1584 | 9. (pobox) Post Office Box Menu. | |
1585 | 10. (quota) Quota Menu. | |
1586 | 11. (verbose) Toggle Verbosity of Delete. | |
1587 | r. (return) Return to previous menu. | |
1588 | t. (toggle) Toggle logging on and off. | |
1589 | q. (quit) Quit. | |
1590 | ||
1591 | @end(Verbatim) | |
1592 | ||
1593 | @begin(Format) | |
1594 | @tabset(20,40, 60) | |
1595 | login@\get_user_by_login | |
1596 | name@\get_user_by_name | |
1597 | class@\get_user_by_class | |
1598 | modify@\get_user_by_login@\update_user | |
1599 | adduser@\add_user | |
1600 | register@\get_user_by_name@\register_user | |
1601 | @\Kerberos server is queried also. | |
1602 | delete@\delete_user@\get_filesys_by_label | |
1603 | @\delete_filesys@\get_members_of_list | |
1604 | @\delete_list@\count_members_of_list | |
1605 | @\get_lists_of_member@\delete_member_from_list | |
1606 | @\get_list_info@\get_ace_use | |
1607 | udelete@\get_user_by_uid@\(plus all of the above). | |
1608 | ||
1609 | @end(Format) | |
1610 | @Hinge() | |
1611 | @Section[Second Tier Menus] | |
1612 | ||
1613 | @Center{ @b[Cluster Data Menu] } | |
1614 | ||
1615 | @begin(Verbatim) | |
1616 | ||
1617 | 1. (show) Show Data on a given Cluster. | |
1618 | 2. (add) Add Data to a given Cluster. | |
1619 | 3. (delete) Remove Data to a given Cluster. | |
1620 | 4. (verbose) Toggle Verbosity of Delete. | |
1621 | r. (return) Return to previous menu. | |
1622 | t. (toggle) Toggle logging on and off. | |
1623 | q. (quit) Quit. | |
1624 | ||
1625 | @end(Verbatim) | |
1626 | ||
1627 | @begin(Format) | |
1628 | @tabset(20,40, 60) | |
1629 | show@\get_cluster_data | |
1630 | add@\add_cluster_data | |
1631 | delete@\get_cluster_data@\delete_cluster_data | |
1632 | ||
1633 | @end(Format) | |
1634 | @Hinge() | |
1635 | @Center{ @b[List Information Menu] } | |
1636 | ||
1637 | @begin(Verbatim) | |
1638 | ||
1639 | 1. (member) Show all lists to which a given member belongs. | |
1640 | 2. (admin) Show all items which a given member can administer. | |
1641 | 3. (groups) Show all lists which are groups. | |
1642 | 4. (public) Show all public mailing lists. | |
1643 | 5. (maillists) Show all mailing lists. | |
1644 | r. (return) Return to previous menu. | |
1645 | t. (toggle) Toggle logging on and off. | |
1646 | q. (quit) Quit. | |
1647 | ||
1648 | @end(Verbatim) | |
1649 | ||
1650 | @begin(Format) | |
1651 | @tabset(20,40, 60) | |
1652 | member@\get_lists_of_member | |
1653 | admin@\get_ace_use | |
1654 | groups@\qualified_get_lists | |
1655 | public@\qualified_get_lists | |
1656 | maillists@\qualified_get_lists | |
1657 | ||
1658 | @end(Format) | |
1659 | @Hinge() | |
1660 | @Center{ @b[Mappings Menu] } | |
1661 | ||
1662 | @begin(Verbatim) | |
1663 | ||
1664 | 1. (map) Show Machine to cluster mapping. | |
1665 | 2. (addcluster) Add machines to a clusters. | |
1666 | 3. (remcluster) Remove machines from clusters. | |
1667 | 4. (verbose) Toggle Verbosity of Delete. | |
1668 | r. (return) Return to previous menu. | |
1669 | t. (toggle) Toggle logging on and off. | |
1670 | q. (quit) Quit. | |
1671 | ||
1672 | @end(Verbatim) | |
1673 | ||
1674 | @begin(Format) | |
1675 | @tabset(20,40, 60) | |
1676 | map@\get_machine_to_cluster_map | |
1677 | addcluster@\get_machine@\get_cluster | |
1678 | @\add_machine_to_cluster | |
1679 | remcluster@\get_machine_to_cluster_map | |
1680 | @\delete_machine_from_cluster | |
1681 | ||
1682 | @end(Format) | |
1683 | @Hinge() | |
1684 | @Center{ @b[Membership Menu] } | |
1685 | ||
1686 | @begin(Verbatim) | |
1687 | ||
1688 | 1. (add) Add a member to this list. | |
1689 | 2. (remove) Remove a member from this list. | |
1690 | 3. (all) Show the members of this list. | |
1691 | 4. (user) Show the members of type USER. | |
1692 | 5. (list) Show the members of type LIST. | |
1693 | 6. (string) Show the members of type STRING. | |
1694 | 7. (verbose) Toggle Verbosity of Delete. | |
1695 | r. (return) Return to previous menu. | |
1696 | t. (toggle) Toggle logging on and off. | |
1697 | q. (quit) Quit. | |
1698 | ||
1699 | @end(Verbatim) | |
1700 | ||
1701 | @begin(Format) | |
1702 | @tabset(20,40, 60) | |
1703 | add@\add_member_to_list | |
1704 | remove@\delete_member_from_list | |
1705 | all@\get_members_of_list | |
1706 | user@\get_members_of_list | |
1707 | list@\get_members_of_list | |
1708 | string@\get_members_of_list | |
1709 | ||
1710 | @end(Format) | |
1711 | @Hinge() | |
1712 | @Center{ @b[Post Office Box Menu] } | |
1713 | ||
1714 | @begin(Verbatim) | |
1715 | ||
1716 | 1. (show) Show a user's post office box. | |
1717 | 2. (set) Set (Add or Change) a user's post office box. | |
1718 | 3. (remove) Remove a user's post office box. | |
1719 | 4. (verbose) Toggle Verbosity of Delete. | |
1720 | r. (return) Return to previous menu. | |
1721 | t. (toggle) Toggle logging on and off. | |
1722 | q. (quit) Quit. | |
1723 | ||
1724 | @end(Verbatim) | |
1725 | ||
1726 | @begin(Format) | |
1727 | @tabset(20,40, 60) | |
1728 | show@\get_pobox | |
1729 | set@\get_pobox@\get_server_locations | |
1730 | @\set_pobox_pop@\set_pobox | |
1731 | remove@\delete_pobox | |
1732 | ||
1733 | @end(Format) | |
1734 | @Hinge() | |
1735 | @Center{ @b[Quota Menu] } | |
1736 | ||
1737 | @begin(Verbatim) | |
1738 | ||
1739 | 1. (shdef) Show default user quota (in KB). | |
1740 | 2. (chdef) Change default user quota. | |
1741 | 3. (shquota) Show a user's disk quota on a filesystem. | |
1742 | 4. (addquota) Add a new disk quota for user on a filesystem. | |
1743 | 5. (chquota) Change a user's disk quota on a filesystem. | |
1744 | 6. (rmquota) Remove a user's disk quota on a filesystem. | |
1745 | 7. (verbose) Toggle Verbosity of Delete. | |
1746 | r. (return) Return to previous menu. | |
1747 | t. (toggle) Toggle logging on and off. | |
1748 | q. (quit) Quit. | |
1749 | ||
1750 | @end(Verbatim) | |
1751 | ||
1752 | @begin(Format) | |
1753 | @tabset(20,40, 60) | |
1754 | shdef@\get_value | |
1755 | chdef@\update_value@\get_value | |
1756 | shquota@\get_nfs_quota | |
1757 | addquota@\add_nfs_quota | |
1758 | chquota@\get_nfs_quota@\update_nfs_quota | |
1759 | rmquota@\get_nfs_quota@\delete_nfs_quota | |
1760 | @end(Format) | |
1761 | @end(Group) | |
1762 | ||
1763 | @Appendix(Menu Tree Diagram) | |
1764 | ||
1765 | @Label(tree) |