]> andersk Git - moira.git/blob - server/qsupport.qc
4198506f0359706edb964d2ecc95af7964c4d21a
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  */
9
10 #ifndef lint
11 static char *rcsid_qsupport_qc = "$Header$";
12 #endif lint
13
14 #include "query.h"
15 #include "sms_server.h"
16 #include <ctype.h>
17
18
19 extern char *whoami, *strsave();
20 extern int  ingres_errno;
21
22
23 /* Specialized Access Routines */
24
25 /* access_user - verify that client name equals specified login name
26  *
27  *  - since field validation routines are called first, a users_id is
28  *    now in argv[0] instead of the login name.
29  */
30
31 access_user(q, argv, cl)
32     struct query *q;
33     char *argv[];
34     client *cl;
35 {
36     if (cl->users_id != *(int *)argv[0])
37         return(SMS_PERM);
38     else
39         return(SMS_SUCCESS);
40 }
41
42     
43
44 /* access_login - verify that client name equals specified login name
45  *
46  *   argv[0...n] contain search info.  q->
47  */
48
49 access_login(q, argv, cl)
50     struct query *q;
51     char *argv[];
52     client *cl;
53 ##{
54 ##  int rowcount, id;
55 ##  char qual[256];
56
57     build_qual(q->qual, q->argc, argv, qual);
58 ##  retrieve (id = u.users_id) where qual
59     if (ingres_errno != 0) return(ingres_errno);
60 ##  inquire_equel(rowcount = "rowcount")
61     if (rowcount != 1 || id != cl->users_id)
62         return(SMS_PERM);
63     else
64         return(SMS_SUCCESS);
65 ##}
66
67     
68
69 /* access_list - check access for most list operations
70  *
71  * Inputs: argv[0] - list_id
72  *          q - query name
73  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
74  *          argv[7] - group IID (only for query "ulis")
75  *          cl - client name
76  *
77  * - check that client is a member of the access control list
78  * - OR, if the query is add_member_to_list or delete_member_from_list
79  *      and the list is public, allow access if client = member
80  */ 
81
82 access_list(q, argv, cl)
83     struct query *q;
84     char *argv[];
85     client *cl;
86 ##{
87 ##  int list_id, acl_id, flags, rowcount, gid;
88 ##  char acl_type[9];
89     char *client_type;
90     int client_id, status;
91
92     list_id = *(int *)argv[0];
93 ##  repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
94 ##                   gid = list.#gid, flags = list.#public) 
95 ##         where list.#list_id = @list_id
96     if (ingres_errno != 0) return(ingres_errno);
97 ##  inquire_equel(rowcount = "rowcount")
98     if (rowcount != 1)
99       return(SMS_INTERNAL);
100
101     /* parse client structure */
102     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
103         return(status);
104
105     /* if amtl or dmfl and list is public allow client to add or delete self */
106     if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
107         (flags && !strcmp("USER", argv[1]))) {
108         if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
109     /* if update_list, don't allow them to change the GID */
110     } else if (!strcmp("ulis", q->shortname)) {
111         if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
112             (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
113           return(SMS_PERM);
114     }
115
116     /* check for client in access control list */
117     status = find_member(acl_type, acl_id, client_type, client_id, 0);
118     if (!status) return(SMS_PERM);
119
120     return(SMS_SUCCESS);
121 ##}
122
123
124 /* access_visible_list - allow access to list only if it is not hidden,
125  *      or if the client is on the ACL
126  *
127  * Inputs: argv[0] - list_id
128  *         cl - client identifier
129  */ 
130
131 access_visible_list(q, argv, cl)
132     struct query *q;
133     char *argv[];
134     client *cl;
135 ##{
136 ##  int list_id, acl_id, flags, rowcount;
137 ##  char acl_type[9];
138     char *client_type;
139     int client_id, status;
140
141     list_id = *(int *)argv[0];
142 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
143 ##      acl_type = list.#acl_type) where list.#list_id = @list_id
144     if (ingres_errno != 0) return(ingres_errno);
145 ##  inquire_equel(rowcount = "rowcount")
146     if (rowcount != 1)
147       return(SMS_INTERNAL);
148     if (!flags)
149         return(SMS_SUCCESS);
150
151     /* parse client structure */
152     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
153         return(status);
154
155     /* check for client in access control list */
156     status = find_member(acl_type, acl_id, client_type, client_id, 0);
157     if (!status)
158         return(SMS_PERM);
159
160     return(SMS_SUCCESS);
161 ##}
162
163
164 /* access_vis_list_by_name - allow access to list only if it is not hidden,
165  *      or if the client is on the ACL
166  *
167  * Inputs: argv[0] - list name
168  *         cl - client identifier
169  */ 
170
171 access_vis_list_by_name(q, argv, cl)
172     struct query *q;
173     char *argv[];
174     client *cl;
175 ##{
176 ##  int acl_id, flags, rowcount;
177 ##  char acl_type[9], *listname;
178     char *client_type;
179     int client_id, status;
180
181     listname = argv[0];
182 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
183 ##      acl_type = list.#acl_type) where list.#name = @listname
184     if (ingres_errno != 0) return(ingres_errno);
185 ##  inquire_equel(rowcount = "rowcount");
186     if (rowcount > 1)
187       return(SMS_WILDCARD);
188     if (rowcount == 0)
189       return(SMS_NO_MATCH);
190     if (!flags)
191         return(SMS_SUCCESS);
192
193     /* parse client structure */
194     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
195         return(status);
196
197     /* check for client in access control list */
198     status = find_member(acl_type, acl_id, client_type, client_id, 0);
199     if (!status)
200         return(SMS_PERM);
201
202     return(SMS_SUCCESS);
203 ##}
204
205
206 /* access_member - allow user to access member of type "USER" and name matches
207  * username, or to access member of type "LIST" and list is one that user is
208  * on the acl of, or the list is visible.
209  */
210
211 access_member(q, argv, cl)
212     struct query *q;
213     char *argv[];
214     client *cl;
215 {
216     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
217       return(access_visible_list(q, &argv[1], cl));
218
219     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
220         if (cl->users_id == *(int *)argv[1])
221           return(SMS_SUCCESS);
222     }
223
224     return(SMS_PERM);
225 }
226
227
228 /* access_qgli - special access routine for Qualified_get_lists.  Allows
229  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
230  */
231
232 access_qgli(q, argv, cl)
233     struct query *q;
234     char *argv[];
235     client *cl;
236 {
237     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
238       return(SMS_SUCCESS);
239     return(SMS_PERM);
240 }
241
242
243 /* access_service - allow access if user is on ACL of service.  Don't
244  * allow access if a wildcard is used.
245  */
246
247 access_service(q, argv, cl)
248     struct query *q;
249     char *argv[];
250     client *cl;
251 ##{
252 ##  int acl_id, rowcount;
253 ##  char *name, acl_type[9];
254     int client_id, status;
255     char *client_type;
256
257     name = argv[0];
258 ##  repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
259 ##      where servers.#name = uppercase(@name)
260     if (ingres_errno != 0) return(ingres_errno);
261 ##  inquire_equel(rowcount = "rowcount")
262     if (rowcount > 1)
263       return(SMS_PERM);
264
265     /* parse client structure */
266     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
267         return(status);
268
269     /* check for client in access control list */
270     status = find_member(acl_type, acl_id, client_type, client_id, 0);
271     if (!status) return(SMS_PERM);
272
273     return(SMS_SUCCESS);
274 ##}
275
276
277
278 /* access_filesys - verify that client is owner or on owners list of filesystem
279  *      named by argv[0]
280  */
281
282 access_filesys(q, argv, cl)
283     struct query *q;
284     char *argv[];
285     client *cl;
286 ##{
287 ##  int rowcount, users_id, list_id;
288 ##  char *name;
289     int status, client_id;
290     char *client_type;
291
292     name = argv[0];
293 ##  repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
294 ##      where filesys.label = @name
295     if (ingres_errno != 0) return(ingres_errno);
296 ##  inquire_equel(rowcount = "rowcount")
297
298     if (rowcount != 1)
299       return(SMS_PERM);
300     if (users_id == cl->users_id)
301       return(SMS_SUCCESS);
302     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
303         return(status);
304     status = find_member("LIST", list_id, client_type, client_id, 0);
305     if (status)
306       return(SMS_SUCCESS);
307     return(SMS_PERM);
308 ##}
309
310     
311 \f
312 /* Setup Routines */
313
314 /* Setup routine for add_user
315  *
316  * Inputs: argv[0] - login
317  *         argv[1] - uid
318  *
319  * Description:
320  *
321  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
322  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
323  */
324
325 setup_ausr(q, argv, cl)
326     struct query *q;
327     register char *argv[];
328     client *cl;
329 ##{
330 ##  int nuid, rowcount;
331
332     if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
333         if (set_next_object_id("uid", "users"))
334           return(SMS_INGRES_ERR);
335 ##      repeat retrieve (nuid = values.value) where values.name = "uid"
336         if (ingres_errno != 0) return(ingres_errno);
337 ##      inquire_equel(rowcount = "rowcount")
338         if (rowcount != 1)
339           return(SMS_INTERNAL);
340         sprintf(argv[1], "%d", nuid);
341     }
342
343     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
344         sprintf(argv[0], "#%s", argv[1]);
345     }
346
347     return(SMS_SUCCESS);
348 ##}
349
350
351 /* setup_dusr - verify that the user is no longer being referenced 
352  * and may safely be deleted.
353  */
354
355 int setup_dusr(q, argv)
356     struct query *q;
357     char **argv;
358 ##{
359 ##  int flag, id;
360
361     id = *(int *)argv[0];
362
363     /* For now, only allow users to be deleted if their status is 0 */
364 ##  repeat retrieve (flag = u.status) where u.users_id = @id
365     if (flag != 0)
366       return(SMS_IN_USE);
367
368 ##  repeat delete nfsquota where nfsquota.users_id = @id
369     if (ingres_errno != 0) return(ingres_errno);
370 ##  repeat retrieve (flag = any(members.member_id where members.member_id=@id
371 ##                       and members.member_type = "USER"))
372     if (ingres_errno != 0) return(ingres_errno);
373     if (flag)
374         return(SMS_IN_USE);
375 ##  repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
376     if (ingres_errno != 0) return(ingres_errno);
377     if (flag)
378         return(SMS_IN_USE);
379 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
380 ##                      list.acl_type = "USER"))
381     if (ingres_errno != 0) return(ingres_errno);
382     if (flag)
383         return(SMS_IN_USE);
384 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
385 ##                      servers.acl_type = "USER"))
386     if (ingres_errno != 0) return(ingres_errno);
387     if (flag)
388         return(SMS_IN_USE);
389 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
390 ##                      hostaccess.acl_type = "USER"))
391     if (ingres_errno != 0) return(ingres_errno);
392     if (flag)
393         return(SMS_IN_USE);
394     else
395         return(SMS_SUCCESS);
396 ##}
397
398
399 /* setup_spop: verify that there is already a valid POP machine_id in the
400  * pop_id field.  Also take care of keeping track of the post office usage.
401  */
402 int setup_spop(q, argv)
403 struct query *q;
404 char **argv;
405 ##{
406 ##  int id, mid, flag;
407 ##  char type[9];
408
409     id = *(int *)argv[0];
410 ##  repeat retrieve (type = u.potype, mid = u.pop_id,
411 ##                   flag = any(machine.name where machine.mach_id = u.pop_id 
412 ##                                   and u.pop_id != 0 and u.users_id = @id))
413 ##      where u.users_id = @id
414     if (ingres_errno != 0) return(ingres_errno);
415     if (!flag)
416       return(SMS_MACHINE);
417     if (strcmp(strtrim(type), "POP"))
418       set_pop_usage(mid, 1);
419     return(SMS_SUCCESS);
420 ##}
421
422
423 /* setup_dpob:  Take care of keeping track of the post office usage.
424  */
425 int setup_dpob(q, argv)
426 struct query *q;
427 char **argv;
428 ##{
429 ##  int id, user;
430 ##  char type[9];
431
432     user = *(int *)argv[0];
433 ##  repeat retrieve (type = u.potype, id = u.pop_id)
434 ##              where u.users_id = @user
435     if (ingres_errno != 0) return(ingres_errno);
436
437     if (!strcmp(strtrim(type), "POP"))
438       set_pop_usage(id, -1);
439     return(SMS_SUCCESS);
440 ##}
441
442
443 /* setup_dmac - verify that the machine is no longer being referenced 
444  * and may safely be deleted.
445  */
446
447 int setup_dmac(q, argv)
448     struct query *q;
449     char **argv;
450 ##{
451 ##  int flag, id;
452
453     id = *(int *)argv[0];
454 ##  repeat retrieve (flag = any(users.login where users.potype = "POP" 
455 ##                                                and users.pop_id=@id))
456     if (ingres_errno != 0) return(ingres_errno);
457     if (flag)
458         return(SMS_IN_USE);
459 ##  repeat retrieve (flag = any(serverhosts.mach_id
460 ##                               where serverhosts.mach_id=@id))
461     if (ingres_errno != 0) return(ingres_errno);
462     if (flag)
463         return(SMS_IN_USE);
464 ##  repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
465     if (ingres_errno != 0) return(ingres_errno);
466     if (flag)
467         return(SMS_IN_USE);
468 ##  repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
469     if (ingres_errno != 0) return(ingres_errno);
470     if (flag)
471         return(SMS_IN_USE);
472 ##  repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
473     if (ingres_errno != 0) return(ingres_errno);
474     if (flag)
475         return(SMS_IN_USE);
476
477 ##  repeat delete mcmap where mcmap.mach_id = @id
478     if (ingres_errno != 0) return(ingres_errno);
479     return(SMS_SUCCESS);
480 ##}
481
482
483 /* setup_dclu - verify that the cluster is no longer being referenced 
484  * and may safely be deleted.
485  */
486
487 int setup_dclu(q, argv)
488     struct query *q;
489     char **argv;
490 ##{
491 ##  int flag, id;
492
493     id = *(int *)argv[0];
494 ##  repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
495     if (ingres_errno != 0) return(ingres_errno);
496     if (flag)
497         return(SMS_IN_USE);
498 ##  repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
499     if (ingres_errno != 0) return(ingres_errno);
500     if (flag)
501         return(SMS_IN_USE);
502     else
503         return(SMS_SUCCESS);
504 ##}
505
506
507 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
508  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
509  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
510  * a -1 there.  Remember that this is also used for ulis, with the indexes
511  * at 6 & 7.
512  */
513
514 int setup_alis(q, argv)
515 struct query *q;
516 char **argv;
517 ##{
518 ##  int ngid;
519     char *malloc();
520     int idx;
521
522     if (!strcmp(q->shortname, "alis"))
523       idx = 6;
524     else if (!strcmp(q->shortname, "ulis"))
525       idx = 7;
526
527     if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
528         if (atoi(argv[idx - 1])) {
529             if (set_next_object_id("gid", "list"))
530               return(SMS_INGRES_ERR);
531 ##          repeat retrieve (ngid = values.value) where values.name = "gid"
532             if (ingres_errno != 0) return(ingres_errno);
533             sprintf(argv[idx], "%d", ngid);
534         } else {
535             strcpy(argv[idx], "-1");
536         }
537     }
538
539     return(SMS_SUCCESS);
540 ##}
541
542
543 /* setup_dlist - verify that the list is no longer being referenced 
544  * and may safely be deleted.
545  */
546
547 int setup_dlis(q, argv)
548     struct query *q;
549     char **argv;
550 ##{
551 ##  int flag, id;
552
553     id = *(int *)argv[0];
554 ##  repeat retrieve (flag = any(members.member_id where members.member_id=@id
555 ##                       and members.member_type = "LIST"))
556     if (ingres_errno != 0) return(ingres_errno);
557     if (flag)
558         return(SMS_IN_USE);
559 ##  repeat retrieve (flag = any(members.member_id where members.list_id=@id))
560     if (ingres_errno != 0) return(ingres_errno);
561     if (flag)
562         return(SMS_IN_USE);
563 ##  repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
564     if (ingres_errno != 0) return(ingres_errno);
565     if (flag)
566         return(SMS_IN_USE);
567 ##  repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
568     if (ingres_errno != 0) return(ingres_errno);
569     if (flag)
570         return(SMS_IN_USE);
571 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
572 ##                      list.acl_type = "LIST" and list.list_id != @id))
573     if (ingres_errno != 0) return(ingres_errno);
574     if (flag)
575         return(SMS_IN_USE);
576 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
577 ##                      servers.acl_type = "LIST"))
578     if (ingres_errno != 0) return(ingres_errno);
579     if (flag)
580         return(SMS_IN_USE);
581 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
582 ##                      hostaccess.acl_type = "LIST"))
583     if (ingres_errno != 0) return(ingres_errno);
584     if (flag)
585         return(SMS_IN_USE);
586 ##  repeat retrieve (flag = any(zephyr.class
587 ##              where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
588 ##                    zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
589 ##                    zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
590 ##                    zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
591     if (ingres_errno != 0) return(ingres_errno);
592     if (flag)
593         return(SMS_IN_USE);
594     else
595         return(SMS_SUCCESS);
596 ##}
597
598
599 /* setup_dsin - verify that the service is no longer being referenced 
600  * and may safely be deleted.
601  */
602
603 int setup_dsin(q, argv)
604     struct query *q;
605     char **argv;
606 ##{
607 ##  int flag;
608 ##  char *name;
609
610     name = argv[0];
611 ##  repeat retrieve (flag = any(serverhosts.service 
612 ##                              where serverhosts.service=uppercase(@name)))
613     if (ingres_errno != 0) return(ingres_errno);
614     if (flag)
615         return(SMS_IN_USE);
616 ##  repeat retrieve (flag = servers.inprogress) where servers.#name = @name
617     if (ingres_errno != 0) return(ingres_errno);
618     if (flag)
619         return(SMS_IN_USE);
620     else
621         return(SMS_SUCCESS);
622 ##}
623
624
625 /* setup_dshi - verify that the service-host is no longer being referenced 
626  * and may safely be deleted.
627  */
628
629 int setup_dshi(q, argv)
630     struct query *q;
631     char **argv;
632 ##{
633 ##  int flag, id;
634 ##  char *name;
635
636     name = argv[0];
637     id = *(int *)argv[1];
638 ##  repeat retrieve (flag=serverhosts.inprogress) 
639 ##      where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
640     if (ingres_errno != 0) return(ingres_errno);
641     if (flag)
642         return(SMS_IN_USE);
643     else
644         return(SMS_SUCCESS);
645 ##}
646
647
648 /**
649  ** setup_add_filesys - verify existance of referenced file systems
650  **
651  ** Inputs:     Add
652  **   argv[1] - type
653  **   argv[2] - mach_id
654  **   argv[3] - name
655  **   argv[5] - access
656  **
657  ** Description:
658  **   - for type = RVD:
659  **        * allow anything
660  **   - for type = NFS:
661  **        * extract directory prefix from name
662  **        * verify mach_id/dir in nfsphys
663  **        * verify access in {r, w, R, W}
664  **
665  **  Side effect: sets variable var_phys_id to the ID of the physical
666  **     filesystem (nfsphys_id for NFS, 0 for RVD)
667  **
668  ** Errors:
669  **   SMS_NFS - specified directory not exported
670  **   SMS_FILESYS_ACCESS - invalid filesys access
671  **
672  **/
673
674 ##static int var_phys_id;
675
676 setup_afil(q, argv)
677     struct query *q;
678     char *argv[];
679 {
680     char *type;
681     int mach_id;
682     char *name;
683     char *access;  
684
685     type = argv[1];
686     mach_id = *(int *)argv[2];
687     name = argv[3];
688     access = argv[5];
689     var_phys_id = 0;
690
691     if (!strcmp(type, "NFS"))
692         return (check_nfs(mach_id, name, access));
693     else
694         return(SMS_SUCCESS);
695 }
696
697
698 /* Verify the arguments, depending on the FStype.  Also, if this is an
699  * NFS filesystem, then update any quotas for that filesystem to reflect
700  * the new phys_id.
701  */
702
703 setup_ufil(q, argv)
704     struct query *q;
705     char *argv[];
706 ##{
707     int mach_id, status;
708     char *type, *name, *access;  
709 ##  int fid;
710
711     type = argv[2];
712     mach_id = *(int *)argv[3];
713     name = argv[4];
714     access = argv[6];
715     var_phys_id = 0;
716
717     if (!strcmp(type, "NFS")) {
718         status = check_nfs(mach_id, name, access);
719         fid = *(int *)argv[0];
720 ##      replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
721         if (ingres_errno != 0) return(ingres_errno);
722         return(status);
723     } else
724       return(SMS_SUCCESS);
725 ##}
726
727
728 /* Find the NFS physical partition that the named directory is on.
729  * This is done by comparing the dir against the mount point of the
730  * partition.  To make sure we get the correct match when there is 
731  * more than one, we sort the query in reverse order by dir name.
732  */
733
734 ##check_nfs(mach_id, name, access)
735 ##  int mach_id;
736     char *name;
737     char *access;
738 ##{
739 ##  char dir[32];
740     char caccess;
741     register int status;
742     register char *cp1;
743     register char *cp2;
744
745     caccess = (isupper(*access)) ? tolower(*access) : *access;
746     if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
747
748     status = SMS_NFS;
749 ##  range of np is nfsphys
750 ##  repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
751 ##      where np.#mach_id = @mach_id sort by #dir:d {
752          cp1 = name;
753          cp2 = dir;
754          while (*cp2) {
755              if (*cp1++ != *cp2) break;
756              cp2++;
757          }
758          if (*cp2 == 0) {
759              status = SMS_SUCCESS;
760 ##           endretrieve
761          }
762 ##  }
763     if (ingres_errno != 0) return(ingres_errno);
764
765     return(status);
766 ##}
767
768
769 /* setup_dfil: free any quota records associated with a filesystem
770  * when it is deleted.
771  */
772
773 setup_dfil(q, argv, cl)
774     struct query  *q;
775     char **argv;
776     client *cl;
777 ##{
778 ##  int id;
779
780     id = *(int *)argv[0];
781 ##  range of q is nfsquota
782 ##  range of fs is filesys
783 ##  range of n is nfsphys
784 ##  repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
785 ##      where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
786     if (ingres_errno != 0) return(ingres_errno);
787
788 ##  repeat delete q where q.filsys_id = @id
789     if (ingres_errno != 0) return(ingres_errno);
790     return(SMS_SUCCESS);
791 ##}
792
793
794 /* setup_dnfp: check to see that the nfs physical partition does not have
795  * any filesystems assigned to it before allowing it to be deleted.
796  */
797
798 setup_dnfp(q, argv, cl)
799     struct query  *q;
800     char **argv;
801     client *cl;
802 ##{
803 ##  int id, exists;
804
805     id = *(int *)argv[0];
806 ##  repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
807     if (ingres_errno != 0) return(ingres_errno);
808     if (exists)
809       return(SMS_IN_USE);
810     return(SMS_SUCCESS);
811 ##}
812
813
814 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
815  *   argv[0] = filsys_id
816  *   argv[1] = users_id
817  */
818
819 setup_dnfq(q, argv, cl)
820     struct query  *q;
821     char **argv;
822     client *cl;
823 ##{
824 ##  int quota, fs, user;
825
826     fs = *(int *)argv[0];
827     user = *(int *)argv[1];
828
829 ##  range of q is nfsquota
830 ##  repeat retrieve (quota = q.#quota) where q.users_id = @user and
831 ##      q.filsys_id = @fs
832     if (ingres_errno != 0) return(ingres_errno);
833 ##  repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
834 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
835     if (ingres_errno != 0) return(ingres_errno);
836     return(SMS_SUCCESS);
837 ##}
838
839
840 \f
841 /* FOLLOWUP ROUTINES */
842
843 /* generic set_modtime routine.  This takes the table name from the query,
844  * and will update the modtime, modby, and modwho fields in the entry in
845  * the table whose name field matches argv[0].
846  */
847
848 set_modtime(q, argv, cl)
849     struct query *q;
850     char *argv[];
851     client *cl;
852 ##{
853 ##  char *name, *entity, *table;
854 ##  int who;
855
856     entity = cl->entity;
857     who = cl->users_id;
858     table = q->rtable;
859     name = argv[0];
860
861 ##  replace table (modtime = "now", modby = who, modwith = entity)
862 ##       where table.#name = name
863     if (ingres_errno != 0) return(ingres_errno);
864     return(SMS_SUCCESS);
865 ##}
866
867 /* generic set_modtime_by_id routine.  This takes the table name from
868  * the query, and the id name from the validate record,
869  * and will update the modtime, modby, and modwho fields in the entry in
870  * the table whose id matches argv[0].
871  */
872
873 set_modtime_by_id(q, argv, cl)
874     struct query *q;
875     char **argv;
876     client *cl;
877 ##{
878 ##  char *entity, *table, *id_name;
879 ##  int who, id;
880
881     entity = cl->entity;
882     who = cl->users_id;
883     table = q->rtable;
884     id_name = q->validate->object_id;
885
886     id = *(int *)argv[0];
887 ##  replace table (modtime = "now", modby = who, modwith = entity)
888 ##       where table.id_name = id
889     if (ingres_errno != 0) return(ingres_errno);
890     return(SMS_SUCCESS);
891 ##}
892
893
894 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
895  */
896
897 set_finger_modtime(q, argv, cl)
898     struct query *q;
899     char *argv[];
900     client *cl;
901 ##{
902 ##  int users_id, who;
903 ##  char *entity;
904
905     entity = cl->entity;
906     who = cl->users_id;
907     users_id = *(int *)argv[0];
908
909 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
910 ##       where u.#users_id = @users_id
911     if (ingres_errno != 0) return(ingres_errno);
912     return(SMS_SUCCESS);
913 ##}
914
915
916 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
917  */
918
919 set_pobox_modtime(q, argv, cl)
920     struct query *q;
921     char **argv;
922     client *cl;
923 ##{
924 ##  int users_id, who;
925 ##  char *entity;
926
927     entity = cl->entity;
928     who = cl->users_id;
929     users_id = *(int *)argv[0];
930
931 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
932 ##       where users.#users_id = @users_id
933     if (ingres_errno != 0) return(ingres_errno);
934     return(SMS_SUCCESS);
935 ##}
936
937
938 /* Sets the modtime on a machine record.  The machine name is in argv[0].
939  * This routine is different from the generic set_modtime in that the
940  * name is uppercased first.
941  */
942
943 set_mach_modtime(q, argv, cl)
944     struct query *q;
945     char **argv;
946     client *cl;
947 ##{
948 ##  char *host, *entity;
949 ##  int who;
950
951     entity = cl->entity;
952     who = cl->users_id;
953
954     host = argv[0];
955 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
956 ##       where m.name = uppercase(@host)
957     if (ingres_errno != 0) return(ingres_errno);
958     return(SMS_SUCCESS);
959 ##}
960
961
962 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
963  * is necessary for add_machine_to_cluster becuase the table that query
964  * operates on is "mcm", not "machine".
965  */
966
967 set_mach_modtime_by_id(q, argv, cl)
968     struct query *q;
969     char **argv;
970     client *cl;
971 ##{
972 ##  char *entity;
973 ##  int who, id;
974
975     entity = cl->entity;
976     who = cl->users_id;
977
978     id = *(int *)argv[0];
979 ##  range of m is machine
980 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
981 ##       where m.mach_id = @id
982     if (ingres_errno != 0) return(ingres_errno);
983     return(SMS_SUCCESS);
984 ##}
985
986
987 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
988  * is necessary for add_cluster_data and delete_cluster_data becuase the
989  * table that query operates on is "svc", not "cluster".
990  */
991
992 set_cluster_modtime_by_id(q, argv, cl)
993     struct query *q;
994     char **argv;
995     client *cl;
996 ##{
997 ##  char *entity;
998 ##  int who, id;
999
1000     entity = cl->entity;
1001     who = cl->users_id;
1002
1003     id = *(int *)argv[0];
1004 ##  range of c is cluster
1005 ##  repeat replace c (modtime = "now", modby = @who, modwith = @entity)
1006 ##       where c.clu_id = @id
1007     if (ingres_errno != 0) return(ingres_errno);
1008     return(SMS_SUCCESS);
1009 ##}
1010
1011
1012 /* sets the modtime on the serverhost where the service name is in argv[0]
1013  * and the mach_id is in argv[1].
1014  */
1015
1016 set_serverhost_modtime(q, argv, cl)
1017     struct query *q;
1018     char **argv;
1019     client *cl;
1020 ##{
1021 ##  char *entity, *serv;
1022 ##  int who, id;
1023
1024     entity = cl->entity;
1025     who = cl->users_id;
1026
1027     serv = argv[0];
1028     id = *(int *)argv[1];
1029 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1030 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
1031     if (ingres_errno != 0) return(ingres_errno);
1032     return(SMS_SUCCESS);
1033 ##}
1034
1035
1036 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1037  * directory name is in argv[1].
1038  */
1039
1040 set_nfsphys_modtime(q, argv, cl)
1041     struct query *q;
1042     char **argv;
1043     client *cl;
1044 ##{
1045 ##  char *entity, *dir;
1046 ##  int who, id;
1047
1048     entity = cl->entity;
1049     who = cl->users_id;
1050
1051     id = *(int *)argv[0];
1052     dir = argv[1];
1053 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1054 ##       where np.#dir = @dir and np.mach_id = @id
1055     if (ingres_errno != 0) return(ingres_errno);
1056     return(SMS_SUCCESS);
1057 ##}
1058
1059
1060 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1061  * label.
1062  */
1063
1064 set_filesys_modtime(q, argv, cl)
1065     struct query *q;
1066     char *argv[];
1067     client *cl;
1068 ##{
1069 ##  char *label, *entity;
1070 ##  int who;
1071
1072     entity = cl->entity;
1073     who = cl->users_id;
1074
1075     label = argv[0];
1076     if (!strcmp(q->shortname, "ufil"))
1077       label = argv[1];
1078
1079 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1080 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1081     if (ingres_errno != 0) return(ingres_errno);
1082     return(SMS_SUCCESS);
1083 ##}
1084
1085
1086 /* sets the modtime on a zephyr class, where argv[0] contains the class
1087  * name.
1088  */
1089
1090 set_zephyr_modtime(q, argv, cl)
1091     struct query *q;
1092     char *argv[];
1093     client *cl;
1094 ##{
1095 ##  char *class, *entity;
1096 ##  int who;
1097
1098     entity = cl->entity;
1099     who = cl->users_id;
1100
1101     class = argv[0];
1102
1103 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1104 ##                     where z.#class = @class
1105     if (ingres_errno != 0) return(ingres_errno);
1106     return(SMS_SUCCESS);
1107 ##}
1108
1109
1110 /* fixes the modby field.  This will be the second to last thing in the
1111  * argv, the argv length is determined from the query structure.  It is
1112  * passed as a pointer to an integer.  This will either turn it into a
1113  * username, or # + the users_id.
1114  */
1115 followup_fix_modby(q, sq, v, action, actarg, cl)
1116     struct query *q;
1117     register struct save_queue *sq;
1118     struct validate *v;
1119     register int (*action)();
1120     register int actarg;
1121     client *cl;
1122 ##{
1123     register int i, j;
1124     char **argv, *malloc();
1125 ##  int id, rowcount;
1126 ##  char *name;
1127
1128     i = q->vcnt - 2;
1129     while (sq_get_data(sq, &argv)) {
1130         id = atoi(argv[i]);
1131         free(argv[i]);
1132         argv[i] = malloc(9);
1133         name = argv[i];
1134 ##      repeat retrieve (name = users.login) where users.users_id = @id
1135 ##      inquire_equel(rowcount = "rowcount")
1136         if (rowcount != 1) {
1137             sprintf(argv[i], "#%d", id);
1138         }
1139         (*action)(q->vcnt, argv, actarg);
1140         for (j = 0; j < q->vcnt; j++)
1141           free(argv[j]);
1142         free(argv);
1143     }
1144     sq_destroy(sq);
1145     return(SMS_SUCCESS);
1146 ##}
1147
1148
1149 /**
1150  ** followup_ausr - add finger and pobox entries, set_user_modtime
1151  **
1152  ** Inputs:
1153  **     argv[0] - login (add_user)
1154  **     argv[3] - last name
1155  **     argv[4] - first name
1156  **     argv[5] - middle name
1157  **
1158  **/
1159
1160 followup_ausr(q, argv, cl)
1161     struct query *q;
1162     char *argv[];
1163     client *cl;
1164 ##{
1165 ##  int who;
1166 ##  char *login, *entity;
1167 ##  char fullname[129];
1168
1169     login = argv[0];
1170     who = cl->users_id;
1171     entity = cl->entity;
1172
1173     /* build fullname */
1174     if (strlen(argv[4]) && strlen(argv[5]))
1175         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1176     else if (strlen(argv[4]))
1177         sprintf(fullname, "%s %s", argv[4], argv[3]);
1178     else
1179         sprintf(fullname, "%s", argv[3]);
1180
1181     /* create finger entry, pobox & set modtime on user */
1182 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1183 ##           #fullname=@fullname, mit_affil = u.mit_year,
1184 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1185 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1186 ##      where u.#login = @login
1187     if (ingres_errno != 0) return(ingres_errno);
1188
1189     return(SMS_SUCCESS);
1190 ##}
1191
1192
1193 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1194  * type in argv[1].  Then completes the upcall to the user.
1195  *
1196  * argv[2] is of the form "123:234" where the first integer is the machine
1197  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1198  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1199  * are skipped.
1200  */
1201
1202 followup_gpob(q, sq, v, action, actarg, cl)
1203     register struct query *q;
1204     register struct save_queue *sq;
1205     register struct validate *v;
1206     register int (*action)();
1207     int actarg;
1208     client *cl;
1209 ##{
1210     char **argv, *index();
1211     char *ptype, *p;
1212 ##  char box[129], *name;
1213 ##  int mid, sid, rowcount;
1214
1215     /* for each row */
1216     while (sq_get_data(sq, &argv)) {
1217         sms_trim_args(2, argv);
1218         ptype = argv[1];
1219         p = index(argv[2], ':');
1220         *p++ = 0;
1221         mid = atoi(argv[2]);
1222         sid = atoi(p);
1223         free(argv[2]);
1224
1225         if (!strcmp(ptype, "POP")) {
1226 ##          repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1227 ##          inquire_equel(rowcount = "rowcount")
1228             if (rowcount != 1)
1229               return(SMS_MACHINE);
1230         } else if (!strcmp(ptype, "SMTP")) {
1231 ##          repeat retrieve (box=strings.string) where strings.string_id=@sid
1232 ##          inquire_equel(rowcount = "rowcount")
1233             if (rowcount != 1)
1234               return(SMS_STRING);
1235         } else /* ptype == "NONE" */ {
1236             goto skip;
1237         }
1238
1239         if (!strcmp(q->shortname, "gpob")) {
1240             sid = atoi(argv[4]);
1241             free(argv[4]);
1242             argv[4] = malloc(9);
1243             name = argv[4];
1244 ##          repeat retrieve (name = users.login) where users.users_id = @sid
1245 ##          inquire_equel(rowcount = "rowcount")
1246             if (rowcount != 1)
1247               sprintf(name, "#%d", sid);
1248         }
1249
1250         argv[2] = box;
1251         (*action)(q->vcnt, argv, actarg);
1252     skip:
1253         /* free saved data */
1254         free(argv[0]);
1255         free(argv[1]);
1256         free(argv);
1257     }
1258
1259     sq_destroy(sq);
1260     return (SMS_SUCCESS);
1261 ##}
1262
1263
1264 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1265  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1266  * proper name based on the type, and repace that string in the argv.
1267  * Also fixes the modby field by called followup_fix_modby.
1268  */
1269
1270 followup_glin(q, sq, v, action, actarg, cl)
1271     register struct query *q;
1272     register struct save_queue *sq;
1273     register struct validate *v;
1274     register int (*action)();
1275     int actarg;
1276     client *cl;
1277 ##{
1278     char **argv, *malloc(), *realloc(), *type;
1279 ##  char *name;
1280 ##  int id, rowcount;
1281     int i, idx;
1282
1283     idx = 8;
1284     if (!strcmp(q->shortname, "gsin"))
1285       idx = 12;
1286
1287     while (sq_get_data(sq, &argv)) {
1288         sms_trim_args(q->vcnt, argv);
1289
1290         id = atoi(argv[i = q->vcnt - 2]);
1291         free(argv[i]);
1292         name = argv[i] = malloc(9);
1293 ##      repeat retrieve (name = users.login) where users.users_id = @id
1294 ##      inquire_equel(rowcount = "rowcount")
1295         if (rowcount != 1)
1296           sprintf(argv[i], "#%d", id);
1297
1298         id = atoi(argv[idx]);
1299         type = argv[idx - 1];
1300         if ((name = malloc(33)) == NULL)
1301             return(SMS_NO_MEM);
1302
1303         if (!strcmp(type, "LIST")) {
1304 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1305 ##          inquire_equel(rowcount = "rowcount")
1306             if (rowcount != 1)
1307                 strcpy(name, "???");
1308         } else if (!strcmp(type, "USER")) {
1309 ##          repeat retrieve (name = users.login) where users.users_id = @id
1310 ##          inquire_equel(rowcount = "rowcount")
1311             if (rowcount != 1)
1312                 strcpy(name, "???");
1313         } else if (!strcmp(type, "NONE")) {
1314             strcpy(name, "NONE");
1315         } else
1316           strcpy(name, "???");
1317         free(argv[idx]);
1318         argv[idx] = name;
1319
1320         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1321             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1322             strcpy(argv[6], UNIQUE_GID);
1323         }
1324
1325         /* send the data */
1326         (*action)(q->vcnt, argv, actarg);
1327
1328         /* free saved data */
1329         for (i = 0; i < q->vcnt; i++) 
1330             free(argv[i]);
1331         free(argv);
1332     }
1333
1334     sq_destroy(sq);
1335     return (SMS_SUCCESS);
1336 ##}
1337
1338
1339 /** followup_amtl - followup for amtl and dmfl; when adding a list 
1340  **                 member to a maillist, make member list a maillist also
1341  **                 unless list is a user-group.
1342  **                 Then set_list_modtime_by_id.
1343  **
1344  ** Inputs:
1345  **   argv[0] - list_id
1346  **   argv[1] - member_type
1347  **   argv[2] - member_id
1348  **
1349  **/
1350
1351 followup_amtl(q, argv, cl)
1352     struct query *q;
1353     char *argv[];
1354     client *cl;
1355 ##{
1356 ##  int list_id;
1357 ##  int member_id;
1358 ##  int exists, who;
1359 ##  char *entity;
1360
1361     list_id = *(int *)argv[0];
1362     entity = cl->entity;
1363     who = cl->users_id;
1364
1365 ##  range of l is list
1366 ##  repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1367 ##       where l.#list_id = @list_id
1368     if (ingres_errno != 0) return(ingres_errno);
1369
1370     /* if query is not amtl or if member_type is not LIST then return */
1371     if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4)) 
1372         return(SMS_SUCCESS);
1373
1374     member_id = *(int *)argv[2];
1375
1376     /* is parent list a mailing list? */
1377 ##  repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1378     if (ingres_errno != 0) return(ingres_errno);
1379     if (!exists)
1380         return(SMS_SUCCESS);
1381
1382     /* list is not a user-group; add list to maillist table */
1383 ##  repeat replace l (maillist = 1) where l.#list_id = @member_id
1384     if (ingres_errno != 0) return(ingres_errno);
1385     return(SMS_SUCCESS);
1386 ##}
1387
1388
1389 /* followup_anfq: Add allocation to nfsphys after creating quota.
1390  *   argv[0] = filsys_id
1391  *   argv[2] = ascii(quota)
1392  */
1393
1394 followup_anfq(q, argv, cl)
1395     struct query  *q;
1396     char **argv;
1397     client *cl;
1398 ##{
1399 ##  int quota, user, fs, who;
1400 ##  char *entity;
1401
1402     fs = *(int *)argv[0];
1403     user = *(int *)argv[1];
1404     quota = atoi(argv[2]);
1405     who = cl->users_id;
1406     entity = cl->entity;
1407
1408 ##  repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1409 ##      where nq.filsys_id = @fs and nq.users_id = @user
1410     if (ingres_errno != 0) return(ingres_errno);
1411 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1412 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1413     if (ingres_errno != 0) return(ingres_errno);
1414     return(SMS_SUCCESS);
1415 ##}
1416
1417
1418 /* followup_gzcl:
1419  */
1420
1421 followup_gzcl(q, sq, v, action, actarg, cl)
1422     register struct query *q;
1423     register struct save_queue *sq;
1424     register struct validate *v;
1425     register int (*action)();
1426     int actarg;
1427     client *cl;
1428 ##{
1429 ##  char *name;
1430 ##  int rowcount, id;
1431     char **argv;
1432     int i;
1433
1434     while (sq_get_data(sq, &argv)) {
1435         sms_trim_args(q->vcnt, argv);
1436
1437         id = atoi(argv[i = q->vcnt - 2]);
1438         free(argv[i]);
1439         name = argv[i] = malloc(9);
1440 ##      repeat retrieve (name = users.login) where users.users_id = @id
1441 ##      inquire_equel(rowcount = "rowcount")
1442         if (rowcount != 1)
1443           sprintf(argv[i], "#%d", id);
1444
1445         for (i = 1; i < 8; i+=2) {
1446             id = atoi(argv[i+1]);
1447             free(argv[i+1]);
1448             if ((name = argv[i+1] = malloc(33)) == NULL)
1449               return(SMS_NO_MEM);
1450             if (!strcmp(argv[i], "LIST")) {
1451 ##              repeat retrieve (name = list.#name) where list.list_id = @id
1452 ##              inquire_equel(rowcount = "rowcount")
1453                 if (rowcount != 1)
1454                   strcpy(name, "???");
1455             } else if (!strcmp(argv[i], "USER")) {
1456 ##              repeat retrieve (name = users.login) where users.users_id = @id
1457 ##              inquire_equel(rowcount = "rowcount")
1458                 if (rowcount != 1)
1459                   strcpy(name, "???");
1460             } else if (!strcmp(argv[i], "NONE")) {
1461                 strcpy(name, "NONE");
1462             } else {
1463                 strcpy(name, "???");
1464             }
1465         }
1466
1467         /* send the data */
1468         (*action)(q->vcnt, argv, actarg);
1469
1470         /* free saved data */
1471         for (i = 0; i < q->vcnt; i++) 
1472             free(argv[i]);
1473         free(argv);
1474     }
1475     sq_destroy(sq);
1476     return(SMS_SUCCESS);
1477 ##}
1478
1479
1480 /* followup_gsha:
1481  */
1482
1483 followup_gsha(q, sq, v, action, actarg, cl)
1484     register struct query *q;
1485     register struct save_queue *sq;
1486     register struct validate *v;
1487     register int (*action)();
1488     int actarg;
1489     client *cl;
1490 ##{
1491 ##  char *name;
1492 ##  int rowcount, id;
1493     char **argv;
1494     int i;
1495
1496     while (sq_get_data(sq, &argv)) {
1497         sms_trim_args(q->vcnt, argv);
1498
1499         id = atoi(argv[4]);
1500         free(argv[4]);
1501         name = argv[4] = malloc(9);
1502 ##      repeat retrieve (name = users.login) where users.users_id = @id
1503 ##      inquire_equel(rowcount = "rowcount")
1504         if (rowcount != 1)
1505           sprintf(argv[4], "#%d", id);
1506
1507         id = atoi(argv[2]);
1508         free(argv[2]);
1509         if ((name = argv[2] = malloc(33)) == NULL)
1510           return(SMS_NO_MEM);
1511         if (!strcmp(argv[1], "LIST")) {
1512 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1513 ##          inquire_equel(rowcount = "rowcount")
1514             if (rowcount != 1)
1515               strcpy(name, "???");
1516         } else if (!strcmp(argv[1], "USER")) {
1517 ##          repeat retrieve (name = users.login) where users.users_id = @id
1518 ##          inquire_equel(rowcount = "rowcount")
1519             if (rowcount != 1)
1520               strcpy(name, "???");
1521         } else if (!strcmp(argv[1], "NONE")) {
1522             strcpy(name, "NONE");
1523         } else {
1524             strcpy(name, "???");
1525         }
1526
1527         /* send the data */
1528         (*action)(q->vcnt, argv, actarg);
1529
1530         /* free saved data */
1531         for (i = 0; i < q->vcnt; i++) 
1532             free(argv[i]);
1533         free(argv);
1534     }
1535     sq_destroy(sq);
1536     return(SMS_SUCCESS);
1537 ##}
1538
1539
1540 \f
1541 /* Special query routines */
1542
1543 /* set_pobox - this does all of the real work.
1544  *       argv = user_id, type, box
1545  * if type is POP, then box should be a machine, and its ID should be put in
1546  * pop_id.  If type is SMTP, then box should be a string and its ID should
1547  * be put in box_id.  If type is NONE, then box doesn't matter.
1548  */
1549
1550 int set_pobox(q, argv, cl)
1551     struct query *q;
1552     char **argv;
1553     client *cl;
1554 ##{
1555 ##  int user, id, rowcount;
1556 ##  char *box, potype[9];
1557
1558     box = argv[2];
1559     user = *(int *)argv[0];
1560
1561 ##  repeat retrieve (id = users.pop_id, potype = users.#potype)
1562 ##              where users.users_id = @user
1563     if (ingres_errno != 0) return(ingres_errno);
1564     if (!strcmp(strtrim(potype), "POP"))
1565       set_pop_usage(id, -1);
1566
1567     if (!strcmp(argv[1], "POP")) {
1568 ##      repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1569         if (ingres_errno != 0) return(ingres_errno);
1570 ##      inquire_equel(rowcount = "rowcount")
1571         if (rowcount != 1)
1572             return(SMS_MACHINE);
1573 ##      repeat replace users (#potype = "POP", pop_id = @id)
1574 ##              where users.users_id = @user
1575         if (ingres_errno != 0) return(ingres_errno);
1576         set_pop_usage(id, 1);
1577     } else if (!strcmp(argv[1], "SMTP")) {
1578 ##      range of s is strings
1579 ##      repeat retrieve (id = s.string_id) where s.string = @box
1580         if (ingres_errno != 0) return(ingres_errno);
1581 ##      inquire_equel (rowcount = "rowcount")
1582         if (rowcount == 0) {
1583 ##          range of v is values
1584 ##          repeat retrieve (id = v.value) where v.name = "strings_id"
1585             if (ingres_errno != 0) return(ingres_errno);
1586             id++;
1587 ##          repeat replace v (value = @id) where v.name = "strings_id"
1588             if (ingres_errno != 0) return(ingres_errno);
1589 ##          append to strings (string_id = id, string = box)
1590             if (ingres_errno != 0) return(ingres_errno);
1591         }
1592 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1593 ##             where users.users_id = @user
1594         if (ingres_errno != 0) return(ingres_errno);
1595     } else /* argv[1] == "NONE" */ {
1596 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1597     if (ingres_errno != 0) return(ingres_errno);
1598     }
1599
1600     set_pobox_modtime(q, argv, cl);
1601 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1602 ##      where tblstats.#table = "users"
1603     if (ingres_errno != 0) return(ingres_errno);
1604     return(SMS_SUCCESS);
1605 ##}
1606
1607
1608 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1609  * each list.  This is tricky:  first build a queue of all requested
1610  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1611  */
1612
1613 get_list_info(q, aargv, cl, action, actarg)
1614     register struct query *q;
1615     char **aargv;
1616     client *cl;
1617     register int (*action)();
1618     int actarg;
1619 ##{
1620     char *argv[13], *malloc(), *realloc();
1621 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1622 ##  char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1623 ##  char modby[9], modwith[9];
1624 ##  int id, rowcount, acl_id, hid, modby_id;
1625     int returned;
1626     struct save_queue *sq, *sq_create();
1627
1628     returned = rowcount = 0;
1629     name = aargv[0];
1630
1631     sq = sq_create();
1632 ##  range of l is list
1633 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1634         sq_save_data(sq, id);
1635         rowcount++;
1636 ##  }
1637     if (rowcount == 0)
1638       return(SMS_NO_MATCH);
1639
1640     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1641     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1642     argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1643     argv[12] = modwith;
1644
1645     while (sq_get_data(sq, &id)) {
1646         if (id == 0)
1647           continue;
1648         argv[6] = gid;
1649 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1650 ##              public = text(l.#public), hidden = text(l.#hidden),
1651 ##              hid = l.#hidden, maillist = text(l.#maillist),
1652 ##              group = text(l.#group), gid = text(l.#gid),
1653 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1654 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1655 ##              modwith =l.#modwith)
1656 ##          where l.list_id = @id
1657
1658         if (atoi(gid) == -1)
1659             argv[6] = UNIQUE_GID;
1660
1661         if (!strcmp(acl_type, "LIST")) {
1662 ##          repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1663 ##          inquire_equel(rowcount = "rowcount")
1664             if (rowcount != 1)
1665                 strcpy(acl_name, "???");
1666         } else if (!strcmp(acl_type, "USER")) {
1667 ##          repeat retrieve (acl_name = users.#login)
1668 ##              where users.users_id = @acl_id
1669 ##          inquire_equel(rowcount = "rowcount")
1670             if (rowcount != 1)
1671                 strcpy(acl_name, "???");
1672         } else if (!strcmp(acl_type, "NONE")) {
1673             strcpy(acl_name, "NONE");
1674         } else
1675           strcpy(acl_name, "???");
1676
1677 ##      repeat retrieve (modby = users.login) where users.users_id = @modby_id
1678 ##      inquire_equel(rowcount = "rowcount")
1679         if (rowcount != 1)
1680           sprintf(modby, "#%d", id);
1681
1682         sms_trim_args(q->vcnt, argv);
1683         returned++;
1684         (*action)(q->vcnt, argv, actarg);
1685     }
1686
1687     sq_destroy(sq);
1688 #ifdef notdef
1689 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1690 ##      where tblstats.#table = "list"
1691 #endif
1692     return (SMS_SUCCESS);
1693 ##}
1694
1695
1696 /* get_ace_use - given a type and a name, return a type and a name.
1697  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1698  * and argv[1] will contain the ID of the entity in question.  The R*
1699  * types mean to recursively look at every containing list, not just
1700  * when the object in question is a direct member.  On return, the
1701  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1702  */
1703
1704 int get_ace_use(q, argv, cl, action, actarg)
1705     struct query *q;
1706     char *argv[];
1707     client *cl;
1708     int (*action)();
1709     int actarg;
1710 ##{
1711     int found = 0;
1712 ##  char *atype;
1713 ##  int aid, listid, id;
1714     struct save_queue *sq, *sq_create();
1715
1716     atype = argv[0];
1717     aid = *(int *)argv[1];
1718     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1719         return(get_ace_internal(atype, aid, action, actarg));
1720     }
1721
1722     sq = sq_create();
1723     if (!strcmp(atype, "RLIST")) {
1724         sq_save_data(sq, aid);
1725         /* get all the list_id's of containing lists */
1726 ##      range of m is members
1727         while (sq_get_data(sq, &id)) {
1728 ##          repeat retrieve (listid = m.list_id)
1729 ##              where m.member_type = "LIST" and m.member_id = @id {
1730               sq_save_unique_data(sq, listid);
1731 ##          }
1732           }
1733         /* now process each one */
1734         while (sq_get_data(sq, &id)) {
1735             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1736               found++;
1737         }
1738     }
1739
1740     if (!strcmp(atype, "RUSER")) {
1741 ##      range of m is members
1742 ##      repeat retrieve (listid = m.list_id)
1743 ##              where m.member_type = "USER" and m.member_id = @aid {
1744             sq_save_data(sq, listid);
1745 ##      }
1746         /* get all the list_id's of containing lists */
1747         while (sq_get_data(sq, &id)) {
1748 ##          repeat retrieve (listid = m.list_id)
1749 ##              where m.member_type = "LIST" and m.member_id = @id {
1750               sq_save_unique_data(sq, listid);
1751 ##          }
1752           }
1753         /* now process each one */
1754         while (sq_get_data(sq, &id)) {
1755             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1756               found++;
1757         }
1758         if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1759           found++;
1760     }
1761
1762     sq_destroy(sq);     
1763     if (!found) return(SMS_NO_MATCH);
1764     return(SMS_SUCCESS);
1765 ##}
1766
1767
1768 /* This looks up a single list or user for ace use.  atype must be "USER"
1769  * or "LIST", and aid is the ID of the corresponding object.  This is used
1770  * by get_ace_use above.
1771  */
1772
1773 ##get_ace_internal(atype, aid, action, actarg)
1774 ##  char *atype;
1775 ##  int aid;
1776     int (*action)();
1777     int actarg;
1778 ##{
1779     char *rargv[2];
1780     int found = 0;
1781 ##  char name[33];
1782
1783     rargv[1] = name;
1784     if (!strcmp(atype, "LIST")) {
1785         rargv[0] = "FILESYS";
1786 ##      repeat retrieve (name = filesys.label) 
1787 ##              where filesys.owners = @aid {
1788             (*action)(2, rargv, actarg);
1789             found++;
1790 ##      }
1791
1792         rargv[0] = "QUERY";
1793 ##      repeat retrieve (name = capacls.capability)
1794 ##              where capacls.list_id = @aid {
1795             (*action)(2, rargv, actarg);
1796             found++;
1797 ##      }
1798     } else if (!strcmp(atype, "USER")) {
1799         rargv[0] = "FILESYS";
1800 ##      repeat retrieve (name = filesys.label) 
1801 ##              where filesys.owner = @aid {
1802             (*action)(2, rargv, actarg);
1803             found++;
1804 ##      }
1805     }
1806
1807     rargv[0] = "LIST";
1808 ##  repeat retrieve (name = list.#name) 
1809 ##              where list.acl_type = @atype and list.acl_id = @aid {
1810          (*action)(2, rargv, actarg);
1811          found++;
1812 ##  }
1813
1814     rargv[0] = "SERVICE";
1815 ##  repeat retrieve (name = servers.#name) 
1816 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
1817          (*action)(2, rargv, actarg);
1818          found++;
1819 ##  }
1820
1821     rargv[0] = "HOSTACCESS";
1822 ##  repeat retrieve (name = machine.#name)
1823 ##              where machine.mach_id = hostaccess.mach_id and 
1824 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1825         (*action)(2, rargv, actarg);
1826         found++;
1827 ##  }
1828     rargv[0] = "ZEPHYR";
1829 ##  repeat retrieve (name = zephyr.class) 
1830 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1831 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1832 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1833 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1834          (*action)(2, rargv, actarg);
1835          found++;
1836 ##  }
1837
1838     if (!found) return(SMS_NO_MATCH);
1839     return(SMS_SUCCESS);
1840 ##}
1841
1842
1843 /* get_lists_of_member - given a type and a name, return the name and flags
1844  * of all of the lists of the given member.  The member_type is one of
1845  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1846  * and argv[1] will contain the ID of the entity in question.  The R*
1847  * types mean to recursively look at every containing list, not just
1848  * when the object in question is a direct member.
1849  */
1850
1851 int get_lists_of_member(q, argv, cl, action, actarg)
1852     struct query *q;
1853     char *argv[];
1854     client *cl;
1855     int (*action)();
1856     int actarg;
1857 ##{
1858     int found = 0;
1859 ##  char *atype;
1860 ##  int aid, listid, id;
1861     struct save_queue *sq, *sq_create();
1862
1863     atype = argv[0];
1864     aid = *(int *)argv[1];
1865     if (!strcmp(atype, "LIST") ||
1866         !strcmp(atype, "USER") ||
1867         !strcmp(atype, "STRING")) {
1868       return(glom_internal(atype, aid, action, actarg));
1869     }
1870
1871     sq = sq_create();
1872     if (!strcmp(atype, "RLIST")) {
1873         sq_save_data(sq, aid);
1874         /* get all the list_id's of containing lists */
1875 ##      range of m is members
1876         while (sq_get_data(sq, &id)) {
1877 ##          repeat retrieve (listid = m.list_id)
1878 ##              where m.member_type = "LIST" and m.member_id = @id {
1879               sq_save_unique_data(sq, listid);
1880 ##          }
1881           }
1882         /* now process each one */
1883         while (sq_get_data(sq, &id)) {
1884             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1885               found++;
1886         }
1887     }
1888
1889     if (!strcmp(atype, "RUSER")) {
1890 ##      range of m is members
1891 ##      repeat retrieve (listid = m.list_id)
1892 ##              where m.member_type = "USER" and m.member_id = @aid {
1893             sq_save_data(sq, listid);
1894 ##      }
1895         /* get all the list_id's of containing lists */
1896         while (sq_get_data(sq, &id)) {
1897 ##          repeat retrieve (listid = m.list_id)
1898 ##              where m.member_type = "LIST" and m.member_id = @id {
1899               sq_save_unique_data(sq, listid);
1900 ##          }
1901           }
1902         /* now process each one */
1903         while (sq_get_data(sq, &id)) {
1904             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1905               found++;
1906         }
1907         if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1908           found++;
1909     }
1910
1911     if (!strcmp(atype, "RSTRING")) {
1912 ##      range of m is members
1913 ##      repeat retrieve (listid = m.list_id)
1914 ##              where m.member_type = "STRING" and m.member_id = @aid {
1915             sq_save_data(sq, listid);
1916 ##      }
1917         /* get all the list_id's of containing lists */
1918         while (sq_get_data(sq, &id)) {
1919 ##          repeat retrieve (listid = m.list_id)
1920 ##              where m.member_type = "LIST" and m.member_id = @id {
1921               sq_save_unique_data(sq, listid);
1922 ##          }
1923           }
1924         /* now process each one */
1925         while (sq_get_data(sq, &id)) {
1926             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1927               found++;
1928         }
1929         if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1930           found++;
1931     }
1932
1933 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1934 ##      where tblstats.#table = "members"
1935     sq_destroy(sq);     
1936     if (!found) return(SMS_NO_MATCH);
1937     return(SMS_SUCCESS);
1938 ##}
1939
1940
1941 /* This looks up a single list, user, or string as a member.  atype must be
1942  * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1943  * This is used by get_lists_of_members above.
1944  */
1945
1946 ##glom_internal(atype, aid, action, actarg)
1947 ##  char *atype;
1948 ##  int aid;
1949     int (*action)();
1950     int actarg;
1951 ##{
1952     char *rargv[6];
1953     int found = 0;
1954 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1955
1956     rargv[0] = name;
1957     rargv[1] = active;
1958     rargv[2] = public;
1959     rargv[3] = hidden;
1960     rargv[4] = maillist;
1961     rargv[5] = group;
1962 ##  repeat retrieve (name = list.#name, active = text(list.#active), 
1963 ##                   public = text(list.#public), hidden = text(list.#hidden),
1964 ##                   maillist = text(list.#maillist), group = text(list.#group))
1965 ##              where list.list_id = m.list_id and
1966 ##                    m.member_type = @atype and m.member_id = @aid {
1967          (*action)(6, rargv, actarg);
1968          found++;
1969 ##  }
1970
1971     if (!found) return(SMS_NO_MATCH);
1972     return(SMS_SUCCESS);
1973 ##}
1974
1975
1976 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1977  * the five flags associated with each list.  It will return the name of
1978  * each list that meets the quailifications.  It does this by building a
1979  * where clause based on the arguments, then doing a retrieve.
1980  */
1981
1982 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1983
1984 int qualified_get_lists(q, argv, cl, action, actarg)
1985     struct query *q;
1986     char *argv[];
1987     client *cl;
1988     int (*action)();
1989     int actarg;
1990 {
1991     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1992                          "l", "name", lflags));
1993 }
1994
1995
1996 /** get_members_of_list - optimized query for retrieval of list members
1997  **
1998  ** Inputs:
1999  **   argv[0] - list_id
2000  **
2001  ** Description:
2002  **   - retrieve USER members, then LIST members, then STRING members
2003  **/
2004
2005 get_members_of_list(q, argv, cl, action, actarg)
2006     struct query *q;
2007     char *argv[];
2008     client *cl;
2009     int (*action)();
2010     int actarg;
2011 ##{
2012 ##  int list_id;
2013 ##  char member_name[129];
2014     char *targv[2];
2015
2016     list_id = *(int *)argv[0];
2017     targv[0] = "USER";
2018     targv[1] = member_name;
2019
2020 ##  range of m is members
2021 ##  repeat retrieve (member_name = users.login)
2022 ##             where m.#list_id = @list_id and m.member_type = "USER"
2023 ##                   and m.member_id = users.users_id
2024 ##             sort by #member_name
2025 ##  {
2026          (*action)(2, targv, actarg);
2027 ##  }
2028
2029     targv[0] = "LIST";
2030 ##  repeat retrieve (member_name = list.name)
2031 ##             where m.#list_id = @list_id and m.member_type = "LIST"
2032 ##                   and m.member_id = list.#list_id
2033 ##             sort by #member_name
2034 ##  {
2035          (*action)(2, targv, actarg);
2036 ##  }
2037
2038     targv[0] = "STRING";
2039 ##  repeat retrieve (member_name = strings.string)
2040 ##             where m.#list_id = @list_id and m.member_type = "STRING"
2041 ##                   and m.member_id = strings.string_id
2042 ##             sort by #member_name
2043 ##  {
2044          (*action)(2, targv, actarg);
2045 ##  }
2046
2047 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2048 ##      where tblstats.#table = "members"
2049     return(SMS_SUCCESS);
2050 ##}
2051
2052
2053 /* count_members_of_list: this is a simple query, but it cannot be done
2054  * through the dispatch table.
2055  */
2056
2057 int count_members_of_list(q, argv, cl, action, actarg)
2058     struct query *q;
2059     char *argv[];
2060     client *cl;
2061     int (*action)();
2062     int actarg;
2063 ##{
2064 ##  int  list, ct = 0;
2065     char *rargv[1], countbuf[5];
2066
2067     list = *(int *)argv[0];
2068     rargv[0] = countbuf;
2069 ##  repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2070     sprintf(countbuf, "%d", ct);
2071     (*action)(1, rargv, actarg);
2072 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2073 ##      where tblstats.#table = "members"
2074     return(SMS_SUCCESS);
2075 ##}
2076
2077
2078 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2079  * the three flags associated with each service.  It will return the name of
2080  * each service that meets the quailifications.  It does this by building a
2081  * where clause based on the arguments, then doing a retrieve.
2082  */
2083
2084 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2085
2086 int qualified_get_server(q, argv, cl, action, actarg)
2087     struct query *q;
2088     char *argv[];
2089     client *cl;
2090     int (*action)();
2091     int actarg;
2092 {
2093     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2094                          "s", "name", sflags));
2095 }
2096
2097
2098 /* generic qualified get routine, used by qualified_get_lists,
2099  * qualified_get_server, and qualified_get_serverhost.
2100  *   Args:
2101  *      start - a simple where clause, must not be empty
2102  *      range - the name of the range variable
2103  *      field - the field to return
2104  *      flags - an array of strings, names of the flag variables
2105  */
2106
2107 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2108     struct query *q;
2109     char *argv[];
2110     int (*action)();
2111     int actarg;
2112     char *start;
2113     char *range;
2114     char *field;
2115     char *flags[];
2116 ##{
2117 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2118     char *rargv[1], buf[32];
2119 ##  int rowcount, i;
2120
2121     strcpy(qual, start);
2122     for (i = 0; i < q->argc; i++) {
2123         if (!strcmp(argv[i], "TRUE")) {
2124             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2125             (void) strcat(qual, buf);
2126         } else if (!strcmp(argv[i], "FALSE")) {
2127             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2128             (void) strcat(qual, buf);
2129         }
2130     }
2131       
2132     rargv[0] = name;
2133     rvar = range;
2134     rtbl = q->rtable;
2135     rfield = field;
2136 ##  range of rvar is rtbl
2137 ##  retrieve (name = rvar.rfield) where qual {
2138         (*action)(1, rargv, actarg);
2139 ##  }
2140 ##  inquire_equel(rowcount = "rowcount")
2141 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2142 ##      where tblstats.#table = @rtbl
2143     if (rowcount == 0)
2144       return(SMS_NO_MATCH);
2145     return(SMS_SUCCESS);
2146 ##}
2147
2148
2149 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2150  * the five flags associated with each serverhost.  It will return the name of
2151  * each service and host that meets the quailifications.  It does this by 
2152  * building a where clause based on the arguments, then doing a retrieve.
2153  */
2154
2155 static char *shflags[6] = { "service", "enable", "override", "success",
2156                             "inprogress", "hosterror" };
2157
2158 int qualified_get_serverhost(q, argv, cl, action, actarg)
2159     struct query *q;
2160     char *argv[];
2161     client *cl;
2162     int (*action)();
2163     int actarg;
2164 ##{
2165 ##  char sname[33], mname[33], qual[256];
2166     char *rargv[2], buf[32];
2167 ##  int rowcount, i;
2168
2169     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2170             argv[0]);
2171     for (i = 1; i < q->argc; i++) {
2172         if (!strcmp(argv[i], "TRUE")) {
2173             sprintf(buf, " and sh.%s != 0", shflags[i]);
2174             strcat(qual, buf);
2175         } else if (!strcmp(argv[i], "FALSE")) {
2176             sprintf(buf, " and sh.%s = 0", shflags[i]);
2177             strcat(qual, buf);
2178         }
2179     }
2180       
2181     rargv[0] = sname;
2182     rargv[1] = mname;
2183 ##  range of sh is serverhosts
2184 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2185         (*action)(2, rargv, actarg);
2186 ##  }
2187 ##  inquire_equel(rowcount = "rowcount")
2188 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2189 ##      where tblstats.#table = "serverhosts"
2190     if (rowcount == 0)
2191       return(SMS_NO_MATCH);
2192     return(SMS_SUCCESS);
2193 ##}
2194
2195
2196 /* register_user - change user's login name and allocate a pobox, group,
2197  * filesystem, and quota for them.  The user's status must start out as 0,
2198  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2199  * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY, 
2200  * SMS_FS_STAFF, SMS_FS_MISC).
2201  */
2202
2203 register_user(q, argv, cl)
2204     struct query *q;
2205     char **argv;
2206     client *cl;
2207 ##{
2208 ##  char *login, dir[65], *entity, *directory, machname[33];
2209 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2210 ##  int size, alloc, pid, m_id;
2211     int maxsize;
2212
2213     entity = cl->entity;
2214     who = cl->users_id;
2215
2216     uid = atoi(argv[0]);
2217     login = argv[1];
2218     utype = atoi(argv[2]);
2219
2220 ##  range of u is users
2221 ##  range of l is list
2222 ##  range of sh is serverhosts
2223 ##  range of n is nfsphys
2224 ##  range of m is machine
2225
2226     /* find user */
2227 ##  repeat retrieve (users_id = u.#users_id)
2228 ##      where u.#uid = @uid and u.status = 0
2229     if (ingres_errno != 0) return(ingres_errno);
2230 ##  inquire_equel(rowcount = "rowcount");
2231     if (rowcount == 0)
2232       return(SMS_NO_MATCH);
2233     if (rowcount > 1)
2234       return(SMS_NOT_UNIQUE);
2235
2236     /* check new login name */
2237 ##  repeat retrieve (flag = any(u.#login where u.#login = @login))
2238     if (flag)
2239       return(SMS_IN_USE);
2240 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2241     if (flag)
2242       return(SMS_IN_USE);
2243 ##  repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2244     if (flag)
2245       return(SMS_IN_USE);
2246     if (ingres_errno != 0) return(ingres_errno);
2247     com_err(whoami, 0, "new login name OK");
2248
2249     /* choose place for pobox, put in mid */
2250 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2251 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2252 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2253     if (ingres_errno != 0) return(ingres_errno);
2254 ##  inquire_equel(rowcount = "rowcount");
2255     if (rowcount == 0)
2256       return(SMS_NO_POBOX);
2257
2258     /* change login name, set pobox */
2259 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2260 ##                    modby = @who, modwith = @entity, potype="POP",
2261 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2262 ##                    pmodwith=@entity)
2263 ##      where u.#users_id = @users_id
2264     if (ingres_errno != 0) return(ingres_errno);
2265 ##  inquire_equel(rowcount = "rowcount");
2266     if (rowcount != 1)
2267       return(SMS_INTERNAL);
2268     set_pop_usage(mid, 1);
2269     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2270             trim(machname));
2271
2272     /* create group list */
2273     if (set_next_object_id("gid", "list"))
2274       return(SMS_NO_ID);
2275     if (set_next_object_id("list_id", "list"))
2276       return(SMS_NO_ID);
2277 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2278     if (ingres_errno != 0) return(ingres_errno);
2279 ##  inquire_equel(rowcount = "rowcount");
2280     if (rowcount != 1)
2281       return(SMS_INTERNAL);
2282 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2283 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2284 ##                      #gid = values.value, desc = "User Group",
2285 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2286 ##                      modby = @who, modwith = @entity)
2287 ##      where values.name = "gid"
2288     if (ingres_errno != 0) return(ingres_errno);
2289 ##  inquire_equel(rowcount = "rowcount");
2290     if (rowcount != 1)
2291       return(SMS_INTERNAL);
2292 ##  repeat append members (#list_id = @list_id, member_type = "USER",
2293 ##                         member_id = @users_id)
2294     if (ingres_errno != 0) return(ingres_errno);
2295 ##  inquire_equel(rowcount = "rowcount");
2296     if (rowcount != 1)
2297       return(SMS_INTERNAL);
2298     com_err(whoami, 0, "group list created");
2299
2300     /* decide where to put filesystem */
2301     maxsize = 0;
2302     directory = NULL;
2303 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2304 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2305         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2306             maxsize = size - alloc;
2307             if (directory)
2308               free(directory);
2309             directory = strsave(dir);
2310             pid = nid;
2311             m_id = mid;
2312         }
2313 ##  }
2314     if (ingres_errno != 0) return(ingres_errno);
2315     if (maxsize == 0)
2316       return(SMS_NO_FILESYS);
2317
2318     /* create filesystem */
2319     if (set_next_object_id("filsys_id", "filesys"))
2320       return(SMS_NO_ID);
2321 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2322 ##                         label = @login, type = "NFS", mach_id = @m_id,
2323 ##                         name = @directory + "/" + @login,
2324 ##                         mount = "/mit/" + @login,
2325 ##                         access = "w", comments = "User Locker",
2326 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2327 ##                         lockertype = "HOMEDIR", modtime = "now",
2328 ##                         modby = @who, modwith = @entity)
2329 ##      where values.name = "filsys_id"
2330     if (ingres_errno != 0) return(ingres_errno);
2331 ##  inquire_equel(rowcount = "rowcount");
2332     if (rowcount != 1)
2333       return(SMS_INTERNAL);
2334     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2335             directory, login);
2336
2337     /* set quota */
2338 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2339     if (ingres_errno != 0) return(ingres_errno);
2340 ##  inquire_equel(rowcount = "rowcount");
2341     if (rowcount != 1)
2342       return(SMS_NO_QUOTA);
2343 ##  repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2344 ##                          #quota = @quota, phys_id = @pid, modtime = "now",
2345 ##                          modby = @who, modwith = @entity)
2346 ##      where values.name = "filsys_id"
2347     if (ingres_errno != 0) return(ingres_errno);
2348 ##  inquire_equel(rowcount = "rowcount");
2349     if (rowcount != 1)
2350       return(SMS_INTERNAL);
2351 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2352 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2353 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2354     if (ingres_errno != 0) return(ingres_errno);
2355 ##  inquire_equel(rowcount = "rowcount");
2356     if (rowcount != 1)
2357       return(SMS_INTERNAL);
2358     com_err(whoami, 0, "quota of %d assigned", quota);
2359
2360 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2361 ##      where tblstats.table = "users"
2362     if (ingres_errno != 0) return(ingres_errno);
2363 ##  repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2364 ##      where tblstats.table = "list" or tblstats.table = "filesys" or
2365 ##            tblstats.table = "nfsquota"
2366     if (ingres_errno != 0) return(ingres_errno);
2367     return(SMS_SUCCESS);
2368 ##}
2369
2370
2371
2372 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2373  **
2374  ** Inputs:
2375  **   id of machine
2376  **   delta (will be +/- 1)
2377  **
2378  ** Description:
2379  **   - incr/decr value field in serverhosts table for pop/mach_id
2380  **
2381  **/
2382
2383 static int set_pop_usage(id, count)
2384 int id;
2385 int count;
2386 ##{
2387 ##  int mach_id = id;
2388 ##  int n = count;
2389
2390 ##  range of sh is serverhosts
2391 ##  repeat replace sh (value1 = sh.value1 + @n)
2392 ##         where sh.service = "POP" and sh.#mach_id = @mach_id
2393     if (ingres_errno != 0) return(ingres_errno);
2394
2395     return(SMS_SUCCESS);
2396 ##}
2397
2398
2399 \f
2400 /* Validation Routines */
2401
2402 validate_row(q, argv, v)
2403     register struct query *q;
2404     char *argv[];
2405     register struct validate *v;
2406 ##{
2407 ##  char *rvar;
2408 ##  char *table;
2409 ##  char *name;
2410 ##  char qual[128];
2411 ##  int rowcount;
2412
2413     /* build where clause */
2414     build_qual(v->qual, v->argc, argv, qual);
2415
2416     /* setup ingres variables */
2417     rvar = q->rvar;
2418     table = q->rtable;
2419     name = v->field;
2420
2421     if (log_flags & LOG_VALID)
2422         /* tell the logfile what we're doing */
2423         com_err(whoami, 0, "validating row: %s", qual);
2424     
2425     /* look for the record */
2426 ##  range of rvar is table
2427 ##  retrieve (rowcount = count(rvar.name where qual))
2428     if (rowcount == 0) return(SMS_NO_MATCH);
2429     if (rowcount > 1) return(SMS_NOT_UNIQUE);
2430     return(SMS_EXISTS);
2431 ##}
2432
2433 validate_fields(q, argv, vo, n)
2434     struct query *q;
2435     register char *argv[];
2436     register struct valobj *vo;
2437     register int n;
2438 {
2439     register int status;
2440
2441     while (--n >= 0) {
2442         switch (vo->type) {
2443         case V_NAME:
2444             if (log_flags & LOG_VALID)
2445                 com_err(whoami, 0, "validating %s in %s: %s", 
2446                     vo->namefield, vo->table, argv[vo->index]);
2447             status = validate_name(argv, vo);
2448             break;
2449
2450         case V_ID:
2451             if (log_flags & LOG_VALID)
2452                 com_err(whoami, 0, "validating %s in %s: %s", 
2453                     vo->idfield, vo->table, argv[vo->index]);
2454             status = validate_id(argv, vo);
2455             break;
2456
2457         case V_DATE:
2458             if (log_flags & LOG_VALID)
2459                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2460             status = validate_date(argv, vo);
2461             break;
2462
2463         case V_TYPE:
2464             if (log_flags & LOG_VALID)
2465                 com_err(whoami, 0, "validating %s type: %s",
2466                     vo->table, argv[vo->index]);
2467             status = validate_type(argv, vo);
2468             break;
2469
2470         case V_TYPEDATA:
2471             if (log_flags & LOG_VALID)
2472                 com_err(whoami, 0, "validating typed data (%s): %s",
2473                     argv[vo->index - 1], argv[vo->index]);
2474             status = validate_typedata(q, argv, vo);
2475             break;
2476
2477         case V_RENAME:
2478             if (log_flags & LOG_VALID)
2479                 com_err(whoami, 0, "validating rename %s in %s",
2480                         argv[vo->index], vo->table);
2481             status = validate_rename(argv, vo);
2482             break;
2483
2484         case V_CHAR:
2485             if (log_flags & LOG_VALID)
2486               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2487             status = validate_chars(argv[vo->index]);
2488             break;
2489
2490         case V_SORT:
2491             status = SMS_EXISTS;
2492             break;
2493
2494         }
2495
2496         if (status != SMS_EXISTS) return(status);
2497         vo++;
2498     }
2499
2500     return(SMS_SUCCESS);
2501 }
2502
2503
2504 /* validate_chars: verify that there are no illegal characters in
2505  * the string.  Legal characters are printing chars other than 
2506  * ", *, ?, \, [ and ].
2507  */
2508 static int illegalchars[] = {
2509     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2510     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2511     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2512     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2513     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2514     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2515     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2516     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2517     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2518     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2519     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2520     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2521     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2522     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2523     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2524     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2525 };
2526
2527 validate_chars(s)
2528 register char *s;
2529 {
2530     while (*s)
2531       if (illegalchars[*s++])
2532         return(SMS_BAD_CHAR);
2533     return(SMS_EXISTS);
2534 }
2535
2536
2537 validate_id(argv, vo)
2538     char *argv[];
2539     register struct valobj *vo;
2540 ##{
2541 ##  char *name;
2542 ##  char *table;
2543 ##  char *namefield;
2544 ##  char *idfield;
2545 ##  int id;
2546 ##  int rowcount;
2547     register char *c;
2548
2549     name = argv[vo->index];
2550     table = vo->table;
2551     /* minor kludge to upcasify machine names */
2552     if (!strcmp(table, "machine"))
2553         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2554     namefield = vo->namefield;
2555     idfield = vo->idfield;
2556     if (!strcmp(namefield, "uid")) {
2557 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2558 ##    inquire_equel (rowcount = "rowcount")
2559     } else {
2560 ##    retrieve (id = table.idfield) where table.namefield = name
2561 ##    inquire_equel (rowcount = "rowcount")
2562     }
2563     if (rowcount != 1) return(vo->error);
2564     *(int *)argv[vo->index] = id;
2565     return(SMS_EXISTS);
2566 ##}
2567
2568 validate_name(argv, vo)
2569     char *argv[];
2570     register struct valobj *vo;
2571 ##{
2572 ##  char *name;
2573 ##  char *table;
2574 ##  char *namefield;
2575 ##  int rowcount;
2576     register char *c;
2577
2578     name = argv[vo->index];
2579     table = vo->table;
2580     namefield = vo->namefield;
2581     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2582         for (c = name; *c; c++)
2583           if (islower(*c))
2584             *c = toupper(*c);
2585     }
2586 ##  retrieve (rowcount = countu(table.namefield 
2587 ##            where table.namefield = name))
2588     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2589 ##}
2590
2591 validate_date(argv, vo)
2592     char *argv[];
2593     struct valobj *vo;
2594 ##{
2595 ##  char *idate;
2596 ##  double dd;
2597 ##  int errorno;
2598
2599     idate = argv[vo->index];
2600
2601 ##  retrieve (dd = interval("years", date(idate) - date("today")))
2602 ##  inquire_equel (errorno = "errorno")
2603     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2604     return(SMS_EXISTS);
2605 ##}
2606
2607
2608 validate_rename(argv, vo)
2609 char *argv[];
2610 struct valobj *vo;
2611 ##{
2612 ##  char *name, *table, *namefield, *idfield;
2613 ##  int id;
2614     register char *c;
2615
2616     c = name = argv[vo->index];
2617     while (*c)
2618       if (illegalchars[*c++])
2619         return(SMS_BAD_CHAR);
2620     table = vo->table;
2621     /* minor kludge to upcasify machine names */
2622     if (!strcmp(table, "machine"))
2623         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2624     namefield = vo->namefield;
2625     idfield = vo->idfield;
2626     id = -1;
2627     if (idfield == 0) {
2628         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2629           return(SMS_EXISTS);
2630 ##      retrieve (id = any(table.namefield where table.namefield = name))
2631         if (id)
2632           return(vo->error);
2633         else
2634           return(SMS_EXISTS);
2635     }
2636 ##  retrieve (id = table.idfield) where table.namefield = name
2637     if (id == -1 || id == *(int *)argv[vo->index - 1])
2638       return(SMS_EXISTS);
2639     else
2640       return(vo->error);
2641 ##}
2642
2643
2644 validate_type(argv, vo)
2645     char *argv[];
2646     register struct valobj *vo;
2647 ##{
2648 ##  char *typename;
2649 ##  char *value;
2650 ##  int exists;
2651     register char *c;
2652
2653     typename = vo->table;
2654     c = value = argv[vo->index];
2655     while (*c)
2656       if (illegalchars[*c++])
2657         return(SMS_BAD_CHAR);
2658
2659     /* uppercase type fields */
2660     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2661
2662 ##  range of a is alias
2663 ##  repeat retrieve (exists = any(a.trans where a.name = @typename and
2664 ##                                    a.type = "TYPE" and
2665 ##                                    a.trans = @value))
2666     return (exists ? SMS_EXISTS : vo->error);
2667 ##}
2668
2669 /* validate member or type-specific data field */
2670
2671 validate_typedata(q, argv, vo)
2672     register struct query *q;
2673     register char *argv[];
2674     register struct valobj *vo;
2675 ##{
2676 ##  char *name;
2677 ##  char *field_type;
2678 ##  char data_type[129];
2679 ##  int id;
2680 ##  int rowcount;
2681     char *index();
2682     register char *c;
2683
2684     /* get named object */
2685     name = argv[vo->index];
2686
2687     /* get field type string (known to be at index-1) */
2688     field_type = argv[vo->index-1];
2689
2690     /* get corresponding data type associated with field type name */
2691 ##  repeat retrieve (data_type = alias.trans) 
2692 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
2693 ##  inquire_equel (rowcount = "rowcount")
2694     if (rowcount != 1) return(SMS_TYPE);
2695
2696     /* now retrieve the record id corresponding to the named object */
2697     if (index(data_type, ' '))
2698         *index(data_type, ' ') = 0;
2699     if (!strcmp(data_type, "user")) {
2700         /* USER */
2701 ##      repeat retrieve (id = users.users_id) where users.login = @name
2702 ##      inquire_equel (rowcount = "rowcount")
2703         if (rowcount != 1) return(SMS_USER);
2704
2705     } else if (!strcmp(data_type, "list")) {
2706         /* LIST */
2707 ##      repeat retrieve (id = list.list_id) where list.#name = @name
2708 ##      inquire_equel (rowcount = "rowcount")
2709         if (rowcount != 1) {
2710             /* if idfield is non-zero, then if argv[0] matches the string
2711              * that we're trying to resolve, we should get the value of
2712              * values.[idfield] for the id.
2713              */
2714             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2715                 set_next_object_id(q->validate->object_id, q->rtable);
2716                 name = vo->idfield;
2717 ##              repeat retrieve (id = values.value) where values.#name = @name
2718 ##              inquire_equel(rowcount = "rowcount")
2719                 if (rowcount != 1) return(SMS_LIST);
2720             } else
2721               return(SMS_LIST);
2722         }
2723     } else if (!strcmp(data_type, "machine")) {
2724         /* MACHINE */
2725         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2726 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
2727 ##      inquire_equel (rowcount = "rowcount")
2728         if (rowcount != 1) return(SMS_MACHINE);
2729
2730     } else if (!strcmp(data_type, "string")) {
2731         /* STRING */
2732 ##      range of s is strings
2733 ##      repeat retrieve (id = s.string_id) where s.string = @name
2734 ##      inquire_equel (rowcount = "rowcount")
2735         if (rowcount == 0) {
2736             if (q->type != APPEND) return(SMS_STRING);
2737 ##          range of v is values
2738 ##          retrieve (id = v.value) where v.#name = "strings_id"
2739             id++;
2740 ##          replace v (value = id) where v.#name = "strings_id"
2741 ##          append to strings (string_id = id, string = name)
2742         }
2743     } else if (!strcmp(data_type, "none")) {
2744         id = 0;
2745     } else {
2746         return(SMS_TYPE);
2747     }
2748
2749     /* now set value in argv */
2750     *(int *)argv[vo->index] = id;
2751     
2752     return (SMS_EXISTS);
2753 ##}
2754
2755
2756 /* This looks up a login name and returns the SMS internal ID.  It is used
2757  * by authenticate to put the users_id in the client structure.
2758  */
2759
2760 int get_users_id(name)
2761 char *name;
2762 ##{
2763 ##  int id, rowcount;
2764 ##  char *login;
2765
2766     login = name;
2767
2768 ##  range of u is users
2769 ##  repeat retrieve (id = u.#users_id) where u.#login = @login
2770 ##  inquire_equel (rowcount = "rowcount")
2771     
2772     if (rowcount == 1)
2773         return(id);
2774     else
2775         return(0);
2776 ##}
2777
2778
2779 /* Check the database at startup time.  For now this just resets the
2780  * inprogress flags that the DCM uses.
2781  */
2782
2783 sanity_check_database()
2784 ##{
2785 ##}
This page took 0.244147 seconds and 3 git commands to generate.