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