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