]> andersk Git - moira.git/blob - server/qsupport.pc
Don't always insert new rows with refcount = 1, it's possible for it to
[moira.git] / server / qsupport.pc
1 /* $Id$
2  *
3  * Special query routines
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include "mr_server.h"
12 #include "query.h"
13 #include "qrtn.h"
14
15 #include <ctype.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 EXEC SQL INCLUDE sqlca;
20
21 RCSID("$Header$");
22
23 extern char *whoami, *table_name[];
24 extern int dbms_errno, mr_errcode;
25
26 EXEC SQL BEGIN DECLARE SECTION;
27 extern char stmt_buf[];
28 EXEC SQL END DECLARE SECTION;
29
30 EXEC SQL WHENEVER SQLERROR DO dbmserr();
31
32 int get_ace_internal(char *atypex, int aid,
33                      int (*action)(int, char *[], void *), void *actarg);
34 int qualified_get(struct query *q, char *argv[],
35                   int (*action)(int, char *[], void *), void *actarg,
36                   char *start, char *range, char *field, char *flags[]);
37
38
39 /* set_pobox - this does all of the real work.
40  *       argv = user_id, type, box
41  * if type is POP, then box should be a machine, and its ID should be put in
42  * pop_id.  If type is IMAP, then box should be a filesys, and its ID should
43  * be put in pop_id.  If type is SMTP, then box should be a string and its
44  * ID should be put in box_id.  If type is NONE, then box doesn't matter.
45  */
46
47 int set_pobox(struct query *q, char **argv, client *cl)
48 {
49   EXEC SQL BEGIN DECLARE SECTION;
50   int user, id;
51   char *box, potype[USERS_POTYPE_SIZE];
52   EXEC SQL END DECLARE SECTION;
53   int status;
54
55   box = argv[2];
56   user = *(int *)argv[0];
57
58   EXEC SQL SELECT pop_id, potype INTO :id, :potype FROM users
59     WHERE users_id = :user;
60   if (dbms_errno)
61     return mr_errcode;
62   if (!strcmp(strtrim(potype), "POP") ||
63       (!strcmp(strtrim(potype), "SPLIT") && id))
64     set_pop_usage(id, -1);
65
66   if (!strcmp(argv[1], "POP"))
67     {
68       status = name_to_id(box, MACHINE_TABLE, &id);
69       if (status == MR_NO_MATCH)
70         return MR_MACHINE;
71       else if (status)
72         return status;
73       EXEC SQL UPDATE users SET potype = 'POP', pop_id = :id, imap_id = 0
74         WHERE users_id = :user;
75       set_pop_usage(id, 1);
76     }
77   else if (!strcmp(argv[1], "SMTP") || !strcmp(argv[1], "SPLIT"))
78     {
79       if (strchr(box, '/') || strchr(box, '|'))
80         return MR_BAD_CHAR;
81       status = name_to_id(box, STRINGS_TABLE, &id);
82       if (status == MR_NO_MATCH)
83         id = add_string(box);
84       else if (status)
85         return status;
86
87       /* If going from SMTP or NONE to SPLIT, make sure we have a valid
88        * POP or IMAP box.
89        */
90       if ((!strcmp(potype, "SMTP") || !strcmp(potype, "NONE")) && 
91            !strcmp(argv[1], "SPLIT"))
92         {
93           status = set_pobox_pop(q, argv, cl);
94           if (status)
95             return status;
96         }
97       strlcpy(potype, argv[1], sizeof(potype));
98       EXEC SQL UPDATE users SET potype = :potype, box_id = :id
99         WHERE users_id = :user;
100     }
101   else if (!strcmp(argv[1], "IMAP"))
102     {
103       EXEC SQL SELECT filsys_id INTO :id FROM filesys
104         WHERE label = :box AND type = 'IMAP';
105       if (sqlca.sqlcode)
106         return MR_FILESYS;
107       EXEC SQL UPDATE users SET potype = 'IMAP', imap_id = :id, pop_id = 0
108         WHERE users_id = :user;
109     }
110   else /* argv[1] == "NONE" */
111     {
112       EXEC SQL UPDATE users SET potype = 'NONE'
113         WHERE users_id = :user;
114     }
115
116   set_pobox_modtime(q, argv, cl);
117   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
118     WHERE table_name = 'users';
119   if (dbms_errno)
120     return mr_errcode;
121   return MR_SUCCESS;
122 }
123
124 /* set_pobox_pop: Revert to existing POP or IMAP pobox.
125  * Also take care of keeping track of the post office usage.
126  */
127 int set_pobox_pop(struct query *q, char **argv, client *cl)
128 {
129   EXEC SQL BEGIN DECLARE SECTION;
130   int id, pid, iid, mid;
131   char type[USERS_POTYPE_SIZE];
132   EXEC SQL END DECLARE SECTION;
133
134   id = *(int *)argv[0];
135   EXEC SQL SELECT potype, pop_id, imap_id INTO :type, :pid, :iid
136     FROM users WHERE users_id = :id;
137   if (sqlca.sqlerrd[2] == 0 || (pid == 0 && iid == 0))
138     return MR_MACHINE;
139
140   if (pid)
141     {
142       EXEC SQL SELECT mach_id INTO :mid FROM machine
143         WHERE mach_id = :pid;
144       if (sqlca.sqlerrd[2] == 0)
145         return MR_MACHINE;
146       EXEC SQL UPDATE users SET potype = 'POP' WHERE users_id = :id;
147       if (!strcmp(strtrim(type), "POP"))
148         set_pop_usage(mid, 1);
149     }
150   else
151     {
152       EXEC SQL SELECT filsys_id INTO :mid FROM filesys
153         WHERE filsys_id = :iid;
154       if (sqlca.sqlerrd[2] == 0)
155         return MR_MACHINE;
156       EXEC SQL UPDATE users SET potype = 'IMAP' WHERE users_id = :id;
157     }
158
159   set_pobox_modtime(q, argv, cl);
160   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
161     WHERE table_name = 'users';
162   if (dbms_errno)
163     return mr_errcode;
164   return MR_SUCCESS;
165 }
166
167
168 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
169  * how many different ancestors a member is allowed to have.
170  */
171
172 #define MAXLISTDEPTH    1024
173
174 int add_member_to_list(struct query *q, char **argv, client *cl)
175 {
176   EXEC SQL BEGIN DECLARE SECTION;
177   int id, lid, mid, tag, error, who, ref, rowcnt;
178   char *mtype, dtype[IMEMBERS_MEMBER_TYPE_SIZE], *entity;
179   EXEC SQL END DECLARE SECTION;
180   int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
181   int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
182   int status;
183   char *dtypes[MAXLISTDEPTH];
184   char *iargv[3], *buf;
185
186   lid = *(int *)argv[0];
187   mtype = argv[1];
188   mid = *(int *)argv[2];
189   tag = !strcmp(q->shortname, "atml") ? *(int *)argv[3] : 0;
190
191   if (acl_access_check(lid, cl))
192     return MR_PERM;
193
194   /* if the member is already a direct member of the list, punt */
195   EXEC SQL SELECT COUNT(list_id) INTO :rowcnt FROM imembers
196     WHERE list_id = :lid AND member_id = :mid
197     AND member_type = :mtype AND direct = 1;
198   if (rowcnt > 0)
199     return MR_EXISTS;
200   if (!strcasecmp(mtype, "STRING"))
201     {
202       buf = malloc(0);
203       status = id_to_name(mid, STRINGS_TABLE, &buf);
204       if (status)
205         return status;
206       if (strchr(buf, '/') || strchr(buf, '|'))
207         {
208           free(buf);
209           return MR_BAD_CHAR;
210         }
211       free(buf);
212     }
213
214   ancestors[0] = lid;
215   aref[0] = 1;
216   acount = 1;
217   EXEC SQL DECLARE csr103 CURSOR FOR
218     SELECT list_id, ref_count   FROM imembers
219     WHERE member_id = :lid AND member_type = 'LIST';
220   if (dbms_errno)
221     return mr_errcode;
222   EXEC SQL OPEN csr103;
223   if (dbms_errno)
224     return mr_errcode;
225   while (1)
226     {
227       EXEC SQL FETCH csr103 INTO :id, :ref;
228       if (sqlca.sqlcode)
229         break;
230       aref[acount] = ref;
231       ancestors[acount++] = id;
232       if (acount >= MAXLISTDEPTH)
233         break;
234     }
235   EXEC SQL CLOSE csr103;
236   if (dbms_errno)
237     return mr_errcode;
238   if (acount >= MAXLISTDEPTH)
239     return MR_INTERNAL;
240   descendants[0] = mid;
241   dtypes[0] = mtype;
242   dref[0] = 1;
243   dcount = 1;
244   error = 0;
245   if (!strcmp(mtype, "LIST"))
246     {
247       EXEC SQL DECLARE csr104 CURSOR FOR
248         SELECT member_id, member_type, ref_count
249         FROM imembers
250         WHERE list_id = :mid;
251       if (dbms_errno)
252         return mr_errcode;
253       EXEC SQL OPEN csr104;
254       if (dbms_errno)
255         return mr_errcode;
256       while (1)
257         {
258           EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
259           if (sqlca.sqlcode)
260             break;
261           switch (dtype[0])
262             {
263             case 'L':
264               dtypes[dcount] = "LIST";
265               break;
266             case 'U':
267               dtypes[dcount] = "USER";
268               break;
269             case 'S':
270               dtypes[dcount] = "STRING";
271               break;
272             case 'K':
273               dtypes[dcount] = "KERBEROS";
274               break;
275             default:
276               error++;
277               break;
278             }
279           dref[dcount] = ref;
280           descendants[dcount++] = id;
281           if (dcount >= MAXLISTDEPTH)
282             {
283               error++;
284               break;
285             }
286         }
287       EXEC SQL CLOSE csr104;
288       if (dbms_errno)
289         return mr_errcode;
290       if (error)
291         return MR_INTERNAL;
292     }
293   for (a = 0; a < acount; a++)
294     {
295       lid = ancestors[a];
296       for (d = 0; d < dcount; d++)
297         {
298           mid = descendants[d];
299           mtype = dtypes[d];
300           if (mid == lid && !strcmp(mtype, "LIST"))
301             return MR_LISTLOOP;
302           EXEC SQL SELECT COUNT(ref_count) INTO :rowcnt
303             FROM imembers
304             WHERE list_id = :lid AND member_id = :mid
305             AND member_type = :mtype;
306           ref = aref[a] * dref[d];
307           if (rowcnt > 0)
308             {
309               if (a == 0 && d == 0)
310                 {
311                   EXEC SQL UPDATE imembers
312                     SET ref_count = ref_count + :ref, direct = 1, tag = :tag
313                     WHERE list_id = :lid AND member_id = :mid
314                     AND member_type = :mtype;
315                 }
316               else
317                 {
318                   EXEC SQL UPDATE imembers
319                     SET ref_count = ref_count + :ref
320                     WHERE list_id = :lid AND member_id = :mid
321                     AND member_type = :mtype;
322                 }
323             }
324           else
325             {
326               incremental_clear_before();
327               if (a == 0 && d == 0)
328                 {
329                   EXEC SQL INSERT INTO imembers
330                     (list_id, member_type, member_id, tag, direct, ref_count)
331                     VALUES (:lid, :mtype, :mid, :tag, 1, :ref);
332                 }
333               else
334                 {
335                   EXEC SQL INSERT INTO imembers
336                     (list_id, member_type, member_id, tag, direct, ref_count)
337                     VALUES (:lid, :mtype, :mid, :tag, 0, :ref);
338                 }
339               iargv[0] = (char *)lid;
340               iargv[1] = mtype;
341               iargv[2] = (char *)mid;
342               incremental_after(IMEMBERS_TABLE, 0, iargv);
343             }
344         }
345     }
346   lid = *(int *)argv[0];
347   entity = cl->entity;
348   who = cl->client_id;
349   EXEC SQL UPDATE list
350     SET modtime = SYSDATE, modby = :who, modwith = :entity
351     WHERE list_id = :lid;
352   if (dbms_errno)
353     return mr_errcode;
354   return MR_SUCCESS;
355 }
356
357
358 /* Delete_member_from_list: do list flattening as we go!
359  */
360
361 int delete_member_from_list(struct query *q, char **argv, client *cl)
362 {
363   EXEC SQL BEGIN DECLARE SECTION;
364   int id, lid, mid, cnt, error, who, ref;
365   char *mtype, dtype[IMEMBERS_MEMBER_TYPE_SIZE], *entity;
366   EXEC SQL END DECLARE SECTION;
367   int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
368   int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
369   char *dtypes[MAXLISTDEPTH];
370   char *iargv[3];
371
372   lid = *(int *)argv[0];
373   mtype = argv[1];
374   mid = *(int *)argv[2];
375
376   if (acl_access_check(lid, cl))
377     return MR_PERM;
378
379   /* if the member is not a direct member of the list, punt */
380   EXEC SQL SELECT COUNT(list_id) INTO :cnt FROM imembers
381     WHERE list_id = :lid AND member_id = :mid
382     AND member_type = :mtype AND direct = 1;
383   if (dbms_errno)
384     return mr_errcode;
385   if (cnt == 0)
386     return MR_NO_MATCH;
387   ancestors[0] = lid;
388   aref[0] = 1;
389   acount = 1;
390   EXEC SQL DECLARE csr105 CURSOR FOR
391     SELECT list_id, ref_count FROM imembers
392     WHERE member_id = :lid AND member_type = 'LIST';
393   if (dbms_errno)
394     return mr_errcode;
395   EXEC SQL OPEN csr105;
396   if (dbms_errno)
397     return mr_errcode;
398   while (1)
399     {
400       EXEC SQL FETCH csr105 INTO :id, :ref;
401       if (sqlca.sqlcode)
402         break;
403       aref[acount] = ref;
404       ancestors[acount++] = id;
405       if (acount >= MAXLISTDEPTH)
406         break;
407     }
408   EXEC SQL CLOSE csr105;
409   if (dbms_errno)
410     return mr_errcode;
411   if (acount >= MAXLISTDEPTH)
412     return MR_INTERNAL;
413   descendants[0] = mid;
414   dtypes[0] = mtype;
415   dref[0] = 1;
416   dcount = 1;
417   error = 0;
418   if (!strcmp(mtype, "LIST"))
419     {
420       EXEC SQL DECLARE csr106 CURSOR FOR
421         SELECT member_id, member_type, ref_count FROM imembers
422         WHERE list_id = :mid;
423       if (dbms_errno)
424         return mr_errcode;
425       EXEC SQL OPEN csr106;
426       if (dbms_errno)
427         return mr_errcode;
428       while (1)
429         {
430           EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
431           if (sqlca.sqlcode)
432             break;
433           switch (dtype[0])
434             {
435             case 'L':
436               dtypes[dcount] = "LIST";
437               break;
438             case 'U':
439               dtypes[dcount] = "USER";
440               break;
441             case 'S':
442               dtypes[dcount] = "STRING";
443               break;
444             case 'K':
445               dtypes[dcount] = "KERBEROS";
446               break;
447             default:
448               error++;
449               break;
450             }
451           dref[dcount] = ref;
452           descendants[dcount++] = id;
453           if (dcount >= MAXLISTDEPTH)
454             break;
455         }
456       EXEC SQL CLOSE csr106;
457       if (dbms_errno)
458         return mr_errcode;
459       if (error)
460         return MR_INTERNAL;
461     }
462   for (a = 0; a < acount; a++)
463     {
464       lid = ancestors[a];
465       for (d = 0; d < dcount; d++)
466         {
467           mid = descendants[d];
468           mtype = dtypes[d];
469           if (mid == lid && !strcmp(mtype, "LIST"))
470             return MR_LISTLOOP;
471           EXEC SQL SELECT ref_count INTO :cnt FROM imembers
472             WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
473           ref = aref[a] * dref[d];
474           if (cnt <= ref)
475             {
476               iargv[0] = (char *)lid;
477               iargv[1] = mtype;
478               iargv[2] = (char *)mid;
479               incremental_before(IMEMBERS_TABLE, 0, iargv);
480               EXEC SQL DELETE FROM imembers
481                 WHERE list_id = :lid AND member_id = :mid
482                 AND member_type= :mtype;
483               incremental_clear_after();
484             }
485           else if (a == 0 && d == 0)
486             {
487               EXEC SQL UPDATE imembers
488                 SET ref_count = ref_count - :ref, direct = 0
489                 WHERE list_id = :lid AND member_id = :mid
490                 AND member_type = :mtype;
491             }
492           else
493             {
494               EXEC SQL UPDATE imembers
495                 SET ref_count = ref_count - :ref
496                 WHERE list_id = :lid AND member_id = :mid
497                 AND member_type = :mtype;
498             }
499         }
500     }
501   lid = *(int *)argv[0];
502   entity = cl->entity;
503   who = cl->client_id;
504   EXEC SQL UPDATE list SET modtime = SYSDATE, modby = :who, modwith = :entity
505     WHERE list_id = :lid;
506   if (dbms_errno)
507     return mr_errcode;
508   return MR_SUCCESS;
509 }
510
511 int tag_member_of_list(struct query *q, char **argv, client *cl)
512 {
513   EXEC SQL BEGIN DECLARE SECTION;
514   int lid, mid, cnt, tag;
515   char *mtype;
516   EXEC SQL END DECLARE SECTION;
517   char *iargv[3];
518
519   lid = *(int *)argv[0];
520   mtype = argv[1];
521   mid = *(int *)argv[2];
522   tag = *(int *)argv[3];
523
524   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
525     WHERE member_id = :mid AND member_type = :mtype AND
526     list_id = :lid;
527   if (dbms_errno)
528     return mr_errcode;
529   if (cnt == 0)
530     return MR_NO_MATCH;
531
532   incremental_clear_before();
533   EXEC SQL UPDATE imembers SET tag = :tag WHERE list_id = :lid 
534     AND member_type = :mtype AND member_id = :mid;
535   if (dbms_errno)
536     return mr_errcode;
537   
538   iargv[0] = (char *)lid;
539   iargv[1] = mtype;
540   iargv[2] = (char *)mid;
541   incremental_after(IMEMBERS_TABLE, 0, iargv);
542
543   return MR_SUCCESS;
544 }
545
546 /* Don't allow someone to add someone to a list which is the acl of a
547  * query unless they're on the list acl, even if they're on the amtl
548  * query acl! Also, don't allow someone proxying to add someone to a
549  * capacl.
550  */
551 int acl_access_check(int list_id, client *cl)
552 {
553   EXEC SQL BEGIN DECLARE SECTION;
554   int c1, c2, lid = list_id, acl_id, memacl_id;
555   char acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
556   EXEC SQL END DECLARE SECTION;
557
558   /* Check if the list is directly a capacl */
559   EXEC SQL SELECT COUNT(list_id) INTO :c1 FROM capacls WHERE list_id=:lid;
560
561   /* Check if the list is a member (direct or indirect) of a list that
562      is a capacl */
563   EXEC SQL SELECT COUNT(l1.list_id) INTO :c2 FROM list l1, list l2,
564     imembers im, capacls c WHERE c.list_id = l2.list_id AND
565     im.list_id = l2.list_id AND im.member_type = 'LIST' AND
566     im.member_id = l1.list_id AND l1.list_id = :lid;
567
568   if (c1 == 0 && c2 == 0)
569     return 0;
570
571   if (cl->proxy_id)
572     return 1;
573
574   EXEC SQL SELECT acl_type, acl_id, memacl_type, memacl_id
575     INTO :acl_type, :acl_id, :memacl_type, :memacl_id
576     FROM list WHERE list_id=:lid;
577
578   if (!find_member(acl_type, acl_id, cl))
579     {
580       if (!find_member(memacl_type, memacl_id, cl))
581         return 1;
582     }
583
584   return 0;
585 }
586
587
588 /* get_ace_use - given a type and a name, return a type and a name.
589  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
590  * and argv[1] will contain the ID of the entity in question.  The R*
591  * types mean to recursively look at every containing list, not just
592  * when the object in question is a direct member.  On return, the
593  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
594  */
595
596 int get_ace_use(struct query *q, char *argv[], client *cl,
597                 int (*action)(int, char *[], void *), void *actarg)
598 {
599   int found = 0;
600   EXEC SQL BEGIN DECLARE SECTION;
601   char *atype;
602   int aid, listid, id;
603   EXEC SQL END DECLARE SECTION;
604   struct save_queue *sq;
605
606   atype = argv[0];
607   aid = *(int *)argv[1];
608   if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
609       !strcmp(atype, "KERBEROS"))
610     return get_ace_internal(atype, aid, action, actarg);
611
612   sq = sq_create();
613   if (!strcmp(atype, "RLIST"))
614     {
615       sq_save_data(sq, (void *)aid);
616       /* get all the list_id's of containing lists */
617       EXEC SQL DECLARE csr107 CURSOR FOR
618         SELECT list_id FROM imembers
619         WHERE member_type = 'LIST' AND member_id = :aid;
620       if (dbms_errno)
621         return mr_errcode;
622       EXEC SQL OPEN csr107;
623       if (dbms_errno)
624         return mr_errcode;
625       while (1)
626         {
627           EXEC SQL FETCH csr107 INTO :listid;
628           if (sqlca.sqlcode)
629             break;
630           sq_save_unique_data(sq, (void *)listid);
631         }
632       EXEC SQL CLOSE csr107;
633       /* now process each one */
634       while (sq_get_data(sq, &id))
635         {
636           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
637             found++;
638         }
639     }
640
641   if (!strcmp(atype, "RUSER"))
642     {
643       EXEC SQL DECLARE csr108 CURSOR FOR
644         SELECT list_id FROM imembers
645         WHERE member_type = 'USER' AND member_id = :aid;
646       if (dbms_errno)
647         return mr_errcode;
648       EXEC SQL OPEN csr108;
649       if (dbms_errno)
650         return mr_errcode;
651       while (1)
652         {
653           EXEC SQL FETCH csr108 INTO :listid;
654           if (sqlca.sqlcode)
655             break;
656           sq_save_data(sq, (void *)listid);
657         }
658       EXEC SQL CLOSE csr108;
659       /* now process each one */
660       while (sq_get_data(sq, &id))
661         {
662           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
663             found++;
664         }
665       if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
666         found++;
667     }
668
669   if (!strcmp(atype, "RKERBEROS"))
670     {
671       EXEC SQL DECLARE csr109 CURSOR FOR
672         SELECT list_id FROM imembers
673         WHERE member_type = 'KERBEROS' AND member_id = :aid;
674       if (dbms_errno)
675         return mr_errcode;
676       EXEC SQL OPEN csr109;
677       if (dbms_errno)
678         return mr_errcode;
679       while (1)
680         {
681           EXEC SQL FETCH csr109 INTO :listid;
682           if (sqlca.sqlcode)
683             break;
684           sq_save_data(sq, (void *)listid);
685         }
686       EXEC SQL CLOSE csr109;
687       /* now process each one */
688       while (sq_get_data(sq, &id))
689         {
690           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
691             found++;
692         }
693       if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
694         found++;
695     }
696
697   sq_destroy(sq);
698   if (dbms_errno)
699     return mr_errcode;
700   if (!found)
701     return MR_NO_MATCH;
702   return MR_SUCCESS;
703 }
704
705
706 /* This looks up a single list or user for ace use.  atype must be "USER"
707  * or "LIST", and aid is the ID of the corresponding object.  This is used
708  * by get_ace_use above.
709  */
710
711 int get_ace_internal(char *atype, int aid,
712                      int (*action)(int, char *[], void *), void *actarg)
713 {
714   char *rargv[2];
715   int found = 0;
716   EXEC SQL BEGIN DECLARE SECTION;
717   char name[MAX_FIELD_WIDTH], *type = atype;
718   int id = aid;
719   EXEC SQL END DECLARE SECTION;
720
721   rargv[1] = name;
722   if (!strcmp(atype, "LIST"))
723     {
724       rargv[0] = "FILESYS";
725       EXEC SQL DECLARE csr110 CURSOR FOR
726         SELECT label FROM filesys
727         WHERE owners = :id;
728       if (dbms_errno)
729         return mr_errcode;
730       EXEC SQL OPEN csr110;
731       if (dbms_errno)
732         return mr_errcode;
733       while (1)
734         {
735           EXEC SQL FETCH csr110 INTO :name;
736           if (sqlca.sqlcode)
737             break;
738           (*action)(2, rargv, actarg);
739           found++;
740         }
741       EXEC SQL CLOSE csr110;
742
743       rargv[0] = "QUERY";
744       EXEC SQL DECLARE csr111 CURSOR FOR
745         SELECT capability FROM capacls
746         WHERE list_id = :id;
747       if (dbms_errno)
748         return mr_errcode;
749       EXEC SQL OPEN csr111;
750       if (dbms_errno)
751         return mr_errcode;
752       while (1)
753         {
754           EXEC SQL FETCH csr111 INTO :name;
755           if (sqlca.sqlcode)
756             break;
757           (*action)(2, rargv, actarg);
758           found++;
759         }
760       EXEC SQL CLOSE csr111;
761     }
762   else if (!strcmp(atype, "USER"))
763     {
764       rargv[0] = "FILESYS";
765       EXEC SQL DECLARE csr112 CURSOR FOR
766         SELECT label FROM filesys
767         WHERE owner = :id;
768       if (dbms_errno)
769         return mr_errcode;
770       EXEC SQL OPEN csr112;
771       if (dbms_errno)
772         return mr_errcode;
773       while (1)
774         {
775           EXEC SQL FETCH csr112 INTO :name;
776           if (sqlca.sqlcode)
777             break;
778           (*action)(2, rargv, actarg);
779           found++;
780         }
781       EXEC SQL CLOSE csr112;
782     }
783
784   rargv[0] = "LIST";
785   EXEC SQL DECLARE csr113 CURSOR FOR
786     SELECT name FROM list
787     WHERE (acl_type = :type AND acl_id = :id)
788     OR (memacl_type = :type AND memacl_id = :id);
789   if (dbms_errno)
790     return mr_errcode;
791   EXEC SQL OPEN csr113;
792   if (dbms_errno)
793     return mr_errcode;
794   while (1)
795     {
796       EXEC SQL FETCH csr113 INTO :name;
797       if (sqlca.sqlcode)
798         break;
799       (*action)(2, rargv, actarg);
800       found++;
801     }
802   EXEC SQL CLOSE csr113;
803
804   rargv[0] = "SERVICE";
805   EXEC SQL DECLARE csr114 CURSOR FOR
806     SELECT name FROM servers
807     WHERE acl_type = :type AND acl_id = :id;
808   if (dbms_errno)
809     return mr_errcode;
810   EXEC SQL OPEN csr114;
811   if (dbms_errno)
812     return mr_errcode;
813   while (1)
814     {
815       EXEC SQL FETCH csr114 INTO :name;
816       if (sqlca.sqlcode)
817         break;
818       (*action)(2, rargv, actarg);
819       found++;
820     }
821   EXEC SQL CLOSE csr114;
822
823   rargv[0] = "HOSTACCESS";
824   EXEC SQL DECLARE csr115 CURSOR FOR
825     SELECT name FROM machine m, hostaccess ha
826     WHERE m.mach_id = ha.mach_id AND ha.acl_type = :type
827     AND ha.acl_id = :id;
828   if (dbms_errno)
829     return mr_errcode;
830   EXEC SQL OPEN csr115;
831   if (dbms_errno)
832     return mr_errcode;
833   while (1)
834     {
835       EXEC SQL FETCH csr115 INTO :name;
836       if (sqlca.sqlcode)
837         break;
838       (*action)(2, rargv, actarg);
839       found++;
840     }
841   EXEC SQL CLOSE csr115;
842
843   rargv[0] = "MACHINE";
844   EXEC SQL DECLARE csr115a CURSOR FOR
845     SELECT name FROM machine m
846     WHERE m.owner_type = :type
847     AND m.owner_id = :id;
848   if (dbms_errno)
849     return mr_errcode;
850   EXEC SQL OPEN csr115a;
851   if (dbms_errno)
852     return mr_errcode;
853   while (1)
854     {
855       EXEC SQL FETCH csr115a INTO :name;
856       if (sqlca.sqlcode)
857         break;
858       (*action)(2, rargv, actarg);
859       found++;
860     }
861   EXEC SQL CLOSE csr115a;
862
863   rargv[0] = "ZEPHYR";
864   EXEC SQL DECLARE csr116 CURSOR FOR
865     SELECT class FROM zephyr z
866     WHERE z.xmt_type = :type AND z.xmt_id = :id
867     OR z.sub_type = :type AND z.sub_id = :id
868     OR z.iws_type = :type AND z.iws_id = :id
869     OR z.iui_type = :type AND z.iui_id = :id;
870   if (dbms_errno)
871     return mr_errcode;
872   EXEC SQL OPEN csr116;
873   if (dbms_errno)
874     return mr_errcode;
875   while (1)
876     {
877       EXEC SQL FETCH csr116 INTO :name;
878       if (sqlca.sqlcode)
879         break;
880       (*action)(2, rargv, actarg);
881       found++;
882     }
883   EXEC SQL CLOSE csr116;
884   
885   if (!found)
886     return MR_NO_MATCH;
887   return MR_SUCCESS;
888 }
889
890 /* ghbo_internal */
891 int ghbo_internal(char *atype, int aid,
892                   int (*action)(int, char *[], void *), void *actarg)
893 {
894   char *rargv[1];
895   int found = 0;
896   EXEC SQL BEGIN DECLARE SECTION;
897   char name[MACHINE_NAME_SIZE], *type = atype;
898   int id = aid;
899   EXEC SQL END DECLARE SECTION;
900
901   rargv[0] = name;
902   EXEC SQL DECLARE csr115b CURSOR FOR
903     SELECT name FROM machine m
904     WHERE m.owner_type = :type
905     AND m.owner_id = :id;
906   if (dbms_errno)
907     return mr_errcode;
908   EXEC SQL OPEN csr115b;
909   if (dbms_errno)
910     return mr_errcode;
911   while (1)
912     {
913       EXEC SQL FETCH csr115b INTO :name;
914       if (sqlca.sqlcode)
915         break;
916       (*action)(1, rargv, actarg);
917       found++;
918     }
919   EXEC SQL CLOSE csr115b;
920   
921   if (!found)
922     return MR_NO_MATCH;
923   return MR_SUCCESS;
924 }
925
926 /* get_host_by_owner - like gaus but limited to hosts */
927 int get_host_by_owner(struct query *q, char *argv[], client *cl,
928                       int (*action)(int, char *[], void *), void *actarg)
929 {
930   int found = 0;
931   EXEC SQL BEGIN DECLARE SECTION;
932   char *atype;
933   int aid, listid, id;
934   EXEC SQL END DECLARE SECTION;
935   struct save_queue *sq;
936
937   atype = argv[0];
938   aid = *(int *)argv[1];
939   if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
940       !strcmp(atype, "KERBEROS"))
941     return ghbo_internal(atype, aid, action, actarg);
942
943   sq = sq_create();
944   if (!strcmp(atype, "RLIST"))
945     {
946       sq_save_data(sq, (void *)aid);
947       /* get all the list_id's of containing lists */
948       EXEC SQL DECLARE csr107q CURSOR FOR
949         SELECT list_id FROM imembers
950         WHERE member_type = 'LIST' AND member_id = :aid;
951       if (dbms_errno)
952         return mr_errcode;
953       EXEC SQL OPEN csr107q;
954       if (dbms_errno)
955         return mr_errcode;
956       while (1)
957         {
958           EXEC SQL FETCH csr107q INTO :listid;
959           if (sqlca.sqlcode)
960             break;
961           sq_save_unique_data(sq, (void *)listid);
962         }
963       EXEC SQL CLOSE csr107q;
964       /* now process each one */
965       while (sq_get_data(sq, &id))
966         {
967           if (ghbo_internal("LIST", id, action, actarg) == MR_SUCCESS)
968             found++;
969         }
970     }
971
972   if (!strcmp(atype, "RUSER"))
973     {
974       EXEC SQL DECLARE csr108q CURSOR FOR
975         SELECT list_id FROM imembers
976         WHERE member_type = 'USER' AND member_id = :aid;
977       if (dbms_errno)
978         return mr_errcode;
979       EXEC SQL OPEN csr108q;
980       if (dbms_errno)
981         return mr_errcode;
982       while (1)
983         {
984           EXEC SQL FETCH csr108q INTO :listid;
985           if (sqlca.sqlcode)
986             break;
987           sq_save_data(sq, (void *)listid);
988         }
989       EXEC SQL CLOSE csr108q;
990       /* now process each one */
991       while (sq_get_data(sq, &id))
992         {
993           if (ghbo_internal("LIST", id, action, actarg) == MR_SUCCESS)
994             found++;
995         }
996       if (ghbo_internal("USER", aid, action, actarg) == MR_SUCCESS)
997         found++;
998     }
999
1000   if (!strcmp(atype, "RKERBEROS"))
1001     {
1002       EXEC SQL DECLARE csr109q CURSOR FOR
1003         SELECT list_id FROM imembers
1004         WHERE member_type = 'KERBEROS' AND member_id = :aid;
1005       if (dbms_errno)
1006         return mr_errcode;
1007       EXEC SQL OPEN csr109q;
1008       if (dbms_errno)
1009         return mr_errcode;
1010       while (1)
1011         {
1012           EXEC SQL FETCH csr109q INTO :listid;
1013           if (sqlca.sqlcode)
1014             break;
1015           sq_save_data(sq, (void *)listid);
1016         }
1017       EXEC SQL CLOSE csr109q;
1018       /* now process each one */
1019       while (sq_get_data(sq, &id))
1020         {
1021           if (ghbo_internal("LIST", id, action, actarg) == MR_SUCCESS)
1022             found++;
1023         }
1024       if (ghbo_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
1025         found++;
1026     }
1027
1028   sq_destroy(sq);
1029   if (dbms_errno)
1030     return mr_errcode;
1031   if (!found)
1032     return MR_NO_MATCH;
1033   return MR_SUCCESS;
1034 }
1035
1036 /* get_lists_of_member - given a type and a name, return the name and flags
1037  * of all of the lists of the given member.  The member_type is one of
1038  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1039  * and argv[1] will contain the ID of the entity in question.  The R*
1040  * types mean to recursively look at every containing list, not just
1041  * when the object in question is a direct member.
1042  */
1043
1044 int get_lists_of_member(struct query *q, char *argv[], client *cl,
1045                         int (*action)(int, char *[], void *), void *actarg)
1046 {
1047   int found = 0, direct = 1;
1048   char *rargv[6];
1049   EXEC SQL BEGIN DECLARE SECTION;
1050   char *atype;
1051   int aid;
1052   char name[LIST_NAME_SIZE];
1053   char active[5], public[5], hidden[5], maillist[5], grouplist[5];
1054   EXEC SQL END DECLARE SECTION;
1055
1056   atype = argv[0];
1057   aid = *(int *)argv[1];
1058   if (!strcmp(atype, "RLIST"))
1059     {
1060       atype = "LIST";
1061       direct = 0;
1062     }
1063   if (!strcmp(atype, "RUSER"))
1064     {
1065       atype = "USER";
1066       direct = 0;
1067     }
1068   if (!strcmp(atype, "RSTRING"))
1069     {
1070       atype = "STRING";
1071       direct = 0;
1072     }
1073   if (!strcmp(atype, "RKERBEROS"))
1074     {
1075       atype = "KERBEROS";
1076       direct = 0;
1077     }
1078
1079   rargv[0] = name;
1080   rargv[1] = active;
1081   rargv[2] = public;
1082   rargv[3] = hidden;
1083   rargv[4] = maillist;
1084   rargv[5] = grouplist;
1085   if (direct)
1086     {
1087       EXEC SQL DECLARE csr117a CURSOR FOR
1088         SELECT l.name, l.active, l.publicflg, l.hidden, l.maillist, l.grouplist
1089         FROM list l, imembers im
1090         WHERE l.list_id = im.list_id AND im.direct = 1
1091         AND im.member_type = :atype AND im.member_id = :aid;
1092       if (dbms_errno)
1093         return mr_errcode;
1094       EXEC SQL OPEN csr117a;
1095       if (dbms_errno)
1096         return mr_errcode;
1097       while (1)
1098         {
1099           EXEC SQL FETCH csr117a
1100             INTO :name, :active, :public, :hidden, :maillist, :grouplist;
1101           if (sqlca.sqlcode)
1102             break;
1103           (*action)(6, rargv, actarg);
1104           found++;
1105         }
1106       EXEC SQL CLOSE csr117a;
1107     }
1108   else
1109     {
1110       EXEC SQL DECLARE csr117b CURSOR FOR
1111         SELECT l.name, l.active, l.publicflg, l.hidden, l.maillist, l.grouplist
1112         FROM list l, imembers im
1113         WHERE l.list_id = im.list_id
1114         AND im.member_type = :atype AND im.member_id = :aid;
1115       if (dbms_errno)
1116         return mr_errcode;
1117       EXEC SQL OPEN csr117b;
1118       if (dbms_errno)
1119         return mr_errcode;
1120       while (1)
1121         {
1122           EXEC SQL FETCH csr117b
1123             INTO :name, :active, :public, :hidden, :maillist, :grouplist;
1124           if (sqlca.sqlcode)
1125             break;
1126           (*action)(6, rargv, actarg);
1127           found++;
1128         }
1129       EXEC SQL CLOSE csr117b;
1130     }
1131
1132   if (dbms_errno)
1133     return mr_errcode;
1134   if (!found)
1135     return MR_NO_MATCH;
1136   return MR_SUCCESS;
1137 }
1138
1139
1140 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1141  * the five flags associated with each list.  It will return the name of
1142  * each list that meets the quailifications.  It does this by building a
1143  * where clause based on the arguments, then doing a retrieve.
1144  */
1145
1146 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
1147
1148 int qualified_get_lists(struct query *q, char *argv[], client *cl,
1149                         int (*action)(int, char *[], void *), void *actarg)
1150 {
1151   return qualified_get(q, argv, action, actarg, "l.list_id != 0",
1152                        "l", "name", lflags);
1153 }
1154
1155
1156 int get_members_of_list(struct query *q, char *argv[], client *cl,
1157                         int (*action)(int, char *[], void *), void *actarg)
1158 {
1159   EXEC SQL BEGIN DECLARE SECTION;
1160   int list_id, direct;
1161   char member_name[MAX_FIELD_WIDTH], tag[STRINGS_STRING_SIZE];
1162   EXEC SQL END DECLARE SECTION;
1163   char *targv[3];
1164   int targc;
1165
1166   /* For gmol or gtml, only get direct members. For geml, get all. */
1167   if (!strcmp(q->shortname, "geml"))
1168     direct = -1;
1169   else
1170     direct = 0;
1171
1172   /* For gmol or geml, only return type and name. For gtml, return tag too. */
1173   if (!strcmp(q->shortname, "gtml"))
1174     targc = 3;
1175   else
1176     targc = 2;
1177
1178   list_id = *(int *)argv[0];
1179
1180   targv[1] = member_name;
1181   targv[2] = tag;
1182
1183   targv[0] = "USER";
1184   EXEC SQL DECLARE csr119 CURSOR FOR
1185     SELECT u.login, s.string FROM users u, imembers im, strings s
1186     WHERE im.list_id = :list_id AND im.member_type = 'USER'
1187     AND im.member_id = u.users_id AND im.direct > :direct
1188     AND s.string_id = im.tag ORDER BY 1;
1189   if (dbms_errno)
1190     return mr_errcode;
1191   EXEC SQL OPEN csr119;
1192   if (dbms_errno)
1193     return mr_errcode;
1194   while (1)
1195     {
1196       EXEC SQL FETCH csr119 INTO :member_name, :tag;
1197       if (sqlca.sqlcode)
1198         break;
1199       (*action)(targc, targv, actarg);
1200     }
1201   EXEC SQL CLOSE csr119;
1202   if (dbms_errno)
1203     return mr_errcode;
1204
1205   targv[0] = "LIST";
1206   EXEC SQL DECLARE csr120 CURSOR FOR
1207     SELECT l.name, s.string FROM list l, imembers im, strings s
1208     WHERE im.list_id = :list_id AND im.member_type = 'LIST'
1209     AND im.member_id = l.list_id AND im.direct > :direct
1210     AND s.string_id = im.tag ORDER BY 1;
1211   if (dbms_errno)
1212     return mr_errcode;
1213   EXEC SQL OPEN csr120;
1214   if (dbms_errno)
1215     return mr_errcode;
1216   while (1)
1217     {
1218       EXEC SQL FETCH csr120 INTO :member_name, :tag;
1219       if (sqlca.sqlcode)
1220         break;
1221       (*action)(targc, targv, actarg);
1222     }
1223   EXEC SQL CLOSE csr120;
1224   if (dbms_errno)
1225     return mr_errcode;
1226
1227   targv[0] = "STRING";
1228   EXEC SQL DECLARE csr121 CURSOR FOR
1229     SELECT str.string, s.string FROM strings str, imembers im, strings s
1230     WHERE im.list_id = :list_id AND im.member_type = 'STRING'
1231     AND im.member_id = str.string_id AND im.direct > :direct
1232     AND s.string_id = im.tag ORDER BY 1;
1233   if (dbms_errno)
1234     return mr_errcode;
1235   EXEC SQL OPEN csr121;
1236   if (dbms_errno)
1237     return mr_errcode;
1238   while (1)
1239     {
1240       EXEC SQL FETCH csr121 INTO :member_name, :tag;
1241       if (sqlca.sqlcode)
1242         break;
1243       (*action)(targc, targv, actarg);
1244     }
1245   EXEC SQL CLOSE csr121;
1246   if (dbms_errno)
1247     return mr_errcode;
1248
1249   targv[0] = "KERBEROS";
1250   EXEC SQL DECLARE csr122 CURSOR FOR
1251     SELECT str.string, s.string FROM strings str, imembers im, strings s
1252     WHERE im.list_id = :list_id AND im.member_type = 'KERBEROS'
1253     AND im.member_id = str.string_id AND im.direct > :direct
1254     AND s.string_id = im.tag ORDER BY 1;
1255   if (dbms_errno)
1256     return mr_errcode;
1257   EXEC SQL OPEN csr122;
1258   if (dbms_errno)
1259     return mr_errcode;
1260   while (1)
1261     {
1262       EXEC SQL FETCH csr122 INTO :member_name, :tag;
1263       if (sqlca.sqlcode)
1264         break;
1265       (*action)(targc, targv, actarg);
1266     }
1267   EXEC SQL CLOSE csr122;
1268   if (dbms_errno)
1269     return mr_errcode;
1270
1271   return MR_SUCCESS;
1272 }
1273
1274
1275 /* count_members_of_list: this is a simple query, but it cannot be done
1276  * through the dispatch table.
1277  */
1278
1279 int count_members_of_list(struct query *q, char *argv[], client *cl,
1280                           int (*action)(int, char *[], void *), void *actarg)
1281 {
1282   EXEC SQL BEGIN DECLARE SECTION;
1283   int  list, ct = 0;
1284   EXEC SQL END DECLARE SECTION;
1285   char *rargv[1], countbuf[5];
1286
1287   list = *(int *)argv[0];
1288   rargv[0] = countbuf;
1289   EXEC SQL SELECT count (*) INTO :ct FROM imembers
1290     WHERE list_id = :list AND direct = 1;
1291   if (dbms_errno)
1292     return mr_errcode;
1293   sprintf(countbuf, "%d", ct);
1294   (*action)(1, rargv, actarg);
1295   return MR_SUCCESS;
1296 }
1297
1298
1299 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
1300  * the three flags associated with each service.  It will return the name of
1301  * each service that meets the quailifications.  It does this by building a
1302  * where clause based on the arguments, then doing a retrieve.
1303  */
1304
1305 static char *sflags[3] = { "enable", "inprogress", "harderror" };
1306
1307 int qualified_get_server(struct query *q, char *argv[], client *cl,
1308                          int (*action)(int, char *[], void *), void *actarg)
1309 {
1310   return qualified_get(q, argv, action, actarg, "s.name is not null",
1311                        "s", "name", sflags);
1312   /* of course, name will never be null, but we need something there
1313      to make qualified_get happy */
1314 }
1315
1316
1317 /* generic qualified get routine, used by qualified_get_lists,
1318  * qualified_get_server, and qualified_get_serverhost.
1319  *   Args:
1320  *      start - a simple where clause, must not be empty
1321  *      range - the name of the range variable
1322  *      field - the field to return
1323  *      flags - an array of strings, names of the flag variables
1324  */
1325
1326 int qualified_get(struct query *q, char *argv[],
1327                   int (*action)(int, char *[], void *), void *actarg,
1328                   char *start, char *range, char *field, char *flags[])
1329 {
1330   char qual[256];
1331   int i;
1332   char buf[32];
1333
1334   strcpy(qual, start);
1335   for (i = 0; i < q->argc; i++)
1336     {
1337       if (!strcmp(argv[i], "TRUE"))
1338         {
1339           sprintf(buf, " AND %s.%s != 0", range, flags[i]);
1340           strcat(qual, buf);
1341         }
1342       else if (!strcmp(argv[i], "FALSE"))
1343         {
1344           sprintf(buf, " AND %s.%s = 0", range, flags[i]);
1345           strcat(qual, buf);
1346         }
1347     }
1348
1349   sprintf(stmt_buf, "SELECT %s.%s FROM %s %s WHERE %s", range, field,
1350           table_name[q->rtable], range, qual);
1351   return do_for_all_rows(stmt_buf, 1, action, actarg);
1352 }
1353
1354
1355 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
1356  * the five flags associated with each serverhost.  It will return the name of
1357  * each service and host that meets the quailifications.  It does this by
1358  * building a where clause based on the arguments, then doing a retrieve.
1359  */
1360
1361 static char *shflags[6] = { "service", "enable", "override", "success",
1362                             "inprogress", "hosterror" };
1363
1364 int qualified_get_serverhost(struct query *q, char *argv[], client *cl,
1365                              int (*action)(int, char *[], void *),
1366                              void *actarg)
1367 {
1368   char qual[256], buf[32];
1369   int i;
1370
1371   sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = UPPER('%s')",
1372           argv[0]);
1373   for (i = 1; i < q->argc; i++)
1374     {
1375       if (!strcmp(argv[i], "TRUE"))
1376         {
1377           sprintf(buf, " AND sh.%s != 0", shflags[i]);
1378           strcat(qual, buf);
1379         }
1380       else if (!strcmp(argv[i], "FALSE"))
1381         {
1382           sprintf(buf, " AND sh.%s = 0", shflags[i]);
1383           strcat(qual, buf);
1384         }
1385     }
1386
1387   sprintf(stmt_buf, "SELECT sh.service, m.name FROM serverhosts sh, "
1388           "machine m WHERE %s", qual);
1389   return do_for_all_rows(stmt_buf, 2, action, actarg);
1390 }
1391
1392
1393 /* register_user - change user's login name and allocate a pobox, group,
1394  * filesystem, and quota for them.  The user's status must start out as 0,
1395  * and is left as 2.  Arguments are: user's UID, new login name, and
1396  * pobox type ("POP" = POP, "IMAP" or numeric = IMAP)
1397  */
1398
1399 int register_user(struct query *q, char **argv, client *cl)
1400 {
1401   EXEC SQL BEGIN DECLARE SECTION;
1402   char *login, *entity;
1403   char directory[FILESYS_NAME_SIZE], machname[MACHINE_NAME_SIZE];
1404   char dir[NFSPHYS_DIR_SIZE], *potype;
1405   int who, rowcount, mid, uid, users_id;
1406   int ostatus, nstatus, fsidval, popid;
1407   int npid, tmp;
1408   int po_exists = 0;
1409   static int m_id, def_quota, def_imap_quota, list_id;
1410   EXEC SQL END DECLARE SECTION;
1411   char buffer[256], *aargv[3];
1412
1413   if (!m_id)
1414     {
1415       EXEC SQL SELECT list_id INTO :list_id FROM list
1416         WHERE name = 'wheel';
1417
1418       EXEC SQL SELECT mach_id INTO :m_id FROM machine
1419         WHERE name = 'ATHENA.MIT.EDU';
1420
1421       EXEC SQL SELECT value INTO :def_quota FROM numvalues
1422         WHERE name = 'def_quota';
1423       if (sqlca.sqlerrd[2] != 1)
1424         return MR_NO_QUOTA;
1425
1426       EXEC SQL SELECT value INTO :def_imap_quota FROM numvalues
1427         WHERE name = 'def_imap_quota';
1428       if (sqlca.sqlerrd[2] != 1)
1429         return MR_NO_QUOTA;
1430     }
1431
1432   entity = cl->entity;
1433   who = cl->client_id;
1434
1435   uid = atoi(argv[0]);
1436   login = argv[1];
1437   potype = argv[2];
1438
1439   /* find user */
1440   EXEC SQL SELECT users_id, status INTO :users_id, :ostatus
1441     FROM users
1442     WHERE unix_uid = :uid AND (status = 0 OR status = 5 OR status = 6);
1443
1444   if (sqlca.sqlerrd[2] == 0)
1445     return MR_NO_MATCH;
1446   if (sqlca.sqlerrd[2] > 1)
1447     return MR_NOT_UNIQUE;
1448
1449   /* check new login name */
1450   EXEC SQL SELECT COUNT(login) INTO :rowcount FROM users
1451     WHERE login = :login AND users_id != :users_id;
1452   if (dbms_errno)
1453     return mr_errcode;
1454   if (rowcount > 0)
1455     return MR_IN_USE;
1456   EXEC SQL SELECT COUNT(name) INTO :rowcount FROM list
1457     WHERE LOWER(name) = :login;
1458   if (dbms_errno)
1459     return mr_errcode;
1460   if (rowcount > 0)
1461     return MR_IN_USE;
1462   EXEC SQL SELECT COUNT(label) INTO :rowcount FROM filesys
1463     WHERE label = :login;
1464   if (dbms_errno)
1465     return mr_errcode;
1466   if (rowcount > 0)
1467     return MR_IN_USE;
1468   EXEC SQL SELECT COUNT(label) INTO :rowcount  
1469     FROM filesys WHERE label = :login || '.po';
1470   if (dbms_errno)
1471     return mr_errcode;
1472   if (rowcount > 0)
1473     {
1474       EXEC SQL SELECT owner INTO :tmp FROM filesys 
1475         WHERE label = :login || '.po';
1476       if (dbms_errno)
1477         return mr_errcode;
1478       if ((ostatus == 0) || (tmp != users_id))
1479         return MR_IN_USE;
1480       EXEC SQL SELECT count(potype) INTO :rowcount FROM users WHERE
1481         login = :login AND potype = 'IMAP';
1482       if (dbms_errno)
1483         return mr_errcode;
1484       if (rowcount > 0)
1485         po_exists = 1;
1486     }
1487   EXEC SQL SELECT COUNT(name) INTO :rowcount FROM alias
1488     WHERE ( name = :login OR name = :login || '.po' )
1489     AND type = 'FILESYS';
1490   if (dbms_errno)
1491     return mr_errcode;
1492   if (rowcount > 0)
1493     return MR_IN_USE;
1494   com_err(whoami, 0, "login name OK");
1495
1496   EXEC SQL SELECT COUNT(potype) INTO :rowcount FROM users WHERE
1497     login = :login AND potype = 'POP';
1498   if (dbms_errno)
1499     return mr_errcode;
1500   if (rowcount > 0)
1501     po_exists = 1;
1502
1503   /* choose type and location for pobox */
1504   if (!po_exists)
1505     {
1506       if (!strcmp(potype, "POP"))
1507         {
1508
1509           EXEC SQL DECLARE csr130 CURSOR FOR
1510             SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
1511             WHERE sh.service = 'POP' AND sh.mach_id = m.mach_id
1512             AND sh.value2 - sh.value1 =
1513             (SELECT MAX(value2 - value1) FROM serverhosts WHERE service = 'POP');
1514           if (dbms_errno)
1515             return mr_errcode;
1516           EXEC SQL OPEN csr130;
1517           if (dbms_errno)
1518             return mr_errcode;
1519           EXEC SQL FETCH csr130 INTO :popid, :machname;
1520           if (sqlca.sqlerrd[2] == 0)
1521             {
1522               EXEC SQL CLOSE csr130;
1523               if (dbms_errno)
1524                 return mr_errcode;
1525               return MR_NO_POBOX;
1526             }
1527           else
1528             {
1529               EXEC SQL CLOSE csr130;
1530               if (dbms_errno)
1531                 return mr_errcode;
1532             }
1533       
1534           EXEC SQL UPDATE users SET potype = 'POP', pop_id = :popid
1535             WHERE users_id = :users_id;
1536           com_err(whoami, 0, "pobox set to POP:%s", strtrim(machname));
1537         }         
1538       else
1539         {
1540       /* Select all IMAP nfsphys entries in order of increasing
1541        * (allocated - partsize).  The partitions will almost always be 
1542        * overallocated, but we choose the one that is the least 
1543        * overallocated.
1544        */
1545           potype = "IMAP";
1546           
1547           EXEC SQL DECLARE csr_rusr_imap CURSOR FOR
1548             SELECT np.allocated - np.partsize, np.nfsphys_id, np.mach_id,
1549             np.dir, m.name FROM serverhosts sh, nfsphys np, machine m
1550             WHERE sh.service = 'POSTOFFICE' AND sh.mach_id = np.mach_id
1551             AND m.mach_id = np.mach_id
1552             ORDER BY 1;
1553           if (dbms_errno)
1554             return mr_errcode;
1555           EXEC SQL OPEN csr_rusr_imap;
1556           if (dbms_errno)
1557             return mr_errcode;
1558           EXEC SQL FETCH csr_rusr_imap INTO :tmp, :npid, :mid, :dir, :machname;
1559           if (sqlca.sqlerrd[2] == 0)
1560             {
1561               EXEC SQL CLOSE csr_rusr_imap;
1562               if (dbms_errno)
1563                 return mr_errcode;
1564               return MR_NO_POBOX;
1565             }
1566           else
1567             {
1568               EXEC SQL CLOSE csr_rusr_imap;
1569               if (dbms_errno)
1570                 return mr_errcode;
1571             }
1572
1573           /* create filesystem */
1574           if (set_next_object_id("filsys_id", FILESYS_TABLE, 0))
1575             return MR_NO_ID;
1576           incremental_clear_before();
1577
1578           EXEC SQL SELECT value INTO :popid FROM numvalues
1579             WHERE numvalues.name = 'filsys_id';
1580           EXEC SQL INSERT INTO filesys
1581             (filsys_id, phys_id, label, type, mach_id, name,
1582              mount, rwaccess, comments, owner, owners, createflg,
1583              lockertype, modtime, modby, modwith)
1584             VALUES
1585             (:popid, :npid, :login || '.po', 'IMAP', :mid, :dir,
1586              CHR(0), 'w', 'IMAP box', :users_id, :list_id, 1,
1587              'USER', SYSDATE, :who, :entity);
1588
1589           if (dbms_errno)
1590             return mr_errcode;
1591           if (sqlca.sqlerrd[2] != 1)
1592             return MR_INTERNAL;
1593           sprintf(buffer, "fs.filsys_id = %d", popid);
1594           incremental_after(FILESYS_TABLE, buffer, 0);
1595
1596           /* set quota */
1597           incremental_clear_before();
1598           EXEC SQL INSERT INTO quota
1599             (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
1600             VALUES (:users_id, :popid, 'USER', :def_imap_quota, :npid,
1601                     SYSDATE, :who, :entity);
1602           if (dbms_errno)
1603             return mr_errcode;
1604           if (sqlca.sqlerrd[2] != 1)
1605             return MR_INTERNAL;
1606           aargv[0] = login;
1607           aargv[1] = "USER";
1608           aargv[2] = login;
1609           sprintf(buffer, "q.entity_id = %d and q.filsys_id = %d and "
1610                   "q.type = 'USER'", users_id, popid);
1611           incremental_after(QUOTA_TABLE, buffer, aargv);
1612           if (dbms_errno)
1613             return mr_errcode;
1614
1615           EXEC SQL UPDATE nfsphys SET allocated = allocated + :def_imap_quota
1616             WHERE nfsphys_id = :npid;
1617
1618           EXEC SQL UPDATE users SET potype = 'IMAP', imap_id = :popid
1619             WHERE users_id = :users_id;
1620           com_err(whoami, 0, "pobox set to IMAP:%s:%s", strtrim(machname),
1621                   strtrim(dir));
1622         }
1623     }
1624   
1625   /* change login name, set pobox */
1626   sprintf(buffer, "u.users_id = %d", users_id);
1627   incremental_before(USERS_TABLE, buffer, 0);
1628   nstatus = 2;
1629   if (ostatus == 5 || ostatus == 6)
1630     nstatus = 1;
1631   EXEC SQL UPDATE users SET login = :login, status = :nstatus,
1632     modtime = SYSDATE, modby = :who, modwith = :entity,
1633     pmodtime = SYSDATE, pmodby = :who, pmodwith = :entity
1634     WHERE users_id = :users_id;
1635
1636   if (dbms_errno)
1637     return mr_errcode;
1638   if (sqlca.sqlerrd[2] != 1)
1639     return MR_INTERNAL;
1640   
1641   /* Only update usage count if we created a POP pobox. */
1642   if (!strcmp(potype, "POP") && !po_exists)
1643     set_pop_usage(mid, 1);
1644   
1645   com_err(whoami, 0, "set login name to %s", login);
1646   incremental_after(USERS_TABLE, buffer, 0);
1647
1648   /* We've just changed the login name in the DB; recache it in case
1649      the wrong thing got into the cache earlier. */
1650   cache_entry(login, USERS_TABLE, users_id);
1651
1652   /* create filesystem */
1653   if (set_next_object_id("filsys_id", FILESYS_TABLE, 0))
1654     return MR_NO_ID;
1655   incremental_clear_before();
1656   if (islower(login[0]) && islower(login[1]))
1657     {
1658       sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
1659               login[0], login[1], login);
1660     }
1661   else
1662     sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
1663
1664   EXEC SQL SELECT value INTO :fsidval FROM numvalues
1665     WHERE numvalues.name = 'filsys_id';
1666   EXEC SQL INSERT INTO filesys
1667     (filsys_id, phys_id, label, type, mach_id, name,
1668      mount, rwaccess, comments, owner, owners, createflg,
1669      lockertype, modtime, modby, modwith)
1670     VALUES
1671     (:fsidval, 0, :login, 'AFS', :m_id, :directory,
1672      '/mit/' || :login, 'w', 'User Locker', :users_id, :list_id, 1,
1673      'HOMEDIR', SYSDATE, :who, :entity);
1674
1675   if (dbms_errno)
1676     return mr_errcode;
1677   if (sqlca.sqlerrd[2] != 1)
1678     return MR_INTERNAL;
1679   sprintf(buffer, "fs.filsys_id = %d", fsidval);
1680   incremental_after(FILESYS_TABLE, buffer, 0);
1681
1682   /* set quota */
1683   incremental_clear_before();
1684   EXEC SQL INSERT INTO quota
1685     (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
1686     VALUES (0, :fsidval, 'ANY', :def_quota, 0, SYSDATE, :who, :entity);
1687   if (dbms_errno)
1688     return mr_errcode;
1689   if (sqlca.sqlerrd[2] != 1)
1690     return MR_INTERNAL;
1691   aargv[0] = login;
1692   aargv[1] = "ANY";
1693   aargv[2] = login;
1694   sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'",
1695           fsidval);
1696   incremental_after(QUOTA_TABLE, buffer, aargv);
1697   com_err(whoami, 0, "quota of %d assigned", def_quota);
1698   if (dbms_errno)
1699     return mr_errcode;
1700
1701   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
1702     WHERE table_name = 'users';
1703   EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = SYSDATE
1704     WHERE table_name = 'filesys' OR table_name = 'quota';
1705   if (dbms_errno)
1706     return mr_errcode;
1707   return MR_SUCCESS;
1708 }
1709
1710 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
1711  **
1712  ** Inputs:
1713  **   id of machine
1714  **   delta (will be +/- 1)
1715  **
1716  ** Description:
1717  **   - incr/decr value field in serverhosts table for pop/mach_id
1718  **
1719  **/
1720
1721 int set_pop_usage(id, cnt)
1722     int id, cnt;
1723 {
1724   EXEC SQL BEGIN DECLARE SECTION;
1725   int iid = id, icnt = cnt;
1726   EXEC SQL END DECLARE SECTION;
1727
1728   EXEC SQL UPDATE serverhosts SET value1 = value1 + :icnt
1729     WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :iid;
1730
1731   if (dbms_errno)
1732     return mr_errcode;
1733   return MR_SUCCESS;
1734 }
1735
1736
1737 int do_user_reservation(struct query *q, char *argv[], client *cl)
1738 {
1739   EXEC SQL BEGIN DECLARE SECTION;
1740   char resv[USERS_RESERVATIONS_SIZE];
1741   char *trans, name[ALIAS_NAME_SIZE];
1742   int uid;
1743   EXEC SQL END DECLARE SECTION;
1744
1745   uid = *(int *)argv[0];
1746   trans = argv[1];
1747
1748   EXEC SQL SELECT UPPER(name) INTO :name FROM alias
1749     WHERE type = 'RESERVE' AND LOWER(trans) = LOWER(:trans);
1750   if (dbms_errno)
1751     return mr_errcode;
1752   if (sqlca.sqlerrd[2] != 1)
1753     return MR_STRING;
1754   name[1] = '\0';
1755
1756   EXEC SQL SELECT reservations INTO :resv FROM users
1757     WHERE users_id = :uid;
1758   if (dbms_errno)
1759     return mr_errcode;
1760   strtrim(resv);
1761
1762   if (!strcmp(q->shortname, "aurv"))
1763     {
1764       if (strchr(resv, *name))
1765         return MR_EXISTS;
1766       if (strlen(resv) == USERS_RESERVATIONS_SIZE - 1)
1767         return MR_ARG_TOO_LONG;
1768
1769       strcat(resv, name);
1770     }
1771   else
1772     {
1773       char *p = strchr(resv, *name);
1774       if (!p)
1775         return MR_NO_MATCH;
1776       memmove(p, p + 1, strlen(p));
1777     }
1778
1779   EXEC SQL UPDATE users SET reservations = NVL(:resv, CHR(0))
1780     WHERE users_id = :uid;
1781   if (dbms_errno)
1782     return mr_errcode;
1783
1784   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
1785     WHERE table_name = 'users';
1786   return set_modtime_by_id(q, argv, cl);
1787 }
1788
1789 int get_user_reservations(struct query *q, char **argv, client *cl,
1790                           int (*action)(int, char *[], void *), void *actarg)
1791 {
1792   EXEC SQL BEGIN DECLARE SECTION;
1793   char resv[USERS_RESERVATIONS_SIZE], *p;
1794   char trans[ALIAS_TRANS_SIZE], name[2] = { 0, 0 };
1795   int uid;
1796   EXEC SQL END DECLARE SECTION;
1797   char *targv[1];
1798
1799   uid = *(int *)argv[0];
1800
1801   EXEC SQL SELECT reservations INTO :resv FROM users
1802     WHERE users_id = :uid;
1803   if (dbms_errno)
1804     return mr_errcode;
1805
1806   targv[0] = trans;
1807   p = resv;
1808   while (*p && !isspace(*p))
1809     {
1810       name[0] = toupper(*p);
1811       EXEC SQL SELECT trans INTO :trans FROM alias
1812         WHERE type = 'RESERVE' AND UPPER(name) = :name;
1813       if (dbms_errno)
1814         return mr_errcode;
1815       if (sqlca.sqlerrd[2] != 1)
1816         sprintf(trans, "Unknown (%s)", name);
1817       (*action)(1, targv, actarg);
1818       p++;
1819     }
1820   return MR_SUCCESS;
1821 }
1822
1823 int get_user_by_reservation(struct query *q, char **argv, client *cl,
1824                             int (*action)(int, char *[], void *), void *actarg)
1825 {
1826   EXEC SQL BEGIN DECLARE SECTION;
1827   char resv[USERS_RESERVATIONS_SIZE], login[USERS_LOGIN_SIZE];
1828   char *trans, name[ALIAS_NAME_SIZE];
1829   int uid;
1830   EXEC SQL END DECLARE SECTION;
1831   char *targv[1];
1832
1833   trans = argv[0];
1834
1835   EXEC SQL SELECT UPPER(name) INTO :name FROM alias
1836     WHERE type = 'RESERVE' AND LOWER(trans) = LOWER(:trans);
1837   if (dbms_errno)
1838     return mr_errcode;
1839   if (sqlca.sqlerrd[2] != 1)
1840     return MR_STRING;
1841   name[1] = '\0';
1842
1843   EXEC SQL DECLARE csr_gubr CURSOR FOR
1844     SELECT login FROM users WHERE reservations LIKE '%' || :name || '%';
1845   EXEC SQL OPEN csr_gubr;
1846   if (dbms_errno)
1847     return mr_errcode;
1848
1849   targv[0] = login;
1850   while (1)
1851     {
1852       EXEC SQL FETCH csr_gubr INTO :login;
1853       if (sqlca.sqlcode)
1854         break;
1855       (*action)(1, targv, actarg);
1856     }
1857   EXEC SQL CLOSE csr_gubr;
1858
1859   return MR_SUCCESS;
1860 }
This page took 0.558215 seconds and 5 git commands to generate.