]> andersk Git - moira.git/blob - server/qsupport.dc
changed the use of vars which conflict with ingres and sql functions (i.e. values...
[moira.git] / server / qsupport.dc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "mr_server.h"
19 #include <ctype.h>
20 EXEC SQL INCLUDE sqlca;
21
22 extern char *whoami, *strsave();
23 extern int ingres_errno, mr_errcode;
24
25
26 /* Specialized Access Routines */
27
28 /* access_user - verify that client name equals specified login name
29  *
30  *  - since field validation routines are called first, a users_id is
31  *    now in argv[0] instead of the login name.
32  */
33
34 access_user(q, argv, cl)
35     struct query *q;
36     char *argv[];
37     client *cl;
38 {
39     if (cl->users_id != *(int *)argv[0])
40         return(MR_PERM);
41     else
42         return(MR_SUCCESS);
43 }
44
45     
46
47 /* access_login - verify that client name equals specified login name
48  *
49  *   argv[0...n] contain search info.  q->
50  */
51
52 access_login(q, argv, cl)
53     struct query *q;
54     char *argv[];
55     client *cl;
56
57 {
58     EXEC SQL BEGIN DECLARE SECTION;
59     int id;
60     char qual[256];
61     EXEC SQL END DECLARE SECTION;
62
63     build_qual(q->qual, q->argc, argv, qual);
64
65     EXEC SQL SELECT users_id INTO :id FROM users WHERE qual;
66
67     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1 || id != cl->users_id)
68         return(MR_PERM);
69     else
70         return(MR_SUCCESS);
71
72 }
73
74     
75
76 /* access_list - check access for most list operations
77  *
78  * Inputs: argv[0] - list_id
79  *          q - query name
80  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
81  *          argv[7] - group IID (only for query "ulis")
82  *          cl - client name
83  *
84  * - check that client is a member of the access control list
85  * - OR, if the query is add_member_to_list or delete_member_from_list
86  *      and the list is public, allow access if client = member
87  */ 
88
89 access_list(q, argv, cl)
90     struct query *q;
91     char *argv[];
92     client *cl;
93 {
94     EXEC SQL BEGIN DECLARE SECTION;
95     int list_id, acl_id, flags, rowcount, gid;
96     char acl_type[9];
97     EXEC SQL END DECLARE SECTION;
98     char *client_type;
99     int client_id, status;
100
101     list_id = *(int *)argv[0];
102     EXEC SQL SELECT acl_id, acl_type, gid, public
103              INTO :acl_id, :acl_type, :gid, :flags
104              FROM list
105              WHERE list_id = :list_id;
106     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
107       return(MR_INTERNAL);
108
109     /* parse client structure */
110     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
111         return(status);
112
113     /* if amtl or dmfl and list is public allow client to add or delete self */
114     if (((!strcmp("amtl", q->shortname) && flags) ||
115          (!strcmp("dmfl", q->shortname))) &&
116         (!strcmp("USER", argv[1]))) {
117         if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
118     /* if update_list, don't allow them to change the GID */
119     } else if (!strcmp("ulis", q->shortname)) {
120         if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
121             (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
122           return(MR_PERM);
123     }
124
125     /* check for client in access control list */
126     status = find_member(acl_type, acl_id, client_type, client_id, 0);
127     if (!status) return(MR_PERM);
128
129     return(MR_SUCCESS);
130 }
131
132
133 /* access_visible_list - allow access to list only if it is not hidden,
134  *      or if the client is on the ACL
135  *
136  * Inputs: argv[0] - list_id
137  *         cl - client identifier
138  */ 
139
140 access_visible_list(q, argv, cl)
141     struct query *q;
142     char *argv[];
143     client *cl;
144 {
145     EXEC SQL BEGIN DECLARE SECTION;
146     int list_id, acl_id, flags, rowcount;
147     char acl_type[9];
148     EXEC SQL END DECLARE SECTION;
149     char *client_type;
150     int client_id, status;
151
152     list_id = *(int *)argv[0];
153     EXEC SQL SELECT hidden, acl_id, acl_type
154              INTO :flags, :acl_id, :acl_type
155              FROM list
156              WHERE list_id = :list_id;
157     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
158       return(MR_INTERNAL);
159     if (!flags)
160         return(MR_SUCCESS);
161
162
163     /* parse client structure */
164     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
165         return(status);
166
167     /* check for client in access control list */
168     status = find_member(acl_type, acl_id, client_type, client_id, 0);
169     if (!status)
170         return(MR_PERM);
171
172     return(MR_SUCCESS);
173 }
174
175
176 /* access_vis_list_by_name - allow access to list only if it is not hidden,
177  *      or if the client is on the ACL
178  *
179  * Inputs: argv[0] - list name
180  *         cl - client identifier
181  */ 
182
183 access_vis_list_by_name(q, argv, cl)
184     struct query *q;
185     char *argv[];
186     client *cl;
187 {
188     EXEC SQL BEGIN DECLARE SECTION;
189     int acl_id, flags, rowcount;
190     char acl_type[9], *listname;
191     EXEC SQL END DECLARE SECTION;
192     char *client_type;
193     int client_id, status;
194
195     listname = argv[0];
196     EXEC SQL SELECT hidden, acl_id, acl_type
197              INTO :flags, :acl_id, :acl_type
198              FROM list
199              WHERE name = :listname;
200     if (sqlca.sqlerrd[2] > 1)  return(MR_WILDCARD);
201     if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
202     if (!flags)
203         return(MR_SUCCESS);
204
205     /* parse client structure */
206     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
207         return(status);
208
209     /* check for client in access control list */
210     status = find_member(acl_type, acl_id, client_type, client_id, 0);
211     if (!status)
212         return(MR_PERM);
213
214     return(MR_SUCCESS);
215 }
216
217
218 /* access_member - allow user to access member of type "USER" and name matches
219  * username, or to access member of type "LIST" and list is one that user is
220  * on the acl of, or the list is visible.
221  */
222
223 access_member(q, argv, cl)
224     struct query *q;
225     char *argv[];
226     client *cl;
227 {
228     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
229       return(access_visible_list(q, &argv[1], cl));
230
231     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
232         if (cl->users_id == *(int *)argv[1])
233           return(MR_SUCCESS);
234     }
235
236     return(MR_PERM);
237 }
238
239
240 /* access_qgli - special access routine for Qualified_get_lists.  Allows
241  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
242  */
243
244 access_qgli(q, argv, cl)
245     struct query *q;
246     char *argv[];
247     client *cl;
248 {
249     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
250       return(MR_SUCCESS);
251     return(MR_PERM);
252 }
253
254
255 /* access_service - allow access if user is on ACL of service.  Don't
256  * allow access if a wildcard is used.
257  */
258
259 access_service(q, argv, cl)
260     struct query *q;
261     char *argv[];
262     client *cl;
263 {
264     EXEC SQL BEGIN DECLARE SECTION;
265     int acl_id, rowcount;
266     char *name, acl_type[9];
267     EXEC SQL END DECLARE SECTION;
268     int client_id, status;
269     char *client_type;
270
271     name = argv[0];
272     uppercase(name);
273     EXEC SQL SELECT acl_id, acl_type
274              INTO :acl_id, :acl_type
275              FROM servers
276              WHERE name = :name;
277     if (sqlca.sqlerrd[2] > 1) return(MR_PERM);
278     /* parse client structure */
279     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
280         return(status);
281
282     /* check for client in access control list */
283     status = find_member(acl_type, acl_id, client_type, client_id, 0);
284     if (!status) return(MR_PERM);
285
286     return(MR_SUCCESS);
287 }
288
289
290
291 /* access_filesys - verify that client is owner or on owners list of filesystem
292  *      named by argv[0]
293  */
294
295 access_filesys(q, argv, cl)
296     struct query *q;
297     char *argv[];
298     client *cl;
299 {
300     EXEC SQL BEGIN DECLARE SECTION;
301     int users_id, list_id;
302     char *name;
303     EXEC SQL END DECLARE SECTION;
304     int status, client_id;
305     char *client_type;
306
307     name = argv[0];
308     EXEC SQL SELECT owner, owners 
309              INTO :users_id, :list_id
310              FROM filesys
311              WHERE label = :name;
312     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
313       return(MR_PERM);
314
315     if (users_id == cl->users_id)
316       return(MR_SUCCESS);
317     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
318       return(status);
319     status = find_member("LIST", list_id, client_type, client_id, 0);
320     if (status)
321       return(MR_SUCCESS);
322     else
323       return(MR_PERM);
324 }
325
326     
327 \f
328 /* Setup Routines */
329
330 /* Setup routine for add_user
331  *
332  * Inputs: argv[0] - login
333  *         argv[1] - uid
334  *
335  * Description:
336  *
337  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
338  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
339  */
340
341 setup_ausr(q, argv, cl)
342     struct query *q;
343     register char *argv[];
344     client *cl;
345 {
346     EXEC SQL BEGIN DECLARE SECTION;
347     int nuid;
348     char *mit_id;
349     EXEC SQL END DECLARE SECTION;
350
351 #ifdef notdef
352     /* this is currently disabled because we need an index on ID's
353      * before it can run in finite time.
354      */
355     mit_id = argv[U_MITID];
356 ##  retrieve (rowcount = any(u.#mit_id where u.#mit_id = mit_id))
357     if (ingres_errno) return(mr_errcode);
358     if (rowcount) return(MR_EXISTS);
359 #endif notdef
360
361     if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
362         if (set_next_object_id("uid", "users"))
363           return(MR_INGRES_ERR);
364         EXEC SQL SELECT value  
365              INTO :nuid
366              FROM values_tbl
367              WHERE name = "uid";
368         if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
369           return(MR_INTERNAL);
370         sprintf(argv[1], "%d", nuid);
371     }
372
373     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
374         sprintf(argv[0], "#%s", argv[1]);
375     }
376
377     return(MR_SUCCESS);
378 d#}
379
380
381 /* setup_dusr - verify that the user is no longer being referenced 
382  * and may safely be deleted.
383  */
384
385 int setup_dusr(q, argv)
386     struct query *q;
387     char **argv;
388 {
389     EXEC SQL BEGIN DECLARE SECTION;
390     int flag, id;
391     EXEC SQL END DECLARE SECTION;
392
393     id = *(int *)argv[0];
394
395     /* For now, only allow users to be deleted if their status is 0 */
396 ##  repeat retrieve (flag = u.status) where u.users_id = @id
397     if (flag != 0 && flag != 4)
398       return(MR_IN_USE);
399
400 ##  repeat delete quota where quota.entity_id = @id and quota.type = "USER"
401 ##  repeat delete krbmap where krbmap.users_id = @id
402 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
403 ##                       and imembers.member_type = "USER"))
404     if (flag)
405         return(MR_IN_USE);
406 ##  repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
407     if (flag)
408         return(MR_IN_USE);
409 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
410 ##                      list.acl_type = "USER"))
411     if (flag)
412         return(MR_IN_USE);
413 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
414 ##                      servers.acl_type = "USER"))
415     if (flag)
416         return(MR_IN_USE);
417 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
418 ##                      hostaccess.acl_type = "USER"))
419     if (flag)
420         return(MR_IN_USE);
421     if (ingres_errno)
422         return(mr_errcode);
423     return(MR_SUCCESS);
424 }
425
426
427 /* setup_spop: verify that there is already a valid POP machine_id in the
428  * pop_id field.  Also take care of keeping track of the post office usage.
429  */
430 int setup_spop(q, argv)
431 struct query *q;
432 char **argv;
433 {
434     EXEC SQL BEGIN DECLARE SECTION;
435     int id, mid, flag;
436     char type[9];
437     EXEC SQL END DECLARE SECTION;
438
439     id = *(int *)argv[0];
440 ##  repeat retrieve (type = u.potype, mid = u.pop_id,
441 ##                   flag = any(machine.name where machine.mach_id = u.pop_id 
442 ##                                   and u.pop_id != 0 and u.users_id = @id))
443 ##      where u.users_id = @id
444     if (!flag)
445       return(MR_MACHINE);
446     if (strcmp(strtrim(type), "POP"))
447       set_pop_usage(mid, 1);
448     return(MR_SUCCESS);
449 }
450
451
452 /* setup_dpob:  Take care of keeping track of the post office usage.
453  */
454 int setup_dpob(q, argv)
455 struct query *q;
456 char **argv;
457 {
458     EXEC SQL BEGIN DECLARE SECTION;
459     int id, user;
460     char type[9];
461     EXEC SQL END DECLARE SECTION;
462
463     user = *(int *)argv[0];
464     EXEC SQL SELECT potype, pop_id
465              INTO :type, :id
466              FROM users
467              WHERE users_id = :user;
468     if (ingres_errno) return(mr_errcode);
469
470     if (!strcmp(strtrim(type), "POP"))
471       set_pop_usage(id, -1);
472     return(MR_SUCCESS);
473 }
474
475
476 /* setup_dmac - verify that the machine is no longer being referenced 
477  * and may safely be deleted.
478  */
479
480 int setup_dmac(q, argv)
481     struct query *q;
482     char **argv;
483 {
484     EXEC SQL BEGIN DECLARE SECTION;
485     int flag, id;
486     EXEC SQL END DECLARE SECTION;
487
488     id = *(int *)argv[0];
489 ##  repeat retrieve (flag = any(users.login where users.potype = "POP" 
490 ##                                                and users.pop_id=@id))
491     if (flag)
492         return(MR_IN_USE);
493 ##  repeat retrieve (flag = any(serverhosts.mach_id
494 ##                               where serverhosts.mach_id=@id))
495     if (flag)
496         return(MR_IN_USE);
497 ##  repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
498     if (flag)
499         return(MR_IN_USE);
500 ##  repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
501     if (flag)
502         return(MR_IN_USE);
503 ##  repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
504     if (flag)
505         return(MR_IN_USE);
506 ##  repeat retrieve (flag = any(printcap.quotaserver where printcap.quotaserver=@id))
507     if (flag)
508         return(MR_IN_USE);
509 ##  repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
510     if (flag)
511         return(MR_IN_USE);
512
513 ##  repeat delete mcmap where mcmap.mach_id = @id
514     if (ingres_errno) return(mr_errcode);
515     return(MR_SUCCESS);
516 }
517
518
519 /* setup_dclu - verify that the cluster is no longer being referenced 
520  * and may safely be deleted.
521  */
522
523 int setup_dclu(q, argv)
524     struct query *q;
525     char **argv;
526 {
527     EXEC SQL BEGIN DECLARE SECTION;
528     int flag, id;
529     EXEC SQL END DECLARE SECTION;
530
531     id = *(int *)argv[0];
532 ##  repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
533     if (flag)
534         return(MR_IN_USE);
535 ##  repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
536     if (flag)
537         return(MR_IN_USE);
538     if (ingres_errno)
539         return(mr_errcode);
540     return(MR_SUCCESS);
541 }
542
543
544 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
545  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
546  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
547  * a -1 there.  Remember that this is also used for ulis, with the indexes
548  * at 6 & 7.
549  */
550
551 int setup_alis(q, argv)
552 struct query *q;
553 char **argv;
554 {
555     EXEC SQL BEGIN DECLARE SECTION;
556     int ngid;
557     EXEC SQL END DECLARE SECTION;
558     char *malloc();
559     int idx;
560
561     if (!strcmp(q->shortname, "alis"))
562       idx = 6;
563     else if (!strcmp(q->shortname, "ulis"))
564       idx = 7;
565
566     if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
567         if (atoi(argv[idx - 1])) {
568             if (set_next_object_id("gid", "list"))
569               return(MR_INGRES_ERR);
570             EXEC SQL SELECT value 
571                      INTO :ngid
572                      FROM values_tbl
573                      WHERE name = "gid";
574             if (ingres_errno) return(mr_errcode);
575             sprintf(argv[idx], "%d", ngid);
576         } else {
577             strcpy(argv[idx], "-1");
578         }
579     }
580
581     return(MR_SUCCESS);
582 }
583
584
585 /* setup_dlist - verify that the list is no longer being referenced 
586  * and may safely be deleted.
587  */
588
589 int setup_dlis(q, argv)
590     struct query *q;
591     char **argv;
592 {
593     EXEC SQL BEGIN DECLARE SECTION;
594     int flag, id;
595     EXEC SQL END DECLARE SECTION;
596
597     id = *(int *)argv[0];
598 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
599 ##                       and imembers.member_type = "LIST"))
600     if (flag)
601         return(MR_IN_USE);
602 ##  repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
603     if (flag)
604         return(MR_IN_USE);
605 ##  repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
606     if (flag)
607         return(MR_IN_USE);
608 ##  repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
609     if (flag)
610         return(MR_IN_USE);
611 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
612 ##                      list.acl_type = "LIST" and list.list_id != @id))
613     if (flag)
614         return(MR_IN_USE);
615 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
616 ##                      servers.acl_type = "LIST"))
617     if (flag)
618         return(MR_IN_USE);
619 ##  repeat retrieve (flag = any(quota.entity_id where quota.entity_id=@id and
620 ##                      quota.type = "GROUP"))
621     if (flag)
622         return(MR_IN_USE);
623 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
624 ##                      hostaccess.acl_type = "LIST"))
625     if (flag)
626         return(MR_IN_USE);
627 ##  repeat retrieve (flag = any(zephyr.class
628 ##              where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
629 ##                    zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
630 ##                    zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
631 ##                    zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
632     if (flag)
633         return(MR_IN_USE);
634     if (ingres_errno)
635         return(mr_errcode);
636     return(MR_SUCCESS);
637 }
638
639
640 /* setup_dsin - verify that the service is no longer being referenced 
641  * and may safely be deleted.
642  */
643
644 int setup_dsin(q, argv)
645     struct query *q;
646     char **argv;
647 {
648     EXEC SQL BEGIN DECLARE SECTION;
649     int flag;
650     char *name;
651     EXEC SQL END DECLARE SECTION;
652
653     name = argv[0];
654 ##  repeat retrieve (flag = any(serverhosts.service 
655 ##                              where serverhosts.service=uppercase(@name)))
656     if (flag)
657         return(MR_IN_USE);
658     EXEC SQL SELECT inprogress  
659              INTO :flag
660              FROM servers
661              WHERE name = :name;
662     if (flag)
663         return(MR_IN_USE);
664     if (ingres_errno)
665         return(mr_errcode);
666     return(MR_SUCCESS);
667 }
668
669
670 /* setup_dshi - verify that the service-host is no longer being referenced 
671  * and may safely be deleted.
672  */
673
674 int setup_dshi(q, argv)
675     struct query *q;
676     char **argv;
677 {
678     EXEC SQL BEGIN DECLARE SECTION;
679     int flag, id;
680     char *name;
681     EXEC SQL END DECLARE SECTION;
682
683     name = argv[0];
684     id = *(int *)argv[1];
685     uppercase(name);
686     EXEC SQL SELECT inprogress  
687              INTO :flag
688              FROM serverhosts
689              WHERE service = :name AND mach_id = :id;
690     if (flag)
691         return(MR_IN_USE);
692     if (ingres_errno)
693         return(mr_errcode);
694     return(MR_SUCCESS);
695 }
696
697
698 /**
699  ** setup_add_filesys - verify existance of referenced file systems
700  **
701  ** Inputs:     Add
702  **   argv[1] - type
703  **   argv[2] - mach_id
704  **   argv[3] - name
705  **   argv[5] - access
706  **
707  ** Description:
708  **   - for type = RVD:
709  **        * allow anything
710  **   - for type = NFS:
711  **        * extract directory prefix from name
712  **        * verify mach_id/dir in nfsphys
713  **        * verify access in {r, w, R, W}
714  **
715  **  Side effect: sets variable var_phys_id to the ID of the physical
716  **     filesystem (nfsphys_id for NFS, 0 for RVD)
717  **
718  ** Errors:
719  **   MR_NFS - specified directory not exported
720  **   MR_FILESYS_ACCESS - invalid filesys access
721  **
722  **/
723
724 ##static int var_phys_id;
725
726 setup_afil(q, argv)
727     struct query *q;
728     char *argv[];
729 {
730     char *type, *name;
731     int mach_id;
732     EXEC SQL BEGIN DECLARE SECTION;
733     int ok;
734     char ftype[32], *access;
735     EXEC SQL END DECLARE SECTION;
736
737     type = argv[1];
738     mach_id = *(int *)argv[2];
739     name = argv[3];
740     access = argv[5];
741     var_phys_id = 0;
742
743     sprintf(ftype, "fs_access_%s", type);
744 ##  retrieve (ok = any(alias.trans where alias.name = ftype and
745 ##                           alias.type = "TYPE" and alias.trans = access))
746     if (ingres_errno) return(mr_errcode);
747     if (ok == 0) return(MR_FILESYS_ACCESS);
748
749     if (!strcmp(type, "NFS"))
750         return (check_nfs(mach_id, name, access));
751     else
752         return(MR_SUCCESS);
753 }
754
755
756 /* Verify the arguments, depending on the FStype.  Also, if this is an
757  * NFS filesystem, then update any quotas for that filesystem to reflect
758  * the new phys_id.
759  */
760
761 setup_ufil(q, argv, cl)
762     struct query *q;
763     char *argv[];
764     client *cl;
765 {
766     int mach_id, status;
767     char *type, *name;  
768     EXEC SQL BEGIN DECLARE SECTION;
769     int fid, total, who;
770     char *entity, ftype[32], *access;
771     EXEC SQL END DECLARE SECTION;
772
773     type = argv[2];
774     mach_id = *(int *)argv[3];
775     name = argv[4];
776     access = argv[6];
777     var_phys_id = 0;
778     fid = *(int *)argv[0];
779     who = cl->client_id;
780     entity = cl->entity;
781
782     sprintf(ftype, "fs_access_%s", type);
783 ##  retrieve (total = any(alias.trans where alias.name = ftype and
784 ##                           alias.type = "TYPE" and alias.trans = access))
785     if (ingres_errno) return(mr_errcode);
786     if (total == 0) return(MR_FILESYS_ACCESS);
787
788     if (!strcmp(type, "NFS")) {
789         status = check_nfs(mach_id, name, access);
790 ##      replace quota (phys_id = var_phys_id) where quota.filsys_id = fid
791         if (ingres_errno) return(mr_errcode);
792         return(status);
793     } else if (!strcmp(type, "AFS")) {
794         total = 0;
795 ##      retrieve (total = sum(quota.quota where quota.filsys_id = fid
796 ##                            and quota.phys_id != 0))
797         if (ingres_errno) return(mr_errcode);
798         if (total != 0) {
799 ##          append quota (quota = total, filsys_id = fid,
800 ##                           phys_id = 0, entity_id = 0, type = "ANY",
801 ##                           modtime = "now", modby = who, modwith = entity)
802             if (ingres_errno) return(mr_errcode);
803         }
804     } else {
805 ##      replace quota (phys_id = 0) where quota.filsys_id = fid
806         if (ingres_errno) return(mr_errcode);
807     }
808     return(MR_SUCCESS);
809 }
810
811
812 /* Find the NFS physical partition that the named directory is on.
813  * This is done by comparing the dir against the mount point of the
814  * partition.  To make sure we get the correct match when there is 
815  * more than one, we sort the query in reverse order by dir name.
816  */
817
818 ##check_nfs(mach_id, name, access)
819     EXEC SQL BEGIN DECLARE SECTION;
820     int mach_id;
821     EXEC SQL END DECLARE SECTION;
822     char *name;
823     char *access;
824 {
825     EXEC SQL BEGIN DECLARE SECTION;
826     char dir[81];
827     EXEC SQL END DECLARE SECTION;
828     char caccess;
829     register int status;
830     register char *cp1;
831     register char *cp2;
832
833     status = MR_NFS;
834 ##  range of np is nfsphys
835 ##  repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
836 ##      where np.#mach_id = @mach_id sort by #dir:d {
837          cp1 = name;
838          cp2 = dir;
839          while (*cp2) {
840              if (*cp1++ != *cp2) break;
841              cp2++;
842          }
843          if (*cp2 == 0) {
844              status = MR_SUCCESS;
845 ##           endretrieve
846          }
847 ##  }
848     if (ingres_errno)
849         return(mr_errcode);
850     return(status);
851 }
852
853
854 /* setup_dfil: free any quota records and fsgroup info associated with
855  * a filesystem when it is deleted.  Also adjust the allocation numbers.
856  */
857
858 setup_dfil(q, argv, cl)
859     struct query  *q;
860     char **argv;
861     client *cl;
862 {
863     EXEC SQL BEGIN DECLARE SECTION;
864     int id;
865     EXEC SQL END DECLARE SECTION;
866
867     id = *(int *)argv[0];
868 ##  range of q is quota
869 ##  range of n is nfsphys
870 ##  repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
871 ##      where n.nfsphys_id = filesys.phys_id and filesys.filsys_id = @id
872
873 ##  repeat delete q where q.filsys_id = @id
874 ##  repeat delete fsgroup where fsgroup.filsys_id = @id
875 ##  repeat delete fsgroup where fsgroup.group_id = @id
876     if (ingres_errno) return(mr_errcode);
877     return(MR_SUCCESS);
878 }
879
880
881 /* setup_dnfp: check to see that the nfs physical partition does not have
882  * any filesystems assigned to it before allowing it to be deleted.
883  */
884
885 setup_dnfp(q, argv, cl)
886     struct query  *q;
887     char **argv;
888     client *cl;
889 {
890     EXEC SQL BEGIN DECLARE SECTION;
891     int id, exist;
892     char *dir;
893     EXEC SQL END DECLARE SECTION;
894
895     id = *(int *)argv[0];
896     dir = argv[1];
897 ##  repeat retrieve (exist = any(filesys.label where filesys.mach_id = @id
898 ##                                and filesys.phys_id = nfsphys.nfsphys_id and
899 ##                                nfsphys.mach_id = @id and nfsphys.#dir = @dir))
900     if (exists)
901       return(MR_IN_USE);
902     if (ingres_errno)
903       return(mr_errcode);
904     return(MR_SUCCESS);
905 }
906
907
908 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
909  *   argv[0] = filsys_id
910  *   argv[1] = type if "update_quota" or "delete_quota"
911  *   argv[2 or 1] = users_id or list_id
912  */
913
914 setup_dqot(q, argv, cl)
915     struct query  *q;
916     char **argv;
917     client *cl;
918 {
919     EXEC SQL BEGIN DECLARE SECTION;
920     int quota, fs, id;
921     char *qtype;
922     EXEC SQL END DECLARE SECTION;
923
924     fs = *(int *)argv[0];
925     if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
926         qtype = argv[1];
927         id = *(int *)argv[2];
928     } else {
929         qtype = "USER";
930         id = *(int *)argv[1];
931     }
932     EXEC SQL SELECT quota_value
933              INTO :quota
934              FROM quota
935              WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
936 ##  repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
937 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
938     if (ingres_errno) return(mr_errcode);
939     return(MR_SUCCESS);
940 }
941
942
943 /* setup_sshi: don't exclusive lock the machine table during
944  * set_server_host_internal.
945  */
946
947 setup_sshi(q, argv, cl)
948     struct query  *q;
949     char **argv;
950     client *cl;
951 ##{
952 ##  set lockmode session where readlock = system
953 ##}
954
955
956 /* setup add_kerberos_user_mapping: add the string to the string 
957  * table if necessary.
958  */
959
960 setup_akum(q, argv, cl)
961 struct query *q;
962 char **argv;
963 client *cl;
964 {
965     EXEC SQL BEGIN DECLARE SECTION;
966     int id, rowcount;
967     char *name;
968     EXEC SQL END DECLARE SECTION;
969
970     name = argv[1];
971     if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
972         if (q->type != APPEND) return(MR_STRING);
973     EXEC SQL SELECT value
974              INTO :id
975              FROM values_tbl
976              WHERE name = "strings_id";
977         id++;
978 ##      replace v (value = id) where v.#name = "strings_id"
979 ##      append to strings (string_id = id, string = name)
980         cache_entry(name, "STRING", id);
981     }
982     if (ingres_errno) return(mr_errcode);
983     *(int *)argv[1] = id;
984     return(MR_SUCCESS);
985 }
986
987
988 \f
989 /* FOLLOWUP ROUTINES */
990
991 /* generic set_modtime routine.  This takes the table name from the query,
992  * and will update the modtime, modby, and modwho fields in the entry in
993  * the table whose name field matches argv[0].
994  */
995
996 set_modtime(q, argv, cl)
997     struct query *q;
998     char *argv[];
999     client *cl;
1000 {
1001     EXEC SQL BEGIN DECLARE SECTION;
1002     char *name, *entity, *tbl;
1003     int who;
1004     EXEC SQL END DECLARE SECTION;
1005
1006     entity = cl->entity;
1007     who = cl->client_id;
1008     tbl = q->rtable;
1009     name = argv[0];
1010
1011 ##  replace tbl (modtime = "now", modby = who, modwith = entity)
1012 ##       where tbl.#name = name
1013     return(MR_SUCCESS);
1014 }
1015
1016 /* generic set_modtime_by_id routine.  This takes the table name from
1017  * the query, and the id name from the validate record,
1018  * and will update the modtime, modby, and modwho fields in the entry in
1019  * the table whose id matches argv[0].
1020  */
1021
1022 set_modtime_by_id(q, argv, cl)
1023     struct query *q;
1024     char **argv;
1025     client *cl;
1026 {
1027     EXEC SQL BEGIN DECLARE SECTION;
1028     char *entity, *tbl, *id_name;
1029     int who, id;
1030     EXEC SQL END DECLARE SECTION;
1031
1032     entity = cl->entity;
1033     who = cl->client_id;
1034     tbl = q->rtable;
1035     id_name = q->validate->object_id;
1036
1037     id = *(int *)argv[0];
1038 ##  replace tbl (modtime = "now", modby = who, modwith = entity)
1039 ##       where tbl.id_name = id
1040     return(MR_SUCCESS);
1041 }
1042
1043
1044 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
1045  */
1046
1047 set_finger_modtime(q, argv, cl)
1048     struct query *q;
1049     char *argv[];
1050     client *cl;
1051 {
1052     EXEC SQL BEGIN DECLARE SECTION;
1053     int users_id, who;
1054     char *entity;
1055     EXEC SQL END DECLARE SECTION;
1056
1057     entity = cl->entity;
1058     who = cl->client_id;
1059     users_id = *(int *)argv[0];
1060
1061 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
1062 ##       where u.#users_id = @users_id
1063     return(MR_SUCCESS);
1064 }
1065
1066
1067 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
1068  */
1069
1070 set_pobox_modtime(q, argv, cl)
1071     struct query *q;
1072     char **argv;
1073     client *cl;
1074 {
1075     EXEC SQL BEGIN DECLARE SECTION;
1076     int users_id, who;
1077     char *entity;
1078     EXEC SQL END DECLARE SECTION;
1079
1080     entity = cl->entity;
1081     who = cl->client_id;
1082     users_id = *(int *)argv[0];
1083
1084 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
1085 ##       where users.#users_id = @users_id
1086     return(MR_SUCCESS);
1087 }
1088
1089
1090 /* Like set_modtime, but uppercases the name first.
1091  */
1092
1093 set_uppercase_modtime(q, argv, cl)
1094     struct query *q;
1095     char **argv;
1096     client *cl;
1097 {
1098     EXEC SQL BEGIN DECLARE SECTION;
1099     char *name, *entity, *tbl;
1100     int who;
1101     EXEC SQL END DECLARE SECTION;
1102
1103     entity = cl->entity;
1104     who = cl->client_id;
1105     tbl = q->rtable;
1106     name = argv[0];
1107
1108 ##  replace tbl (modtime = "now", modby = who, modwith = entity)
1109 ##       where tbl.#name = uppercase(name)
1110     return(MR_SUCCESS);
1111 }
1112
1113
1114 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
1115  * is necessary for add_machine_to_cluster becuase the table that query
1116  * operates on is "mcm", not "machine".
1117  */
1118
1119 set_mach_modtime_by_id(q, argv, cl)
1120     struct query *q;
1121     char **argv;
1122     client *cl;
1123 {
1124     EXEC SQL BEGIN DECLARE SECTION;
1125     char *entity;
1126     int who, id;
1127     EXEC SQL END DECLARE SECTION;
1128
1129     entity = cl->entity;
1130     who = cl->client_id;
1131
1132     id = *(int *)argv[0];
1133 ##  repeat replace machine (modtime = "now", modby = @who, modwith = @entity)
1134 ##       where machine.mach_id = @id
1135     return(MR_SUCCESS);
1136 }
1137
1138
1139 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
1140  * is necessary for add_cluster_data and delete_cluster_data becuase the
1141  * table that query operates on is "svc", not "cluster".
1142  */
1143
1144 set_cluster_modtime_by_id(q, argv, cl)
1145     struct query *q;
1146     char **argv;
1147     client *cl;
1148 {
1149     EXEC SQL BEGIN DECLARE SECTION;
1150     char *entity;
1151     int who, id;
1152     EXEC SQL END DECLARE SECTION;
1153
1154     entity = cl->entity;
1155     who = cl->client_id;
1156
1157     id = *(int *)argv[0];
1158 ##  repeat replace cluster (modtime = "now", modby = @who, modwith = @entity)
1159 ##       where cluster.clu_id = @id
1160     return(MR_SUCCESS);
1161 }
1162
1163
1164 /* sets the modtime on the serverhost where the service name is in argv[0]
1165  * and the mach_id is in argv[1].
1166  */
1167
1168 set_serverhost_modtime(q, argv, cl)
1169     struct query *q;
1170     char **argv;
1171     client *cl;
1172 {
1173     EXEC SQL BEGIN DECLARE SECTION;
1174     char *entity, *serv;
1175     int who, id;
1176     EXEC SQL END DECLARE SECTION;
1177
1178     entity = cl->entity;
1179     who = cl->client_id;
1180
1181     serv = argv[0];
1182     id = *(int *)argv[1];
1183 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1184 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
1185     return(MR_SUCCESS);
1186 }
1187
1188
1189 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1190  * directory name is in argv[1].
1191  */
1192
1193 set_nfsphys_modtime(q, argv, cl)
1194     struct query *q;
1195     char **argv;
1196     client *cl;
1197 {
1198     EXEC SQL BEGIN DECLARE SECTION;
1199     char *entity, *dir;
1200     int who, id;
1201     EXEC SQL END DECLARE SECTION;
1202
1203     entity = cl->entity;
1204     who = cl->client_id;
1205
1206     id = *(int *)argv[0];
1207     dir = argv[1];
1208 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1209 ##       where np.#dir = @dir and np.mach_id = @id
1210     return(MR_SUCCESS);
1211 }
1212
1213
1214 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1215  * label.
1216  */
1217
1218 set_filesys_modtime(q, argv, cl)
1219     struct query *q;
1220     char *argv[];
1221     client *cl;
1222 {
1223     EXEC SQL BEGIN DECLARE SECTION;
1224     char *label, *entity;
1225     int who;
1226     EXEC SQL END DECLARE SECTION;
1227
1228     entity = cl->entity;
1229     who = cl->client_id;
1230
1231     label = argv[0];
1232     if (!strcmp(q->shortname, "ufil"))
1233       label = argv[1];
1234
1235 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1236 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1237     return(MR_SUCCESS);
1238 }
1239
1240
1241 /* sets the modtime on a zephyr class, where argv[0] contains the class
1242  * name.
1243  */
1244
1245 set_zephyr_modtime(q, argv, cl)
1246     struct query *q;
1247     char *argv[];
1248     client *cl;
1249 {
1250     EXEC SQL BEGIN DECLARE SECTION;
1251     char *class, *entity;
1252     int who;
1253     EXEC SQL END DECLARE SECTION;
1254
1255     entity = cl->entity;
1256     who = cl->client_id;
1257
1258     class = argv[0];
1259
1260 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1261 ##                     where z.#class = @class
1262     return(MR_SUCCESS);
1263 }
1264
1265
1266 /* fixes the modby field.  This will be the second to last thing in the
1267  * argv, the argv length is determined from the query structure.  It is
1268  * passed as a pointer to an integer.  This will either turn it into a
1269  * username, or # + the users_id.
1270  */
1271 followup_fix_modby(q, sq, v, action, actarg, cl)
1272     struct query *q;
1273     register struct save_queue *sq;
1274     struct validate *v;
1275     register int (*action)();
1276     register int actarg;
1277     client *cl;
1278 {
1279     register int i, j;
1280     char **argv, *malloc();
1281     int id, status;
1282
1283     i = q->vcnt - 2;
1284     while (sq_get_data(sq, &argv)) {
1285         id = atoi(argv[i]);
1286         if (id > 0)
1287           status = id_to_name(id, "USER", &argv[i]);
1288         else
1289           status = id_to_name(-id, "STRING", &argv[i]);
1290         if (status && status != MR_NO_MATCH)
1291           return(status);
1292         (*action)(q->vcnt, argv, actarg);
1293         for (j = 0; j < q->vcnt; j++)
1294           free(argv[j]);
1295         free(argv);
1296     }
1297     sq_destroy(sq);
1298     return(MR_SUCCESS);
1299 }
1300
1301
1302 /**
1303  ** followup_ausr - add finger and pobox entries, set_user_modtime
1304  **
1305  ** Inputs:
1306  **     argv[0] - login (add_user)
1307  **     argv[3] - last name
1308  **     argv[4] - first name
1309  **     argv[5] - middle name
1310  **
1311  **/
1312
1313 followup_ausr(q, argv, cl)
1314     struct query *q;
1315     char *argv[];
1316     client *cl;
1317 {
1318     EXEC SQL BEGIN DECLARE SECTION;
1319     int who;
1320     char *login, *entity;
1321     char fullname[129];
1322     EXEC SQL END DECLARE SECTION;
1323
1324     login = argv[0];
1325     who = cl->client_id;
1326     entity = cl->entity;
1327
1328     /* build fullname */
1329     if (strlen(argv[4]) && strlen(argv[5]))
1330         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1331     else if (strlen(argv[4]))
1332         sprintf(fullname, "%s %s", argv[4], argv[3]);
1333     else
1334         sprintf(fullname, "%s", argv[3]);
1335
1336     /* create finger entry, pobox & set modtime on user */
1337 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1338 ##           #fullname=@fullname, mit_affil = u.mit_year,
1339 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1340 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1341 ##      where u.#login = @login
1342
1343     return(MR_SUCCESS);
1344 }
1345
1346
1347 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1348  * type in argv[1].  Then completes the upcall to the user.
1349  *
1350  * argv[2] is of the form "123:234" where the first integer is the machine
1351  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1352  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1353  * are skipped.
1354  */
1355
1356 followup_gpob(q, sq, v, action, actarg, cl)
1357     register struct query *q;
1358     register struct save_queue *sq;
1359     register struct validate *v;
1360     register int (*action)();
1361     int actarg;
1362     client *cl;
1363 {
1364     char **argv, *index();
1365     char *ptype, *p;
1366     int mid, sid, status;
1367
1368     /* for each row */
1369     while (sq_get_data(sq, &argv)) {
1370         mr_trim_args(2, argv);
1371         ptype = argv[1];
1372         p = index(argv[2], ':');
1373         *p++ = 0;
1374         mid = atoi(argv[2]);
1375         sid = atoi(p);
1376
1377         if (!strcmp(ptype, "POP")) {
1378             status = id_to_name(mid, "MACHINE", &argv[2]);
1379             if (status == MR_NO_MATCH)
1380               return(MR_MACHINE);
1381         } else if (!strcmp(ptype, "SMTP")) {
1382             status = id_to_name(sid, "STRING", &argv[2]);
1383             if (status == MR_NO_MATCH)
1384               return(MR_STRING);
1385         } else /* ptype == "NONE" */ {
1386             goto skip;
1387         }
1388         if (status) return(status);
1389
1390         if (!strcmp(q->shortname, "gpob")) {
1391             sid = atoi(argv[4]);
1392             if (sid > 0)
1393               status = id_to_name(sid, "USER", &argv[4]);
1394             else
1395               status = id_to_name(-sid, "STRING", &argv[4]);
1396         }
1397         if (status && status != MR_NO_MATCH) return(status);
1398
1399         (*action)(q->vcnt, argv, actarg);
1400     skip:
1401         /* free saved data */
1402         free(argv[0]);
1403         free(argv[1]);
1404         free(argv[4]);
1405         free(argv);
1406     }
1407
1408     sq_destroy(sq);
1409     return (MR_SUCCESS);
1410 }
1411
1412
1413 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1414  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1415  * proper name based on the type, and repace that string in the argv.
1416  * Also fixes the modby field by called followup_fix_modby.
1417  */
1418
1419 followup_glin(q, sq, v, action, actarg, cl)
1420     register struct query *q;
1421     register struct save_queue *sq;
1422     register struct validate *v;
1423     register int (*action)();
1424     int actarg;
1425     client *cl;
1426 {
1427     char **argv, *malloc(), *realloc(), *type;
1428     int id, i, idx, status;
1429
1430     idx = 8;
1431     if (!strcmp(q->shortname, "gsin"))
1432       idx = 12;
1433
1434     while (sq_get_data(sq, &argv)) {
1435         mr_trim_args(q->vcnt, argv);
1436
1437         id = atoi(argv[i = q->vcnt - 2]);
1438         if (id > 0)
1439           status = id_to_name(id, "USER", &argv[i]);
1440         else
1441           status = id_to_name(-id, "STRING", &argv[i]);
1442         if (status && status != MR_NO_MATCH)
1443           return(status);
1444
1445         id = atoi(argv[idx]);
1446         type = argv[idx - 1];
1447
1448         if (!strcmp(type, "LIST")) {
1449             status = id_to_name(id, "LIST", &argv[idx]);
1450         } else if (!strcmp(type, "USER")) {
1451             status = id_to_name(id, "USER", &argv[idx]);
1452         } else if (!strcmp(type, "KERBEROS")) {
1453             status = id_to_name(id, "STRING", &argv[idx]);
1454         } else if (!strcmp(type, "NONE")) {
1455             status = 0;
1456             free(argv[idx]);
1457             argv[idx] = strsave("NONE");
1458         } else {
1459             status = 0;
1460             free(argv[idx]);
1461             argv[idx] = strsave("???");
1462         }
1463         if (status && status != MR_NO_MATCH)
1464           return(status);
1465
1466         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1467             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1468             strcpy(argv[6], UNIQUE_GID);
1469         }
1470
1471         /* send the data */
1472         (*action)(q->vcnt, argv, actarg);
1473
1474         /* free saved data */
1475         for (i = 0; i < q->vcnt; i++) 
1476             free(argv[i]);
1477         free(argv);
1478     }
1479
1480     sq_destroy(sq);
1481     return (MR_SUCCESS);
1482 }
1483
1484
1485 /* followup_gqot: Fix the entity name, directory name & modby fields
1486  *   argv[0] = filsys_id
1487  *   argv[1] = type
1488  *   argv[2] = entity_id
1489  *   argv[3] = ascii(quota)
1490  */
1491
1492 followup_gqot(q, sq, v, action, actarg, cl)
1493     struct query *q;
1494     register struct save_queue *sq;
1495     struct validate *v;
1496     register int (*action)();
1497     register int actarg;
1498     client *cl;
1499 {
1500     register int j;
1501     char **argv, *malloc();
1502     EXEC SQL BEGIN DECLARE SECTION;
1503     int id, rowcount;
1504     char *name, *label;
1505     EXEC SQL END DECLARE SECTION;
1506     int status, idx;
1507
1508     if (!strcmp(q->name, "get_quota") ||
1509         !strcmp(q->name, "get_quota_by_filesys"))
1510       idx = 4;
1511     else
1512       idx = 3;
1513     while (sq_get_data(sq, &argv)) {
1514         if (idx == 4) {
1515             switch (argv[1][0]) {
1516             case 'U':
1517                 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1518                 break;
1519             case 'G':
1520             case 'L':
1521                 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1522                 break;
1523             case 'A':
1524                 free(argv[2]);
1525                 argv[2] = strsave("system:anyuser");
1526                 break;
1527             default:
1528                 id = atoi(argv[2]);
1529                 argv[2] = malloc(8);
1530                 sprintf(argv[2], "%d", id);
1531             }
1532         }
1533         id = atoi(argv[idx]);
1534         free(argv[idx]);
1535         argv[idx] = malloc(256);
1536         name = argv[idx];
1537         if (id == 0) {
1538             label = argv[0];
1539             EXEC SQL SELECT name
1540                      INTO :name
1541                      FROM filesys
1542                      WHERE label = :label;
1543         } else {
1544             EXEC SQL SELECT dir
1545                      INTO :name
1546                      FROM nfsphys
1547                      WHERE nfsphys_id = :id;
1548         }
1549         if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1) {
1550             sprintf(argv[idx], "#%d", id);
1551         }
1552
1553         id = atoi(argv[idx+3]);
1554         if (id > 0)
1555           status = id_to_name(id, "USER", &argv[idx+3]);
1556         else
1557           status = id_to_name(-id, "STRING", &argv[idx+3]);
1558         if (status && status != MR_NO_MATCH)
1559           return(status);
1560         (*action)(q->vcnt, argv, actarg);
1561         for (j = 0; j < q->vcnt; j++)
1562           free(argv[j]);
1563         free(argv);
1564     }
1565     sq_destroy(sq);
1566     return(MR_SUCCESS);
1567 }
1568
1569
1570 /* followup_aqot: Add allocation to nfsphys after creating quota.
1571  *   argv[0] = filsys_id
1572  *   argv[1] = type if "add_quota" or "update_quota"
1573  *   argv[2 or 1] = id
1574  *   argv[3 or 2] = ascii(quota)
1575  */
1576
1577 followup_aqot(q, argv, cl)
1578     struct query  *q;
1579     char **argv;
1580     client *cl;
1581 {
1582     EXEC SQL BEGIN DECLARE SECTION;
1583     int quota, id, fs, who;
1584     char *entity, *qtype;
1585     EXEC SQL END DECLARE SECTION;
1586
1587     fs = *(int *)argv[0];
1588     if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1589         qtype = argv[1];
1590         id = *(int *)argv[2];
1591         quota = atoi(argv[3]);
1592     } else {
1593         qtype = "USER";
1594         id = *(int *)argv[1];
1595         quota = atoi(argv[2]);
1596     }
1597     who = cl->client_id;
1598     entity = cl->entity;
1599
1600 ##  repeat replace q (modtime = "now", modby = @who, modwith = @entity)
1601 ##      where q.filsys_id = @fs and q.type = @qtype and q.entity_id = @id
1602 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1603 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1604     if (ingres_errno) return(mr_errcode);
1605     return(MR_SUCCESS);
1606 }
1607
1608
1609 followup_gpce(q, sq, v, action, actarg, cl)
1610     struct query *q;
1611     register struct save_queue *sq;
1612     struct validate *v;
1613     register int (*action)();
1614     register int actarg;
1615     client *cl;
1616 {
1617     register int i, j;
1618     char **argv, *malloc();
1619     int id, status;
1620
1621     i = q->vcnt - 2;
1622     while (sq_get_data(sq, &argv)) {
1623         id = atoi(argv[PCAP_QSERVER]);
1624         status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1625         if (status) return (status);
1626         id = atoi(argv[i]);
1627         if (id > 0)
1628           status = id_to_name(id, "USER", &argv[i]);
1629         else
1630           status = id_to_name(-id, "STRING", &argv[i]);
1631         if (status && status != MR_NO_MATCH)
1632           return(status);
1633         (*action)(q->vcnt, argv, actarg);
1634         for (j = 0; j < q->vcnt; j++)
1635           free(argv[j]);
1636         free(argv);
1637     }
1638     sq_destroy(sq);
1639     return(MR_SUCCESS);
1640 }
1641
1642
1643 /* followup_gzcl:
1644  */
1645
1646 followup_gzcl(q, sq, v, action, actarg, cl)
1647     register struct query *q;
1648     register struct save_queue *sq;
1649     register struct validate *v;
1650     register int (*action)();
1651     int actarg;
1652     client *cl;
1653 {
1654     int id, i, status;
1655     char **argv;
1656
1657     while (sq_get_data(sq, &argv)) {
1658         mr_trim_args(q->vcnt, argv);
1659
1660         id = atoi(argv[i = q->vcnt - 2]);
1661         if (id > 0)
1662           status = id_to_name(id, "USER", &argv[i]);
1663         else
1664           status = id_to_name(-id, "STRING", &argv[i]);
1665         if (status && status != MR_NO_MATCH)
1666           return(status);
1667
1668         for (i = 1; i < 8; i+=2) {
1669             id = atoi(argv[i+1]);
1670             if (!strcmp(argv[i], "LIST")) {
1671                 status = id_to_name(id, "LIST", &argv[i+1]);
1672             } else if (!strcmp(argv[i], "USER")) {
1673                 status = id_to_name(id, "USER", &argv[i+1]);
1674             } else if (!strcmp(argv[i], "KERBEROS")) {
1675                 status = id_to_name(id, "STRING", &argv[i+1]);
1676             } else if (!strcmp(argv[i], "NONE")) {
1677                 status = 0;
1678                 free(argv[i+1]);
1679                 argv[i+1] = strsave("NONE");
1680             } else {
1681                 status = 0;
1682                 free(argv[i+1]);
1683                 argv[i+1] = strsave("???");
1684             }
1685             if (status && status != MR_NO_MATCH)
1686               return(status);
1687         }
1688
1689         /* send the data */
1690         (*action)(q->vcnt, argv, actarg);
1691
1692         /* free saved data */
1693         for (i = 0; i < q->vcnt; i++) 
1694             free(argv[i]);
1695         free(argv);
1696     }
1697     sq_destroy(sq);
1698     return(MR_SUCCESS);
1699 }
1700
1701
1702 /* followup_gsha:
1703  */
1704
1705 followup_gsha(q, sq, v, action, actarg, cl)
1706     register struct query *q;
1707     register struct save_queue *sq;
1708     register struct validate *v;
1709     register int (*action)();
1710     int actarg;
1711     client *cl;
1712 {
1713     char **argv;
1714     int i, id, status;
1715
1716     while (sq_get_data(sq, &argv)) {
1717         mr_trim_args(q->vcnt, argv);
1718
1719         id = atoi(argv[4]);
1720         if (id > 0)
1721           status = id_to_name(id, "USER", &argv[4]);
1722         else
1723           status = id_to_name(-id, "STRING", &argv[4]);
1724         if (status && status != MR_NO_MATCH)
1725           return(status);
1726
1727         id = atoi(argv[2]);
1728         if (!strcmp(argv[1], "LIST")) {
1729             status = id_to_name(id, "LIST", &argv[2]);
1730         } else if (!strcmp(argv[1], "USER")) {
1731             status = id_to_name(id, "USER", &argv[2]);
1732         } else if (!strcmp(argv[1], "KERBEROS")) {
1733             status = id_to_name(id, "STRING", &argv[2]);
1734         } else if (!strcmp(argv[1], "NONE")) {
1735             status = 0;
1736             free(argv[2]);
1737             argv[2] = strsave("NONE");
1738         } else {
1739             status = 0;
1740             free(argv[2]);
1741             argv[2] = strsave("???");
1742         }
1743         if (status && status != MR_NO_MATCH)
1744           return(status);
1745
1746         /* send the data */
1747         (*action)(q->vcnt, argv, actarg);
1748
1749         /* free saved data */
1750         for (i = 0; i < q->vcnt; i++) 
1751             free(argv[i]);
1752         free(argv);
1753     }
1754     sq_destroy(sq);
1755     return(MR_SUCCESS);
1756 }
1757
1758
1759 \f
1760 /* Special query routines */
1761
1762 /* set_pobox - this does all of the real work.
1763  *       argv = user_id, type, box
1764  * if type is POP, then box should be a machine, and its ID should be put in
1765  * pop_id.  If type is SMTP, then box should be a string and its ID should
1766  * be put in box_id.  If type is NONE, then box doesn't matter.
1767  */
1768
1769 int set_pobox(q, argv, cl)
1770     struct query *q;
1771     char **argv;
1772     client *cl;
1773 {
1774     EXEC SQL BEGIN DECLARE SECTION;
1775     int user, id;
1776     char *box, potype[9];
1777     EXEC SQL END DECLARE SECTION;
1778     int status;
1779
1780     box = argv[2];
1781     user = *(int *)argv[0];
1782     EXEC SQL SELECT pop_id, potype
1783              INTO :id, :potype
1784              FROM users
1785              WHERE users_id = :user;
1786     if (ingres_errno) return(mr_errcode);
1787     if (!strcmp(strtrim(potype), "POP"))
1788       set_pop_usage(id, -1);
1789
1790     if (!strcmp(argv[1], "POP")) {
1791         status = name_to_id(box, "MACHINE", &id);
1792         if (status == MR_NO_MATCH)
1793           return(MR_MACHINE);
1794         else if (status)
1795           return(status);
1796 ##      repeat replace users (#potype = "POP", pop_id = @id)
1797 ##              where users.users_id = @user
1798         set_pop_usage(id, 1);
1799     } else if (!strcmp(argv[1], "SMTP")) {
1800         if (index(box, '/') || index(box, '|'))
1801           return(MR_BAD_CHAR);
1802         status = name_to_id(box, "STRING", &id);
1803         if (status == MR_NO_MATCH) {
1804             EXEC SQL SELECT value 
1805                      INTO :id 
1806                      FROM values_tbl 
1807                      WHERE name =  "strings_id";
1808             id++;
1809 ##          repeat replace values_tbl.(value = @id) where values_tbl.name = "strings_id"
1810 ##          append to strings (string_id = id, string = box)
1811         } else if (status)
1812           return(status);
1813 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1814 ##             where users.users_id = @user
1815     } else /* argv[1] == "NONE" */ {
1816 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1817     }
1818
1819     set_pobox_modtime(q, argv, cl);
1820 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1821 ##      where tblstats.#table = "users"
1822     if (ingres_errno) return(mr_errcode);
1823     return(MR_SUCCESS);
1824 }
1825
1826
1827 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1828  * each list.  This is tricky:  first build a queue of all requested
1829  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1830  */
1831
1832 get_list_info(q, aargv, cl, action, actarg)
1833     register struct query *q;
1834     char **aargv;
1835     client *cl;
1836     register int (*action)();
1837     int actarg;
1838 {
1839     char *argv[13], *malloc(), *realloc();
1840     EXEC SQL BEGIN DECLARE SECTION;
1841     char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1842     char maillist[5], grp[5], gid[6], acl_name[256], desc[256], modtime[27];
1843     char modby[256], modwith[9];
1844     int id, rowcount, acl_id, hid, modby_id;
1845     EXEC SQL END DECLARE SECTION;
1846     int returned, status;
1847     struct save_queue *sq, *sq_create();
1848
1849     returned = rowcount = 0;
1850     name = aargv[0];
1851
1852     sq = sq_create();
1853     EXEC SQL DECLARE l_cursor CURSOR FOR
1854           SELECT L.list_id
1855           FROM LIST L
1856           WHERE L.name = :name;
1857     EXEC SQL OPEN l_cursor;
1858     while (1) {
1859         EXEC SQL FETCH l_cursor INTO :id;
1860         if (sqlca.sqlcode != 0) break;
1861         sq_save_data(sq, id);
1862         rowcount++;
1863     }
1864     EXEC SQL CLOSE l_cursor;
1865     if (ingres_errno) return(mr_errcode);
1866     if (rowcount == 0)
1867       return(MR_NO_MATCH);
1868
1869     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1870     argv[4] = maillist; argv[5] = grp; argv[6] = gid; argv[7] = acl_type;
1871     argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
1872
1873     while (sq_get_data(sq, &id)) {
1874         if (id == 0)
1875           continue;
1876         argv[6] = gid;
1877 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1878 ##              public = text(l.#public), hidden = text(l.#hidden),
1879 ##              hid = l.#hidden, maillist = text(l.#maillist),
1880 ##              group = text(l.#grp), gid = text(l.#gid),
1881 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1882 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1883 ##              modwith =l.#modwith)
1884 ##          where l.list_id = @id
1885         if (ingres_errno) return(mr_errcode);
1886
1887         if (atoi(gid) == -1)
1888             argv[6] = UNIQUE_GID;
1889
1890         argv[8] = malloc(0);
1891         if (!strcmp(acl_type, "LIST")) {
1892             status = id_to_name(acl_id, "LIST", &argv[8]);
1893         } else if (!strcmp(acl_type, "USER")) {
1894             status = id_to_name(acl_id, "USER", &argv[8]);
1895         } else if (!strcmp(acl_type, "KERBEROS")) {
1896             status = id_to_name(acl_id, "STRING", &argv[8]);
1897         } else if (!strcmp(acl_type, "NONE")) {
1898             status = 0;
1899             free(argv[8]);
1900             argv[8] = strsave("NONE");
1901         } else {
1902             status = 0;
1903             free(argv[8]);
1904             argv[8] = strsave("???");
1905         }
1906         if (status && status != MR_NO_MATCH) return(status);
1907
1908         argv[11] = malloc(0);
1909         if (modby_id > 0)
1910           status = id_to_name(modby_id, "USER", &argv[11]);
1911         else
1912           status = id_to_name(-modby_id, "STRING", &argv[11]);
1913         if (status && status != MR_NO_MATCH) return(status);
1914
1915         mr_trim_args(q->vcnt, argv);
1916         returned++;
1917         (*action)(q->vcnt, argv, actarg);
1918         free(argv[8]);
1919         free(argv[11]);
1920     }
1921
1922     sq_destroy(sq);
1923     if (ingres_errno) return(mr_errcode);
1924     return (MR_SUCCESS);
1925 }
1926
1927
1928 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
1929  * how many different ancestors a member is allowed to have.
1930  */
1931
1932 #define MAXLISTDEPTH    1024
1933
1934 int add_member_to_list(q, argv, cl)
1935     struct query *q;
1936     char **argv;
1937     client *cl;
1938 {
1939     EXEC SQL BEGIN DECLARE SECTION;
1940     int id, lid, mid, exist, error, who, ref;
1941     char *mtype, dtype[9], *entity;
1942     EXEC SQL END DECLARE SECTION;
1943     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
1944     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
1945     int status;
1946     char *dtypes[MAXLISTDEPTH];
1947     char *iargv[3], *buf;
1948
1949     EXEC SQL DECLARE m_cursor_a CURSOR FOR
1950           SELECT M.list_id, M.ref_count
1951           FROM IMEMBERS M
1952           WHERE M.member_id = :lid AND M.member_type = "LIST";
1953     EXEC SQL OPEN m_cursor_a;
1954
1955     lid = *(int *)argv[0];
1956     mtype = argv[1];
1957     mid = *(int *)argv[2];
1958     /* if the member is already a direct member of the list, punt */
1959 ##  repeat retrieve (exist = any(m.list_id where m.list_id=@lid and 
1960 ##                         m.member_id = @mid and m.member_type = @mtype
1961 ##                         and m.direct = 1))
1962     if (exist)
1963       return(MR_EXISTS);
1964     if (!strcasecmp(mtype, "STRING")) {
1965         buf = malloc(0);
1966         status = id_to_name(mid, "STRING", &buf);
1967         if (status) return(status);
1968         if (index(buf, '/') || index(buf, '|')) {
1969             free(buf);
1970             return(MR_BAD_CHAR);
1971         }
1972         free(buf);
1973     }
1974
1975     ancestors[0] = lid;
1976     aref[0] = 1;
1977     acount = 1;
1978     while (1) {
1979         EXEC SQL FETCH m_cursor_a INTO :id, :ref;
1980         if (sqlca.sqlcode != 0) break;
1981         aref[acount] = ref;
1982         ancestors[acount++] = id;
1983         if (acount >= MAXLISTDEPTH) {
1984            return(MR_INTERNAL);
1985         }
1986     }
1987     if (ingres_errno) return(mr_errcode);
1988     if (acount >= MAXLISTDEPTH) {
1989         return(MR_INTERNAL);
1990     }
1991     EXEC SQL CLOSE m_cursor_a;
1992     descendants[0] = mid;
1993     dtypes[0] = mtype;
1994     dref[0] = 1;
1995     dcount = 1;
1996     error = 0;
1997
1998
1999     if (!strcmp(mtype, "LIST")) {
2000         EXEC SQL DECLARE m_cursor_l CURSOR FOR
2001              SELECT M.member_id, M.memeber_type, M.ref_count
2002              FROM IMEMBERS M
2003              WHERE M.list_id = :mid;
2004         EXEC SQL OPEN m_cursor_l;
2005         while (1) {
2006             EXEC SQL FETCH m_cursor_l INTO :id, :dtype, :ref;
2007             if (sqlca.sqlcode != 0) break;
2008             switch (dtype[0]) {
2009             case 'L':
2010                 dtypes[dcount] = "LIST";
2011                 break;
2012             case 'U':
2013                 dtypes[dcount] = "USER";
2014                 break;
2015             case 'S':
2016                 dtypes[dcount] = "STRING";
2017                 break;
2018             case 'K':
2019                 dtypes[dcount] = "KERBEROS";
2020                 break;
2021             default:
2022                 error++;
2023             }
2024             dref[dcount] = ref;
2025             descendants[dcount++] = id;
2026             if (dcount >= MAXLISTDEPTH) {
2027                 error++;
2028             }
2029         }
2030         EXEC SQL CLOSE m_cursor_l;
2031         if (ingres_errno) return(mr_errcode);
2032         if (error)
2033           return(MR_INTERNAL);
2034     }
2035     for (a = 0; a < acount; a++) {
2036         lid = ancestors[a];
2037         for (d = 0; d < dcount; d++) {
2038             mid = descendants[d];
2039             mtype = dtypes[d];
2040             if (mid == lid && !strcmp(mtype, "LIST")) {
2041                 return(MR_LISTLOOP);
2042             }
2043 ##          repeat retrieve (exist = any(m.ref_count where m.list_id = @lid
2044 ##                                       and m.member_id = @mid
2045 ##                                       and m.member_type = @mtype))
2046             ref = aref[a] * dref[d];
2047             if (exist) {
2048                 if (a == 0 && d == 0)
2049 ##                replace m (ref_count = m.ref_count+ref, direct = 1)
2050 ##                           where m.list_id = lid and m.member_id = mid and
2051 ##                           m.member_type = mtype
2052                 else
2053 ##                replace m (ref_count = m.ref_count+ref)
2054 ##                           where m.list_id = lid and m.member_id = mid and
2055 ##                           m.member_type = mtype
2056             } else {
2057                 incremental_clear_before();
2058                 if (a == 0 && d == 0)
2059 ##                append imembers (list_id=lid, member_id = mid, direct = 1,
2060 ##                                 member_type=mtype, ref_count = 1)
2061                 else
2062 ##                append imembers (list_id=lid, member_id = mid,
2063 ##                                 member_type=mtype, ref_count = ref)
2064                 iargv[0] = (char *)lid;
2065                 iargv[1] = mtype;
2066                 iargv[2] = (char *)mid;
2067                 incremental_after("members", 0, iargv);
2068             }
2069         }
2070     }
2071     lid = *(int *)argv[0];
2072     entity = cl->entity;
2073     who = cl->client_id;
2074 ##  repeat replace list (modtime = "now", modby = @who, modwith = @entity)
2075 ##       where list.#list_id = @lid
2076     if (ingres_errno) return(mr_errcode);
2077     return(MR_SUCCESS);
2078 }
2079
2080
2081 /* Delete_member_from_list: do list flattening as we go!
2082  */
2083
2084 int delete_member_from_list(q, argv, cl)
2085     struct query *q;
2086     char **argv;
2087     client *cl;
2088 {
2089     EXEC SQL BEGIN DECLARE SECTION;
2090     int id, lid, mid, cnt, exist, error, who, ref;
2091     char *mtype, dtype[9], *entity;
2092     EXEC SQL END DECLARE SECTION;
2093     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2094     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2095     char *dtypes[MAXLISTDEPTH];
2096     char *iargv[3];
2097
2098 ##  range of m is imembers
2099     lid = *(int *)argv[0];
2100     mtype = argv[1];
2101     mid = *(int *)argv[2];
2102     /* if the member is not a direct member of the list, punt */
2103 ##  repeat retrieve (exist = any(m.list_id where m.list_id=@lid and 
2104 ##                         m.member_id = @mid and m.member_type = @mtype
2105 ##                         and m.direct = 1))
2106     if (ingres_errno) return(mr_errcode);
2107     if (!exist)
2108       return(MR_NO_MATCH);
2109     ancestors[0] = lid;
2110     aref[0] = 1;
2111     acount = 1;
2112
2113     EXEC SQL DECLARE m3_cursor CURSOR FOR
2114          SELECT M.list_id, M.ref_count
2115          FROM IMEMBERS M
2116          WHERE M.member_id = :lid AND M.member_type = "LIST";
2117     EXEC SQL OPEN m3_cursor;
2118     while (1) {
2119         EXEC SQL FETCH m3_cursor INTO :id, :ref;
2120         if (sqlca.sqlcode != 0) break;
2121         aref[acount] = ref;
2122         ancestors[acount++] = id;
2123         if (acount >= MAXLISTDEPTH)
2124           break; 
2125     }
2126     EXEC SQL CLOSE m3_cursor;
2127     if (ingres_errno) return(mr_errcode);
2128     if (acount >= MAXLISTDEPTH)
2129       return(MR_INTERNAL);
2130     descendants[0] = mid;
2131     dtypes[0] = mtype;
2132     dref[0] = 1;
2133     dcount = 1;
2134     error = 0;
2135     if (!strcmp(mtype, "LIST")) {
2136         EXEC SQL DECLARE m4_cursor CURSOR FOR
2137              SELECT M.member_id, M.memeber_type, M.ref_count
2138              FROM IMEMBERS M
2139              WHERE M.list_id = :mid;
2140         EXEC SQL OPEN m4_cursor;
2141         while (1) {
2142             EXEC SQL FETCH m4_cursor INTO :id, :dtype, :ref;
2143             if (sqlca.sqlcode != 0) break;
2144             switch (dtype[0]) {
2145             case 'L':
2146                 dtypes[dcount] = "LIST";
2147                 break;
2148             case 'U':
2149                 dtypes[dcount] = "USER";
2150                 break;
2151             case 'S':
2152                 dtypes[dcount] = "STRING";
2153                 break;
2154             case 'K':
2155                 dtypes[dcount] = "KERBEROS";
2156                 break;
2157             default:
2158                 error++;
2159             }
2160             dref[dcount] = ref;
2161             descendants[dcount++] = id;
2162             if (dcount >= MAXLISTDEPTH)
2163                break;
2164         }
2165         EXEC SQL CLOSE m4_cursor;
2166         if (ingres_errno) return(mr_errcode);
2167         if (error)
2168           return(MR_INTERNAL);
2169     }
2170     EXEC SQL DECLARE m5_cursor CURSOR FOR
2171      SELECT M.ref_count
2172      FROM IMEMBERS M
2173      WHERE M.list_id = :lid AND M.member_id = :mid AND M.member_type = :mtype;
2174     EXEC SQL OPEN m5_cursor;
2175     for (a = 0; a < acount; a++) {
2176         lid = ancestors[a];
2177         for (d = 0; d < dcount; d++) {
2178             mid = descendants[d];
2179             mtype = dtypes[d];
2180             if (mid == lid && !strcmp(mtype, "LIST")) {
2181                 return(MR_LISTLOOP);
2182             }
2183             EXEC SQL FETCH m5_cursor INTO :cnt;
2184             if (sqlca.sqlcode != 0) break;
2185             ref = aref[a] * dref[d];
2186             if (cnt <= ref) {
2187                 iargv[0] = (char *)lid;
2188                 iargv[1] = mtype;
2189                 iargv[2] = (char *)mid;
2190                 incremental_before("members", 0, iargv);
2191                 EXEC SQL DELETE 
2192                  FROM IMEMBERS 
2193                  WHERE list_id = :lid AND member_id = :mid 
2194                     AND member_type = :mtype;
2195                 incremental_clear_after();
2196             } else if (a == 0 && d == 0) {
2197                 EXEC SQL UPDATE imembers
2198                  SET ref_count = ref_count - :ref, direct = 0
2199                  WHERE list_id = :lid AND member_id = :mid 
2200                     AND member_type = :mtype;
2201             } else {
2202                 EXEC SQL UPDATE imembers
2203                  SET ref_count = ref_count - :ref
2204                  WHERE list_id = :lid AND member_id = :mid 
2205                     AND member_type = :mtype;
2206             }
2207         }
2208     }
2209     EXEC SQL CLOSE m5_cursor;
2210     lid = *(int *)argv[0];
2211     entity = cl->entity;
2212     who = cl->client_id;
2213     EXEC SQL UPDATE list
2214          SET modtime = "now", modby = :who, modwith = :entity
2215          WHERE list = :list_id;
2216     if (ingres_errno) return(mr_errcode);
2217     return(MR_SUCCESS);
2218 }
2219
2220
2221 /* get_ace_use - given a type and a name, return a type and a name.
2222  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2223  * and argv[1] will contain the ID of the entity in question.  The R*
2224  * types mean to recursively look at every containing list, not just
2225  * when the object in question is a direct member.  On return, the
2226  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2227  */
2228
2229 int get_ace_use(q, argv, cl, action, actarg)
2230     struct query *q;
2231     char *argv[];
2232     client *cl;
2233     int (*action)();
2234     int actarg;
2235 {
2236     int found = 0;
2237     EXEC SQL BEGIN DECLARE SECTION;
2238     char *atype;
2239     int aid, listid, id;
2240     EXEC SQL END DECLARE SECTION;
2241     struct save_queue *sq, *sq_create();
2242
2243     atype = argv[0];
2244     aid = *(int *)argv[1];
2245     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2246         !strcmp(atype, "KERBEROS")) {
2247         return(get_ace_internal(atype, aid, action, actarg));
2248     }
2249
2250     sq = sq_create();
2251     if (!strcmp(atype, "RLIST")) {
2252         sq_save_data(sq, aid);
2253         /* get all the list_id's of containing lists */
2254         EXEC SQL DECLARE m6_cursor CURSOR FOR
2255          SELECT M.list_id
2256          FROM IMEMBERS M
2257          WHERE M.member_type = "LIST" AND M.member_id = :id;
2258         EXEC SQL OPEN m6_cursor;
2259         while (1) {
2260             EXEC SQL FETCH m6_cursor INTO :listid;
2261             if (sqlca.sqlcode != 0) break;
2262             sq_save_unique_data(sq, listid);
2263         }
2264         /* now process each one */
2265         while (sq_get_data(sq, &id)) {
2266             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2267               found++;
2268         }
2269     EXEC SQL CLOSE m6_cursor;
2270     }
2271
2272     if (!strcmp(atype, "RUSER")) {
2273         EXEC SQL DECLARE m7_cursor CURSOR FOR
2274          SELECT M.list_id
2275          FROM IMEMBERS M
2276          WHERE M.member_type = "USER" AND M.member_id = :aid;
2277         EXEC SQL OPEN m7_cursor;
2278         while (1) {
2279             EXEC SQL FETCH m7_cursor INTO :listid;
2280             if (sqlca.sqlcode != 0) break;
2281             sq_save_data(sq, listid);
2282         }
2283         /* now process each one */
2284         while (sq_get_data(sq, &id)) {
2285             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2286               found++;
2287         }
2288         if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2289           found++;
2290     EXEC SQL CLOSE m7_cursor;
2291     }
2292
2293     if (!strcmp(atype, "RKERBERO")) {
2294         EXEC SQL DECLARE m8_cursor CURSOR FOR
2295          SELECT M.list_id
2296          FROM IMEMBERS M
2297          WHERE M.member_type = "KERBEROS" AND M.member_id = :aid;
2298         EXEC SQL OPEN m8_cursor;
2299         while (1) {
2300             EXEC SQL FETCH m8_cursor INTO :listid;
2301             if (sqlca.sqlcode != 0) break;
2302             sq_save_data(sq, listid);
2303         }
2304         /* now process each one */
2305         while (sq_get_data(sq, &id)) {
2306             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2307               found++;
2308         }
2309         if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2310           found++;
2311     EXEC SQL CLOSE m8_cursor;
2312     }
2313
2314     sq_destroy(sq);     
2315     if (ingres_errno) return(mr_errcode);
2316     if (!found) return(MR_NO_MATCH);
2317     return(MR_SUCCESS);
2318 }
2319
2320
2321 /* This looks up a single list or user for ace use.  atype must be "USER"
2322  * or "LIST", and aid is the ID of the corresponding object.  This is used
2323  * by get_ace_use above.
2324  */
2325
2326 ##get_ace_internal(atype, aid, action, actarg)
2327     EXEC SQL BEGIN DECLARE SECTION;
2328     char *atype;
2329     int aid;
2330     EXEC SQL END DECLARE SECTION;
2331     int (*action)();
2332     int actarg;
2333 {
2334     char *rargv[2];
2335     int found = 0;
2336     EXEC SQL BEGIN DECLARE SECTION;
2337     char name[33];
2338     EXEC SQL END DECLARE SECTION;
2339
2340     rargv[1] = name;
2341     EXEC SQL DECLARE F1_cursor CURSOR FOR
2342          SELECT F.label
2343          FROM FILESYS F
2344          WHERE F.owners = :aid;
2345     EXEC SQL OPEN F1_cursor;
2346
2347     EXEC SQL DECLARE C1_cursor CURSOR FOR
2348          SELECT C.capability
2349          FROM CAPACLS C
2350          WHERE C.list_id = :aid;
2351     EXEC SQL OPEN C1_cursor;
2352
2353     if (!strcmp(atype, "LIST")) {
2354         rargv[0] = "FILESYS";
2355         while (1) {
2356             EXEC SQL FETCH F1_cursor INTO :name;
2357             if (sqlca.sqlcode != 0) break;
2358             (*action)(2, rargv, actarg);
2359             found++;
2360         }
2361         rargv[0] = "QUERY";
2362         while (1) {
2363             EXEC SQL FETCH C1_cursor INTO :name;
2364             if (sqlca.sqlcode != 0) break;
2365             (*action)(2, rargv, actarg);
2366             found++;
2367         }
2368     } else if (!strcmp(atype, "USER")) {
2369         rargv[0] = "FILESYS";
2370         while (1) {
2371             EXEC SQL FETCH F1_cursor INTO :name;
2372             if (sqlca.sqlcode != 0) break;
2373             (*action)(2, rargv, actarg);
2374             found++;
2375         }
2376     }
2377     EXEC SQL CLOSE F1_cursor;
2378     EXEC SQL CLOSE C1_cursor;
2379
2380     rargv[0] = "LIST";
2381     EXEC SQL DECLARE l8_cursor CURSOR FOR
2382          SELECT L.name
2383          FROM LIST L
2384          WHERE L.acl_type = :atype AND L.acl_id = :aid;
2385     EXEC SQL OPEN l8_cursor;
2386
2387     while (1) {
2388          EXEC SQL FETCH l8_cursor INTO :name;
2389          if (sqlca.sqlcode != 0) break;
2390          (*action)(2, rargv, actarg);
2391          found++;
2392     }
2393     EXEC SQL CLOSE l8_cursor;
2394
2395     rargv[0] = "SERVICE";
2396     EXEC SQL DECLARE s_cursor CURSOR FOR
2397          SELECT S.name
2398          FROM SERVERS S
2399          WHERE S.acl_type = :atype AND S.acl_id = :aid;
2400     EXEC SQL OPEN s_cursor;
2401
2402     while (1) {
2403          EXEC SQL FETCH s_cursor INTO :name;
2404          if (sqlca.sqlcode != 0) break;
2405          (*action)(2, rargv, actarg);
2406          found++;
2407     }
2408     EXEC SQL CLOSE s_cursor;
2409
2410     rargv[0] = "HOSTACCESS";
2411     EXEC SQL DECLARE h_cursor CURSOR FOR
2412          SELECT M.name
2413          FROM MACHINE M, HOSTACCESS H
2414          WHERE M.mach_id = H.mach_id 
2415              AND H.acl_type = :atype AND H.acl_id = :aid;
2416     EXEC SQL OPEN h_cursor;
2417     while (1) {
2418         EXEC SQL FETCH h_cursor INTO :name;
2419         if (sqlca.sqlcode != 0) break;
2420         (*action)(2, rargv, actarg);
2421         found++;
2422     }
2423     EXEC SQL CLOSE h_cursor;
2424
2425     rargv[0] = "ZEPHYR";
2426     EXEC SQL DECLARE z_cursor CURSOR FOR
2427          SELECT Z.class
2428          FROM ZEPHYR Z
2429          WHERE Z.xmt_type = :atype AND Z.xmt_id = :aid OR
2430             Z.sub_type = :atype AND Z.sub_id = :aid OR
2431             Z.iws_type = :atype AND Z.iws_id = :aid OR
2432             Z.iui_type = :atype AND Z.iui_id = :aid;
2433
2434     EXEC SQL OPEN z_cursor;
2435     while (1) {
2436          EXEC SQL FETCH h_cursor INTO :name;
2437          if (sqlca.sqlcode != 0) break;
2438          (*action)(2, rargv, actarg);
2439          found++;
2440     }
2441     EXEC SQL CLOSE z_cursor;
2442
2443     if (!found) return(MR_NO_MATCH);
2444     return(MR_SUCCESS);
2445 }
2446
2447
2448 /* get_lists_of_member - given a type and a name, return the name and flags
2449  * of all of the lists of the given member.  The member_type is one of
2450  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2451  * and argv[1] will contain the ID of the entity in question.  The R*
2452  * types mean to recursively look at every containing list, not just
2453  * when the object in question is a direct member.
2454  */
2455
2456 int get_lists_of_member(q, argv, cl, action, actarg)
2457     struct query *q;
2458     char *argv[];
2459     client *cl;
2460     int (*action)();
2461     int actarg;
2462 {
2463     int found = 0, direct = 1;
2464     char *rargv[6];
2465     EXEC SQL BEGIN DECLARE SECTION;
2466     char *atype;
2467     int aid, listid, id;
2468     char name[33], active[5], public[5], hidden[5], maillist[5], grp[5];
2469     EXEC SQL END DECLARE SECTION;
2470
2471     atype = argv[0];
2472     aid = *(int *)argv[1];
2473     if (!strcmp(atype, "RLIST")) {
2474         atype = "LIST";
2475         direct = 0;
2476     }
2477     if (!strcmp(atype, "RUSER")) {
2478         atype = "USER";
2479         direct = 0;
2480     }
2481     if (!strcmp(atype, "RSTRING")) {
2482         atype = "STRING";
2483         direct = 0;
2484     }
2485     if (!strcmp(atype, "RKERBEROS")) {
2486         atype = "KERBEROS";
2487         direct = 0;
2488     }
2489
2490     rargv[0] = name;
2491     rargv[1] = active;
2492     rargv[2] = public;
2493     rargv[3] = hidden;
2494     rargv[4] = maillist;
2495     rargv[5] = grp;
2496 ##  range of m is imembers
2497     if (direct) {
2498 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2499 ##                   public = text(list.#public), hidden = text(list.#hidden),
2500 ##                   maillist = text(list.#maillist), grp = text(list.#group))
2501 ##              where list.list_id = m.list_id and m.direct = 1 and
2502 ##                    m.member_type = @atype and m.member_id = @aid {
2503          (*action)(6, rargv, actarg);
2504          found++;
2505 ##    }
2506     } else {
2507 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2508 ##                   public = text(list.#public), hidden = text(list.#hidden),
2509 ##                   maillist = text(list.#maillist), grp = text(list.#group))
2510 ##              where list.list_id = m.list_id and
2511 ##                    m.member_type = @atype and m.member_id = @aid {
2512          (*action)(6, rargv, actarg);
2513          found++;
2514 ##    }
2515     }
2516
2517     if (ingres_errno) return(mr_errcode);
2518     if (!found) return(MR_NO_MATCH);
2519     return(MR_SUCCESS);
2520 ##}
2521
2522
2523 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2524  * the five flags associated with each list.  It will return the name of
2525  * each list that meets the quailifications.  It does this by building a
2526  * where clause based on the arguments, then doing a retrieve.
2527  */
2528
2529 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2530
2531 int qualified_get_lists(q, argv, cl, action, actarg)
2532     struct query *q;
2533     char *argv[];
2534     client *cl;
2535     int (*action)();
2536     int actarg;
2537 {
2538     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2539                          "l", "name", lflags));
2540 }
2541
2542
2543 /** get_members_of_list - optimized query for retrieval of list members
2544  **
2545  ** Inputs:
2546  **   argv[0] - list_id
2547  **
2548  ** Description:
2549  **   - retrieve USER members, then LIST members, then STRING members
2550  **/
2551
2552 get_members_of_list(q, argv, cl, action, actarg)
2553     struct query *q;
2554     char *argv[];
2555     client *cl;
2556     int (*action)();
2557     int actarg;
2558 {
2559     EXEC SQL BEGIN DECLARE SECTION;
2560     int list_id, member_id;
2561     char member_name[129], member_type[9];
2562     EXEC SQL END DECLARE SECTION;
2563     char *targv[2];
2564     int members;
2565     struct save_queue *sq;
2566
2567     list_id = *(int *)argv[0];
2568     members = 0;
2569     sq = sq_create();
2570
2571     EXEC SQL DECLARE m9_cursor CURSOR FOR
2572          SELECT M.member_type, M.member_id
2573          FROM IMEMBERS M
2574          WHERE M.list_id = :list_id AND M.direct = 1;
2575     EXEC SQL OPEN m9_cursor;
2576     while (1) {
2577       EXEC SQL FETCH m9_cursor INTO :member_type, :member_id;
2578       if (sqlca.sqlcode != 0) break;
2579       if (members++ > 49)
2580          break;
2581       sq_save_data(sq, (member_type[0] << 24) | (member_id & 0xffffff));
2582     }
2583     EXEC SQL CLOSE m9_cursor;
2584     if (members <= 49) {
2585         targv[1] = malloc(0);
2586         while (sq_remove_data(sq, &member_id)) {
2587             switch (member_id >> 24) {
2588             case 'U':
2589                 targv[0] = "USER";
2590                 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2591                 (*action)(2, targv, actarg);
2592                 break;
2593             case 'L':
2594                 targv[0] = "LIST";
2595                 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2596                 (*action)(2, targv, actarg);
2597                 break;
2598             case 'S':
2599                 targv[0] = "STRING";
2600                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2601                 (*action)(2, targv, actarg);
2602                 break;
2603             case 'K':
2604                 targv[0] = "KERBEROS";
2605                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2606                 (*action)(2, targv, actarg);
2607                 break;
2608             default:
2609                 sq_destroy(sq);
2610                 return(MR_INTERNAL);
2611             }
2612         }
2613         free(targv[1]);
2614         sq_destroy(sq);
2615         return(MR_SUCCESS);
2616     }
2617     sq_destroy(sq);
2618
2619     targv[1] = member_name;
2620     targv[0] = "USER";
2621 ##  range of m is imembers
2622 ##  repeat retrieve (member_name = users.login)
2623 ##             where m.#list_id = @list_id and m.#member_type = "USER"
2624 ##                   and m.#member_id = users.users_id and m.direct = 1
2625 ##             sort by #member_name
2626 ##  {
2627          (*action)(2, targv, actarg);
2628 ##  }
2629     if (ingres_errno) return(mr_errcode);
2630
2631     targv[0] = "LIST";
2632 ##  repeat retrieve (member_name = list.name)
2633 ##             where m.#list_id = @list_id and m.#member_type = "LIST"
2634 ##                   and m.#member_id = list.#list_id and m.direct = 1
2635 ##             sort by #member_name
2636 ##  {
2637          (*action)(2, targv, actarg);
2638 ##  }
2639     if (ingres_errno) return(mr_errcode);
2640
2641     targv[0] = "STRING";
2642 ##  repeat retrieve (member_name = strings.string)
2643 ##             where m.#list_id = @list_id and m.#member_type = "STRING"
2644 ##                   and m.#member_id = strings.string_id and m.direct = 1
2645 ##             sort by #member_name
2646 ##  {
2647          (*action)(2, targv, actarg);
2648 ##  }
2649     if (ingres_errno) return(mr_errcode);
2650
2651     targv[0] = "KERBEROS";
2652 ##  repeat retrieve (member_name = strings.string)
2653 ##             where m.#list_id = @list_id and m.#member_type = "KERBEROS"
2654 ##                   and m.#member_id = strings.string_id and m.direct = 1
2655 ##             sort by #member_name
2656 ##  {
2657          (*action)(2, targv, actarg);
2658 ##  }
2659     if (ingres_errno) return(mr_errcode);
2660
2661     return(MR_SUCCESS);
2662 }
2663
2664
2665 /* count_members_of_list: this is a simple query, but it cannot be done
2666  * through the dispatch table.
2667  */
2668
2669 int count_members_of_list(q, argv, cl, action, actarg)
2670     struct query *q;
2671     char *argv[];
2672     client *cl;
2673     int (*action)();
2674     int actarg;
2675 {
2676     EXEC SQL BEGIN DECLARE SECTION;
2677     int  list, ct = 0;
2678     EXEC SQL END DECLARE SECTION;
2679     char *rargv[1], countbuf[5];
2680
2681     list = *(int *)argv[0];
2682     rargv[0] = countbuf;
2683 ##  repeat retrieve (ct = count(imembers.list_id
2684 ##                              where imembers.list_id = @list and
2685 ##                                    imembers.direct = 1))
2686     if (ingres_errno) return(mr_errcode);
2687     sprintf(countbuf, "%d", ct);
2688     (*action)(1, rargv, actarg);
2689     return(MR_SUCCESS);
2690 }
2691
2692
2693 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2694  * the three flags associated with each service.  It will return the name of
2695  * each service that meets the quailifications.  It does this by building a
2696  * where clause based on the arguments, then doing a retrieve.
2697  */
2698
2699 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2700
2701 int qualified_get_server(q, argv, cl, action, actarg)
2702     struct query *q;
2703     char *argv[];
2704     client *cl;
2705     int (*action)();
2706     int actarg;
2707 {
2708     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2709                          "s", "name", sflags));
2710 }
2711
2712
2713 /* generic qualified get routine, used by qualified_get_lists,
2714  * qualified_get_server, and qualified_get_serverhost.
2715  *   Args:
2716  *      start - a simple where clause, must not be empty
2717  *      range - the name of the range variable
2718  *      field - the field to return
2719  *      flags - an array of strings, names of the flag variables
2720  */
2721
2722 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2723     struct query *q;
2724     char *argv[];
2725     int (*action)();
2726     int actarg;
2727     char *start;
2728     char *range;
2729     char *field;
2730     char *flags[];
2731 {
2732     EXEC SQL BEGIN DECLARE SECTION;
2733     char name[33], qual[256], *rvar, *rtbl, *rfield;
2734     int rowcount, i;
2735     EXEC SQL END DECLARE SECTION;
2736     char *rargv[1], buf[32];
2737
2738     strcpy(qual, start);
2739     for (i = 0; i < q->argc; i++) {
2740         if (!strcmp(argv[i], "TRUE")) {
2741             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2742             (void) strcat(qual, buf);
2743         } else if (!strcmp(argv[i], "FALSE")) {
2744             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2745             (void) strcat(qual, buf);
2746         }
2747     }
2748       
2749     rargv[0] = name;
2750     rvar = range;
2751     rtbl = q->rtable;
2752     rfield = field;
2753     EXEC SQL DECLARE r9_cursor CURSOR FOR
2754          SELECT R.rfield
2755          FROM RTBL R
2756          WHERE qual;
2757     EXEC SQL OPEN r9_cursor;
2758     while (1) {
2759       EXEC SQL FETCH r9_cursor INTO :name;
2760       if (sqlca.sqlcode != 0) break;
2761         (*action)(1, rargv, actarg);
2762     }
2763     EXEC SQL CLOSE r9_cursor;
2764     if (ingres_errno) return(mr_errcode);
2765     if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2766     return(MR_SUCCESS);
2767 }
2768
2769
2770 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2771  * the five flags associated with each serverhost.  It will return the name of
2772  * each service and host that meets the quailifications.  It does this by 
2773  * building a where clause based on the arguments, then doing a retrieve.
2774  */
2775
2776 static char *shflags[6] = { "service", "enable", "override", "success",
2777                             "inprogress", "hosterror" };
2778
2779 int qualified_get_serverhost(q, argv, cl, action, actarg)
2780     struct query *q;
2781     char *argv[];
2782     client *cl;
2783     int (*action)();
2784     int actarg;
2785 {
2786     EXEC SQL BEGIN DECLARE SECTION;
2787     char sname[33], mname[33], qual[256];
2788     int rowcount, i;
2789     EXEC SQL END DECLARE SECTION;
2790     char *rargv[2], buf[32];
2791
2792     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2793             argv[0]);
2794     for (i = 1; i < q->argc; i++) {
2795         if (!strcmp(argv[i], "TRUE")) {
2796             sprintf(buf, " and sh.%s != 0", shflags[i]);
2797             strcat(qual, buf);
2798         } else if (!strcmp(argv[i], "FALSE")) {
2799             sprintf(buf, " and sh.%s = 0", shflags[i]);
2800             strcat(qual, buf);
2801         }
2802     }
2803       
2804     rargv[0] = sname;
2805     rargv[1] = mname;
2806     EXEC SQL DECLARE s9_cursor CURSOR FOR
2807          SELECT S.service, M.name
2808          FROM SERVERHOSTS S, MACHINE M
2809          WHERE qual;
2810     EXEC SQL OPEN s9_cursor;
2811     while (1) {
2812       EXEC SQL FETCH s_cursor INTO :sname, :mname;
2813       if (sqlca.sqlcode != 0) break;
2814         (*action)(2, rargv, actarg);
2815     }
2816     EXEC SQL CLOSE s9_cursor;
2817     if (ingres_errno) return(mr_errcode);
2818     if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2819     return(MR_SUCCESS);
2820 }
2821
2822
2823 /* register_user - change user's login name and allocate a pobox, group,
2824  * filesystem, and quota for them.  The user's status must start out as 0,
2825  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2826  * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY, 
2827  * MR_FS_STAFF, MR_FS_MISC).
2828  */
2829
2830 register_user(q, argv, cl)
2831     struct query *q;
2832     char **argv;
2833     client *cl;
2834 {
2835     EXEC SQL BEGIN DECLARE SECTION;
2836     char *login, dir[65], *entity, *directory, machname[33];
2837     int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2838     int size, alloc, pid, m_id;
2839     EXEC SQL END DECLARE SECTION;
2840     char buffer[256], *aargv[3];
2841     int maxsize;
2842
2843     entity = cl->entity;
2844     who = cl->client_id;
2845
2846     uid = atoi(argv[0]);
2847     login = argv[1];
2848     utype = atoi(argv[2]);
2849
2850 ##  range of u is users
2851 ##  range of l is list
2852 ##  range of sh is serverhosts
2853 ##  range of n is nfsphys
2854 ##  range of m is machine
2855
2856     /* find user */
2857     EXEC SQL DECLARE u_cursor CURSOR FOR
2858      SELECT U.users_id
2859      FROM USERS U
2860      WHERE U.uid = :uid AND (U.status = 0 OR U.status = 5 OR U.status = 6);
2861     EXEC SQL OPEN u_cursor;
2862     while (1) {
2863         EXEC SQL FETCH u_cursor INTO :users_id;
2864         if (sqlca.sqlcode != 0) break;
2865     }
2866     if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2867     if (sqlca.sqlerrd[2] > 1) return(MR_NOT_UNIQUE);
2868
2869     /* check new login name */
2870 ##  repeat retrieve (flag = any(u.#login where u.#login = @login and
2871 ##                              u.#users_id != users_id))
2872     if (ingres_errno) return(mr_errcode);
2873     if (flag) return(MR_IN_USE);
2874 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2875     if (ingres_errno) return(mr_errcode);
2876     if (flag) return(MR_IN_USE);
2877 ##  repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2878     if (ingres_errno) return(mr_errcode);
2879     if (flag) return(MR_IN_USE);
2880     com_err(whoami, 0, "new login name OK");
2881
2882     /* choose place for pobox, put in mid */
2883
2884 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2885 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2886 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2887     if (ingres_errno) return(mr_errcode);
2888     if (sqlca.sqlcode == 100) return(MR_NO_POBOX);
2889
2890     /* change login name, set pobox */
2891     sprintf(buffer, "u.users_id = %d", users_id);
2892     incremental_before("users", buffer, 0);
2893 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2894 ##                    modby = @who, modwith = @entity, potype="POP",
2895 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2896 ##                    pmodwith=@entity)
2897 ##      where u.#users_id = @users_id
2898     if (ingres_errno) return(mr_errcode);
2899     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2900       return(MR_INTERNAL);
2901     set_pop_usage(mid, 1);
2902     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2903             strtrim(machname));
2904     incremental_after("users", buffer, 0);
2905
2906     /* create group list */
2907     if (set_next_object_id("gid", "list"))
2908       return(MR_NO_ID);
2909     if (set_next_object_id("list_id", "list"))
2910       return(MR_NO_ID);
2911
2912     EXEC SQL DECLARE v_cursor CURSOR FOR
2913          SELECT V.value
2914          FROM values_tbl V
2915          WHERE V.name = "list_id";
2916     EXEC SQL OPEN v_cursor;
2917     while (1) {
2918         EXEC SQL FETCH v_cursor INTO :list_id;
2919         if (sqlca.sqlcode != 0) break;
2920     }
2921     EXEC SQL CLOSE v_cursor;
2922
2923     if (ingres_errno) return(mr_errcode);
2924     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2925       return(MR_INTERNAL);
2926     incremental_clear_before();
2927 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2928 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2929 ##                      #gid = values_tbl.value, desc = "User Group",
2930 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2931 ##                      modby = @who, modwith = @entity)
2932 ##      where values_tbl.name = "gid"
2933     if (ingres_errno) return(mr_errcode);
2934     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2935       return(MR_INTERNAL);
2936     sprintf(buffer, "l.list_id = %d", list_id);
2937     incremental_after("list", buffer, 0);
2938     aargv[0] = (char *) list_id;
2939     aargv[1] = "USER";
2940     aargv[2] = (char *) users_id;
2941     incremental_clear_before();
2942 ##  repeat append imembers (#list_id = @list_id, member_type = "USER",
2943 ##                         member_id = @users_id, ref_count = 1, direct = 1)
2944     if (ingres_errno) return(mr_errcode);
2945     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2946       return(MR_INTERNAL);
2947
2948     incremental_after("members", 0, aargv);
2949     com_err(whoami, 0, "group list created");
2950
2951     /* decide where to put filesystem */
2952     maxsize = 0;
2953     directory = NULL;
2954 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2955 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2956         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2957             maxsize = size - alloc;
2958             if (directory)
2959               free(directory);
2960             directory = strsave(dir);
2961             pid = nid;
2962             m_id = mid;
2963         }
2964 ##  }
2965     if (ingres_errno) return(mr_errcode);
2966     if (maxsize == 0)
2967       return(MR_NO_FILESYS);
2968
2969     /* create filesystem */
2970     if (set_next_object_id("filsys_id", "filesys"))
2971       return(MR_NO_ID);
2972     incremental_clear_before(); 
2973 ##  repeat append filesys (filsys_id = values_tbl.value, phys_id = @pid,
2974 ##                         label = @login, type = "NFS", mach_id = @m_id,
2975 ##                         name = @directory + "/" + @login,
2976 ##                         mount = "/mit/" + @login,
2977 ##                         access = "w", comments = "User Locker",
2978 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2979 ##                         lockertype = "HOMEDIR", modtime = "now",
2980 ##                         modby = @who, modwith = @entity)
2981 ##      where values_tbl.name = "filsys_id"
2982     if (ingres_errno) return(mr_errcode);
2983     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2984       return(MR_INTERNAL);
2985     incremental_after("filesys", 
2986           "fs.filsys_id = values_tbl.value and values_tbl.name = \"filsys_id\"",
2987                       0);
2988     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2989             directory, login);
2990
2991     /* set quota */
2992 ##  repeat retrieve (quota = values_tbl.value) where values_tbl.name = "def_quota"
2993     if (ingres_errno) return(mr_errcode);
2994     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2995       return(MR_NO_QUOTA);
2996     incremental_clear_before();
2997 ##  repeat append #quota (entity_id = @users_id, filsys_id = values_tbl.value,
2998 ##                        type = "USER",
2999 ##                        #quota = @quota, phys_id = @pid, modtime = "now",
3000 ##                        modby = @who, modwith = @entity)
3001 ##      where values_tbl.name = "filsys_id"
3002     if (ingres_errno) return(mr_errcode);
3003     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3004       return(MR_INTERNAL);
3005 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
3006 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
3007 ##            filesys.filsys_id = values_tbl.value and values_tbl.name = "filsys_id"
3008     if (ingres_errno) return(mr_errcode);
3009     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3010       return(MR_INTERNAL);
3011     aargv[0] = login;
3012     aargv[1] = "USER";
3013     aargv[2] = login;
3014     sprintf(buffer, "q.entity_id = %d and q.filsys_id = values_tbl.value and q.type = \"USER\" and values_tbl.name = \"filsys_id\"", users_id);
3015     incremental_after("quota", buffer, aargv);
3016     com_err(whoami, 0, "quota of %d assigned", quota);
3017     if (ingres_errno) return(mr_errcode);
3018
3019     cache_entry(login, "USER", users_id);
3020
3021     EXEC SQL UPDATE tblstats
3022          SET updates = tblstats.update + 1, modtime = "now"
3023          WHERE table_name = "users";
3024
3025     EXEC SQL UPDATE tblstats
3026          SET appends = tblstats.appends + 1, modtime = "now"
3027          WHERE table_name = "list" OR table_name = "filesys" 
3028                OR table_name = "quota";
3029
3030     if (ingres_errno) return(mr_errcode);
3031     return(MR_SUCCESS);
3032 }
3033
3034
3035
3036 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3037  **
3038  ** Inputs:
3039  **   id of machine
3040  **   delta (will be +/- 1)
3041  **
3042  ** Description:
3043  **   - incr/decr value field in serverhosts table for pop/mach_id
3044  **
3045  **/
3046
3047 static int set_pop_usage(id, count)
3048 int id;
3049 int count;
3050 {
3051     EXEC SQL BEGIN DECLARE SECTION;
3052     int mach_id = id;
3053     int n = count;
3054     EXEC SQL END DECLARE SECTION;
3055
3056     EXEC SQL UPDATE serverhosts
3057          SET value1 = value1 + :n
3058          WHERE service = "POP" AND mach_id = :mach_id;
3059
3060     if (ingres_errno) return(mr_errcode);
3061     return(MR_SUCCESS);
3062 }
3063
3064
3065 \f
3066 /* Validation Routines */
3067
3068 validate_row(q, argv, v)
3069     register struct query *q;
3070     char *argv[];
3071     register struct validate *v;
3072 {
3073     EXEC SQL BEGIN DECLARE SECTION;
3074     char *rvar;
3075     char *tbl;
3076     char *name;
3077     char qual[128];
3078     int rowcount;
3079     EXEC SQL END DECLARE SECTION;
3080
3081     /* build where clause */
3082     build_qual(v->qual, v->argc, argv, qual);
3083
3084     /* setup ingres variables */
3085     rvar = q->rvar;
3086     tbl = q->rtable;
3087     name = v->field;
3088
3089     if (log_flags & LOG_VALID)
3090         /* tell the logfile what we're doing */
3091         com_err(whoami, 0, "validating row: %s", qual);
3092     
3093     /* look for the record */
3094 ##  range of rvar is tbl
3095 ##  retrieve (rowcount = count(rvar.name where qual))
3096     if (ingres_errno) return(mr_errcode);
3097     if (rowcount == 0) return(MR_NO_MATCH);
3098     if (rowcount > 1) return(MR_NOT_UNIQUE);
3099     return(MR_EXISTS);
3100 }
3101
3102 validate_fields(q, argv, vo, n)
3103     struct query *q;
3104     register char *argv[];
3105     register struct valobj *vo;
3106     register int n;
3107 {
3108     register int status;
3109
3110     while (--n >= 0) {
3111         switch (vo->type) {
3112         case V_NAME:
3113             if (log_flags & LOG_VALID)
3114                 com_err(whoami, 0, "validating %s in %s: %s", 
3115                     vo->namefield, vo->table, argv[vo->index]);
3116             status = validate_name(argv, vo);
3117             break;
3118
3119         case V_ID:
3120             if (log_flags & LOG_VALID)
3121                 com_err(whoami, 0, "validating %s in %s: %s", 
3122                     vo->idfield, vo->table, argv[vo->index]);
3123             status = validate_id(argv, vo);
3124             break;
3125
3126         case V_DATE:
3127             if (log_flags & LOG_VALID)
3128                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3129             status = validate_date(argv, vo);
3130             break;
3131
3132         case V_TYPE:
3133             if (log_flags & LOG_VALID)
3134                 com_err(whoami, 0, "validating %s type: %s",
3135                     vo->table, argv[vo->index]);
3136             status = validate_type(argv, vo);
3137             break;
3138
3139         case V_TYPEDATA:
3140             if (log_flags & LOG_VALID)
3141                 com_err(whoami, 0, "validating typed data (%s): %s",
3142                     argv[vo->index - 1], argv[vo->index]);
3143             status = validate_typedata(q, argv, vo);
3144             break;
3145
3146         case V_RENAME:
3147             if (log_flags & LOG_VALID)
3148                 com_err(whoami, 0, "validating rename %s in %s",
3149                         argv[vo->index], vo->table);
3150             status = validate_rename(argv, vo);
3151             break;
3152
3153         case V_CHAR:
3154             if (log_flags & LOG_VALID)
3155               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3156             status = validate_chars(argv[vo->index]);
3157             break;
3158
3159         case V_SORT:
3160             status = MR_EXISTS;
3161             break;
3162
3163         case V_LOCK:
3164             status = lock_table(vo);
3165             break;
3166         }
3167
3168         if (status != MR_EXISTS) return(status);
3169         vo++;
3170     }
3171
3172     if (ingres_errno) return(mr_errcode);
3173     return(MR_SUCCESS);
3174 }
3175
3176
3177 /* validate_chars: verify that there are no illegal characters in
3178  * the string.  Legal characters are printing chars other than 
3179  * ", *, ?, \, [ and ].
3180  */
3181 static int illegalchars[] = {
3182     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3183     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3184     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3185     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3186     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
3187     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3188     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3189     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3190     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3191     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3192     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3193     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3194     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3195     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3196     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3197     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3198 };
3199
3200 validate_chars(s)
3201 register char *s;
3202 {
3203     while (*s)
3204       if (illegalchars[*s++])
3205         return(MR_BAD_CHAR);
3206     return(MR_EXISTS);
3207 }
3208
3209
3210 validate_id(argv, vo)
3211     char *argv[];
3212     register struct valobj *vo;
3213 {
3214     EXEC SQL BEGIN DECLARE SECTION;
3215     char *name;
3216     char *tbl;
3217     char *namefield;
3218     char *idfield;
3219     int id, rowcount;
3220     EXEC SQL END DECLARE SECTION;
3221     int status;
3222     register char *c;
3223
3224
3225     name = argv[vo->index];
3226     tbl = vo->table;
3227     namefield = vo->namefield;
3228     idfield = vo->idfield;
3229
3230     if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3231         !strcmp(tbl, "machine") ||
3232         !strcmp(tbl, "filesys") ||
3233         !strcmp(tbl, "list") ||
3234         !strcmp(tbl, "cluster") ||
3235         !strcmp(tbl, "string")) {
3236         if (!strcmp(tbl, "machine"))
3237           for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3238         status = name_to_id(name, tbl, &id);
3239         if (status == 0) {
3240             *(int *)argv[vo->index] = id;
3241             return(MR_EXISTS);
3242         } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3243           return(vo->error);
3244         else
3245           return(status);
3246     }
3247
3248     if (!strcmp(namefield, "uid")) {
3249 ##    retrieve (id = tbl.idfield) where tbl.namefield = int4(name)
3250       if (ingres_errno) return(mr_errcode);
3251     } else {
3252 ##    retrieve (id = table.idfield) where table.namefield = name
3253       if (ingres_errno) return(mr_errcode);
3254     }
3255     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3256       return(vo->error);
3257     *(int *)argv[vo->index] = id;
3258     return(MR_EXISTS);
3259 }
3260
3261 validate_name(argv, vo)
3262     char *argv[];
3263     register struct valobj *vo;
3264 {
3265     EXEC SQL BEGIN DECLARE SECTION;
3266     char *name;
3267     char *tbl;
3268     char *namefield;
3269     int rowcount;
3270     EXEC SQL END DECLARE SECTION;
3271     register char *c;
3272
3273     name = argv[vo->index];
3274     tbl = vo->table;
3275     namefield = vo->namefield;
3276     if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3277         for (c = name; *c; c++)
3278           if (islower(*c))
3279             *c = toupper(*c);
3280     }
3281 ##  retrieve (rowcount = countu(tbl.namefield 
3282 ##            where tbl.namefield = name))
3283     if (ingres_errno) return(mr_errcode);
3284     return ((rowcount == 1) ? MR_EXISTS : vo->error);
3285 }
3286
3287 validate_date(argv, vo)
3288     char *argv[];
3289     struct valobj *vo;
3290 {
3291     EXEC SQL BEGIN DECLARE SECTION;
3292     char *idate;
3293     double dd;
3294     int errorno;
3295     EXEC SQL END DECLARE SECTION;
3296
3297     idate = argv[vo->index];
3298
3299 ##  retrieve (dd = interval("years", date(idate) - date("today")))
3300     if (sqlca.sqlcode < 0 || dd > 5.0) return(MR_DATE);
3301     return(MR_EXISTS);
3302 }
3303
3304
3305 validate_rename(argv, vo)
3306 char *argv[];
3307 struct valobj *vo;
3308 {
3309     EXEC SQL BEGIN DECLARE SECTION;
3310     char *name, *tbl, *namefield, *idfield;
3311     int id;
3312     EXEC SQL END DECLARE SECTION;
3313     int status;
3314     register char *c;
3315
3316     c = name = argv[vo->index];
3317     while (*c)
3318       if (illegalchars[*c++])
3319         return(MR_BAD_CHAR);
3320     tbl = vo->table;
3321     /* minor kludge to upcasify machine names */
3322     if (!strcmp(tbl, "machine"))
3323         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3324     namefield = vo->namefield;
3325     idfield = vo->idfield;
3326     id = -1;
3327     if (idfield == 0) {
3328         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3329           return(MR_EXISTS);
3330 ##      retrieve (id = any(tbl.namefield where tbl.namefield = name))
3331         if (ingres_errno) return(mr_errcode);
3332         if (id)
3333           return(vo->error);
3334         else
3335           return(MR_EXISTS);
3336     }
3337     status = name_to_id(name, tbl, &id);
3338     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3339       return(MR_EXISTS);
3340     else
3341       return(vo->error);
3342 }
3343
3344
3345 validate_type(argv, vo)
3346     char *argv[];
3347     register struct valobj *vo;
3348 {
3349     EXEC SQL BEGIN DECLARE SECTION;
3350     char *typename;
3351     char *value;
3352     int exist;
3353     EXEC SQL END DECLARE SECTION;
3354     register char *c;
3355
3356     typename = vo->table;
3357     c = value = argv[vo->index];
3358     while (*c)
3359       if (illegalchars[*c++])
3360         return(MR_BAD_CHAR);
3361
3362     /* uppercase type fields */
3363     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
3364
3365 ##  repeat retrieve (exist = any(alias.trans where alias.name = @typename and
3366 ##                                alias.type = "TYPE" and alias.trans = @value))
3367     if (ingres_errno) return(mr_errcode);
3368     return (exist ? MR_EXISTS : vo->error);
3369 }
3370
3371 /* validate member or type-specific data field */
3372
3373 validate_typedata(q, argv, vo)
3374     register struct query *q;
3375     register char *argv[];
3376     register struct valobj *vo;
3377 {
3378     EXEC SQL BEGIN DECLARE SECTION;
3379     char *name;
3380     char *field_type;
3381     char data_type[129];
3382     int id, rowcount;
3383     EXEC SQL END DECLARE SECTION;
3384
3385     int status;
3386     char *index();
3387     register char *c;
3388
3389     /* get named object */
3390     name = argv[vo->index];
3391
3392     /* get field type string (known to be at index-1) */
3393     field_type = argv[vo->index-1];
3394
3395     /* get corresponding data type associated with field type name */
3396 ##  repeat retrieve (data_type = alias.trans) 
3397 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
3398     if (ingres_errno) return(mr_errcode);
3399     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3400       return(MR_TYPE);
3401
3402     /* now retrieve the record id corresponding to the named object */
3403     if (index(data_type, ' '))
3404         *index(data_type, ' ') = 0;
3405     if (!strcmp(data_type, "user")) {
3406         /* USER */
3407         status = name_to_id(name, data_type, &id);
3408         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3409           return(MR_USER);
3410         if (status) return(status);
3411     } else if (!strcmp(data_type, "list")) {
3412         /* LIST */
3413         status = name_to_id(name, data_type, &id);
3414         if (status && status == MR_NOT_UNIQUE)
3415           return(MR_LIST);
3416         if (status == MR_NO_MATCH) {
3417             /* if idfield is non-zero, then if argv[0] matches the string
3418              * that we're trying to resolve, we should get the value of
3419              * values_tbl.[idfield] for the id.
3420              */
3421             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3422                 set_next_object_id(q->validate->object_id, q->rtable);
3423                 name = vo->idfield;
3424 ##              repeat retrieve (id = values_tbl.value) where values_tbl.#name = @name
3425                 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3426                   return(MR_LIST);
3427             } else
3428               return(MR_LIST);
3429         } else if (status) return(status);
3430     } else if (!strcmp(data_type, "machine")) {
3431         /* MACHINE */
3432         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3433         status = name_to_id(name, data_type, &id);
3434         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3435           return(MR_MACHINE);
3436         if (status) return(status);
3437     } else if (!strcmp(data_type, "string")) {
3438         /* STRING */
3439         status = name_to_id(name, data_type, &id);
3440         if (status && status == MR_NOT_UNIQUE)
3441           return(MR_STRING);
3442         if (status == MR_NO_MATCH) {
3443             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3444 ##          retrieve (id = values_tbl.value) where values_tbl.#name = "strings_id"
3445             id++;
3446 ##          replace values_tbl.(value = id) where values_tbl.#name = "strings_id"
3447 ##          append to strings (string_id = id, string = name)
3448         } else if (status) return(status);
3449     } else if (!strcmp(data_type, "none")) {
3450         id = 0;
3451     } else {
3452         return(MR_TYPE);
3453     }
3454
3455     /* now set value in argv */
3456     *(int *)argv[vo->index] = id;
3457     
3458     return (MR_EXISTS);
3459 }
3460
3461
3462 /* Lock the table named by the validation object */
3463
3464 lock_table(vo)
3465 struct valobj *vo;
3466 {
3467     EXEC SQL BEGIN DECLARE SECTION;
3468     char *tbl, *idfield;
3469     int rowcount;
3470     EXEC SQL END DECLARE SECTION;
3471
3472     tbl = vo->table;
3473     idfield = vo->idfield;
3474 ##  replace tbl (modtime = "now") where tbl.idfield = 0
3475     if (ingres_errno) return(mr_errcode);
3476     if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3477       return(vo->error);
3478     else
3479       return(MR_EXISTS);
3480 }
3481
3482
3483 /* Check the database at startup time.  For now this just resets the
3484  * inprogress flags that the DCM uses.
3485  */
3486
3487 sanity_check_database()
3488 {
3489 }
This page took 0.311072 seconds and 5 git commands to generate.