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