]> andersk Git - moira.git/blob - server/qsupport.pc
make set_pobox and set_pobox_pop deal with imap_id.
[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     set_pop_usage(id, -1);
64
65   if (!strcmp(argv[1], "POP"))
66     {
67       status = name_to_id(box, MACHINE_TABLE, &id);
68       if (status == MR_NO_MATCH)
69         return MR_MACHINE;
70       else if (status)
71         return status;
72       EXEC SQL UPDATE users SET potype = 'POP', pop_id = :id, imap_id = 0
73         WHERE users_id = :user;
74       set_pop_usage(id, 1);
75     }
76   else if (!strcmp(argv[1], "SMTP"))
77     {
78       if (strchr(box, '/') || strchr(box, '|'))
79         return MR_BAD_CHAR;
80       status = name_to_id(box, STRINGS_TABLE, &id);
81       if (status == MR_NO_MATCH)
82         id = add_string(box);
83       else if (status)
84         return status;
85       EXEC SQL UPDATE users SET potype = 'SMTP', box_id = :id
86         WHERE users_id = :user;
87     }
88   else if (!strcmp(argv[1], "IMAP"))
89     {
90       EXEC SQL SELECT filsys_id INTO :id FROM filesys
91         WHERE label = :box AND type = 'IMAP';
92       if (sqlca.sqlcode)
93         return MR_FILESYS;
94       EXEC SQL UPDATE users SET potype = 'IMAP', imap_id = :id, pop_id = 0
95         WHERE users_id = :user;
96     }
97   else /* argv[1] == "NONE" */
98     {
99       EXEC SQL UPDATE users SET potype = 'NONE'
100         WHERE users_id = :user;
101     }
102
103   set_pobox_modtime(q, argv, cl);
104   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
105     WHERE table_name = 'users';
106   if (dbms_errno)
107     return mr_errcode;
108   return MR_SUCCESS;
109 }
110
111 /* set_pobox_pop: Revert to existing POP or IMAP pobox.
112  * Also take care of keeping track of the post office usage.
113  */
114 int set_pobox_pop(struct query *q, char **argv, client *cl)
115 {
116   EXEC SQL BEGIN DECLARE SECTION;
117   int id, pid, iid, mid;
118   char type[USERS_POTYPE_SIZE];
119   EXEC SQL END DECLARE SECTION;
120
121   id = *(int *)argv[0];
122   EXEC SQL SELECT potype, pop_id, imap_id INTO :type, :pid, :iid
123     FROM users WHERE users_id = :id;
124   if (sqlca.sqlerrd[2] == 0 || (pid == 0 && iid == 0))
125     return MR_MACHINE;
126
127   if (pid)
128     {
129       EXEC SQL SELECT mach_id INTO :mid FROM machine
130         WHERE mach_id = :pid;
131       if (sqlca.sqlerrd[2] == 0)
132         return MR_MACHINE;
133       EXEC SQL UPDATE users SET potype = 'POP' WHERE users_id = :id;
134       if (strcmp(strtrim(type), "POP"))
135         set_pop_usage(mid, 1);
136     }
137   else
138     {
139       EXEC SQL SELECT filsys_id INTO :mid FROM filesys
140         WHERE filsys_id = :iid;
141       if (sqlca.sqlerrd[2] == 0)
142         return MR_MACHINE;
143       EXEC SQL UPDATE users SET potype = 'IMAP' WHERE users_id = :id;
144     }
145
146   set_pobox_modtime(q, argv, cl);
147   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
148     WHERE table_name = 'users';
149   if (dbms_errno)
150     return mr_errcode;
151   return MR_SUCCESS;
152 }
153
154
155 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
156  * how many different ancestors a member is allowed to have.
157  */
158
159 #define MAXLISTDEPTH    1024
160
161 int add_member_to_list(struct query *q, char **argv, client *cl)
162 {
163   EXEC SQL BEGIN DECLARE SECTION;
164   int id, lid, mid, tag, error, who, ref, rowcnt;
165   char *mtype, dtype[IMEMBERS_MEMBER_TYPE_SIZE], *entity;
166   EXEC SQL END DECLARE SECTION;
167   int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
168   int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
169   int status;
170   char *dtypes[MAXLISTDEPTH];
171   char *iargv[3], *buf;
172
173   lid = *(int *)argv[0];
174   mtype = argv[1];
175   mid = *(int *)argv[2];
176   tag = !strcmp(q->shortname, "atml") ? *(int *)argv[3] : 0;
177
178   if (acl_access_check(lid, cl))
179     return MR_PERM;
180
181   /* if the member is already a direct member of the list, punt */
182   EXEC SQL SELECT COUNT(list_id) INTO :rowcnt FROM imembers
183     WHERE list_id = :lid AND member_id = :mid
184     AND member_type = :mtype AND direct = 1;
185   if (rowcnt > 0)
186     return MR_EXISTS;
187   if (!strcasecmp(mtype, "STRING"))
188     {
189       buf = malloc(0);
190       status = id_to_name(mid, STRINGS_TABLE, &buf);
191       if (status)
192         return status;
193       if (strchr(buf, '/') || strchr(buf, '|'))
194         {
195           free(buf);
196           return MR_BAD_CHAR;
197         }
198       free(buf);
199     }
200
201   ancestors[0] = lid;
202   aref[0] = 1;
203   acount = 1;
204   EXEC SQL DECLARE csr103 CURSOR FOR
205     SELECT list_id, ref_count   FROM imembers
206     WHERE member_id = :lid AND member_type = 'LIST';
207   if (dbms_errno)
208     return mr_errcode;
209   EXEC SQL OPEN csr103;
210   if (dbms_errno)
211     return mr_errcode;
212   while (1)
213     {
214       EXEC SQL FETCH csr103 INTO :id, :ref;
215       if (sqlca.sqlcode)
216         break;
217       aref[acount] = ref;
218       ancestors[acount++] = id;
219       if (acount >= MAXLISTDEPTH)
220         break;
221     }
222   EXEC SQL CLOSE csr103;
223   if (dbms_errno)
224     return mr_errcode;
225   if (acount >= MAXLISTDEPTH)
226     return MR_INTERNAL;
227   descendants[0] = mid;
228   dtypes[0] = mtype;
229   dref[0] = 1;
230   dcount = 1;
231   error = 0;
232   if (!strcmp(mtype, "LIST"))
233     {
234       EXEC SQL DECLARE csr104 CURSOR FOR
235         SELECT member_id, member_type, ref_count
236         FROM imembers
237         WHERE list_id = :mid;
238       if (dbms_errno)
239         return mr_errcode;
240       EXEC SQL OPEN csr104;
241       if (dbms_errno)
242         return mr_errcode;
243       while (1)
244         {
245           EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
246           if (sqlca.sqlcode)
247             break;
248           switch (dtype[0])
249             {
250             case 'L':
251               dtypes[dcount] = "LIST";
252               break;
253             case 'U':
254               dtypes[dcount] = "USER";
255               break;
256             case 'S':
257               dtypes[dcount] = "STRING";
258               break;
259             case 'K':
260               dtypes[dcount] = "KERBEROS";
261               break;
262             default:
263               error++;
264               break;
265             }
266           dref[dcount] = ref;
267           descendants[dcount++] = id;
268           if (dcount >= MAXLISTDEPTH)
269             {
270               error++;
271               break;
272             }
273         }
274       EXEC SQL CLOSE csr104;
275       if (dbms_errno)
276         return mr_errcode;
277       if (error)
278         return MR_INTERNAL;
279     }
280   for (a = 0; a < acount; a++)
281     {
282       lid = ancestors[a];
283       for (d = 0; d < dcount; d++)
284         {
285           mid = descendants[d];
286           mtype = dtypes[d];
287           if (mid == lid && !strcmp(mtype, "LIST"))
288             return MR_LISTLOOP;
289           EXEC SQL SELECT COUNT(ref_count) INTO :rowcnt
290             FROM imembers
291             WHERE list_id = :lid AND member_id = :mid
292             AND member_type = :mtype;
293           ref = aref[a] * dref[d];
294           if (rowcnt > 0)
295             {
296               if (a == 0 && d == 0)
297                 {
298                   EXEC SQL UPDATE imembers
299                     SET ref_count = ref_count + :ref, direct = 1, tag = :tag
300                     WHERE list_id = :lid AND member_id = :mid
301                     AND member_type = :mtype;
302                 }
303               else
304                 {
305                   EXEC SQL UPDATE imembers
306                     SET ref_count = ref_count + :ref
307                     WHERE list_id = :lid AND member_id = :mid
308                     AND member_type = :mtype;
309                 }
310             }
311           else
312             {
313               incremental_clear_before();
314               if (a == 0 && d == 0)
315                 {
316                   EXEC SQL INSERT INTO imembers
317                     (list_id, member_type, member_id, tag, direct, ref_count)
318                     VALUES (:lid, :mtype, :mid, :tag, 1, 1);
319                 }
320               else
321                 {
322                   EXEC SQL INSERT INTO imembers
323                     (list_id, member_type, member_id, tag, direct, ref_count)
324                     VALUES (:lid, :mtype, :mid, :tag, 0, 1);
325                 }
326               iargv[0] = (char *)lid;
327               iargv[1] = mtype;
328               iargv[2] = (char *)mid;
329               incremental_after(IMEMBERS_TABLE, 0, iargv);
330             }
331         }
332     }
333   lid = *(int *)argv[0];
334   entity = cl->entity;
335   who = cl->client_id;
336   EXEC SQL UPDATE list
337     SET modtime = SYSDATE, modby = :who, modwith = :entity
338     WHERE list_id = :lid;
339   if (dbms_errno)
340     return mr_errcode;
341   return MR_SUCCESS;
342 }
343
344
345 /* Delete_member_from_list: do list flattening as we go!
346  */
347
348 int delete_member_from_list(struct query *q, char **argv, client *cl)
349 {
350   EXEC SQL BEGIN DECLARE SECTION;
351   int id, lid, mid, cnt, error, who, ref;
352   char *mtype, dtype[IMEMBERS_MEMBER_TYPE_SIZE], *entity;
353   EXEC SQL END DECLARE SECTION;
354   int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
355   int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
356   char *dtypes[MAXLISTDEPTH];
357   char *iargv[3];
358
359   lid = *(int *)argv[0];
360   mtype = argv[1];
361   mid = *(int *)argv[2];
362
363   if (acl_access_check(lid, cl))
364     return MR_PERM;
365
366   /* if the member is not a direct member of the list, punt */
367   EXEC SQL SELECT COUNT(list_id) INTO :cnt FROM imembers
368     WHERE list_id = :lid AND member_id = :mid
369     AND member_type = :mtype AND direct = 1;
370   if (dbms_errno)
371     return mr_errcode;
372   if (cnt == 0)
373     return MR_NO_MATCH;
374   ancestors[0] = lid;
375   aref[0] = 1;
376   acount = 1;
377   EXEC SQL DECLARE csr105 CURSOR FOR
378     SELECT list_id, ref_count FROM imembers
379     WHERE member_id = :lid AND member_type = 'LIST';
380   if (dbms_errno)
381     return mr_errcode;
382   EXEC SQL OPEN csr105;
383   if (dbms_errno)
384     return mr_errcode;
385   while (1)
386     {
387       EXEC SQL FETCH csr105 INTO :id, :ref;
388       if (sqlca.sqlcode)
389         break;
390       aref[acount] = ref;
391       ancestors[acount++] = id;
392       if (acount >= MAXLISTDEPTH)
393         break;
394     }
395   EXEC SQL CLOSE csr105;
396   if (dbms_errno)
397     return mr_errcode;
398   if (acount >= MAXLISTDEPTH)
399     return MR_INTERNAL;
400   descendants[0] = mid;
401   dtypes[0] = mtype;
402   dref[0] = 1;
403   dcount = 1;
404   error = 0;
405   if (!strcmp(mtype, "LIST"))
406     {
407       EXEC SQL DECLARE csr106 CURSOR FOR
408         SELECT member_id, member_type, ref_count FROM imembers
409         WHERE list_id = :mid;
410       if (dbms_errno)
411         return mr_errcode;
412       EXEC SQL OPEN csr106;
413       if (dbms_errno)
414         return mr_errcode;
415       while (1)
416         {
417           EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
418           if (sqlca.sqlcode)
419             break;
420           switch (dtype[0])
421             {
422             case 'L':
423               dtypes[dcount] = "LIST";
424               break;
425             case 'U':
426               dtypes[dcount] = "USER";
427               break;
428             case 'S':
429               dtypes[dcount] = "STRING";
430               break;
431             case 'K':
432               dtypes[dcount] = "KERBEROS";
433               break;
434             default:
435               error++;
436               break;
437             }
438           dref[dcount] = ref;
439           descendants[dcount++] = id;
440           if (dcount >= MAXLISTDEPTH)
441             break;
442         }
443       EXEC SQL CLOSE csr106;
444       if (dbms_errno)
445         return mr_errcode;
446       if (error)
447         return MR_INTERNAL;
448     }
449   for (a = 0; a < acount; a++)
450     {
451       lid = ancestors[a];
452       for (d = 0; d < dcount; d++)
453         {
454           mid = descendants[d];
455           mtype = dtypes[d];
456           if (mid == lid && !strcmp(mtype, "LIST"))
457             return MR_LISTLOOP;
458           EXEC SQL SELECT ref_count INTO :cnt FROM imembers
459             WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
460           ref = aref[a] * dref[d];
461           if (cnt <= ref)
462             {
463               iargv[0] = (char *)lid;
464               iargv[1] = mtype;
465               iargv[2] = (char *)mid;
466               incremental_before(IMEMBERS_TABLE, 0, iargv);
467               EXEC SQL DELETE FROM imembers
468                 WHERE list_id = :lid AND member_id = :mid
469                 AND member_type= :mtype;
470               incremental_clear_after();
471             }
472           else if (a == 0 && d == 0)
473             {
474               EXEC SQL UPDATE imembers
475                 SET ref_count = ref_count - :ref, direct = 0
476                 WHERE list_id = :lid AND member_id = :mid
477                 AND member_type = :mtype;
478             }
479           else
480             {
481               EXEC SQL UPDATE imembers
482                 SET ref_count = ref_count - :ref
483                 WHERE list_id = :lid AND member_id = :mid
484                 AND member_type = :mtype;
485             }
486         }
487     }
488   lid = *(int *)argv[0];
489   entity = cl->entity;
490   who = cl->client_id;
491   EXEC SQL UPDATE list SET modtime = SYSDATE, modby = :who, modwith = :entity
492     WHERE list_id = :lid;
493   if (dbms_errno)
494     return mr_errcode;
495   return MR_SUCCESS;
496 }
497
498
499 /* Don't allow someone to add someone to a list which is the acl of a
500  * query unless they're on the list acl, even if they're on the amtl
501  * query acl! Also, don't allow someone proxying to add someone to a
502  * capacl.
503  */
504 int acl_access_check(int list_id, client *cl)
505 {
506   EXEC SQL BEGIN DECLARE SECTION;
507   int c1, c2, lid = list_id, acl_id;
508   char acl_type[LIST_ACL_TYPE_SIZE];
509   EXEC SQL END DECLARE SECTION;
510
511   /* Check if the list is directly a capacl */
512   EXEC SQL SELECT COUNT(list_id) INTO :c1 FROM capacls WHERE list_id=:lid;
513
514   /* Check if the list is a member (direct or indirect) of a list that
515      is a capacl */
516   EXEC SQL SELECT COUNT(l1.list_id) INTO :c2 FROM list l1, list l2,
517     imembers im, capacls c WHERE c.list_id = l2.list_id AND
518     im.list_id = l2.list_id AND im.member_type = 'LIST' AND
519     im.member_id = l1.list_id AND l1.list_id = :lid;
520
521   if (c1 == 0 && c2 == 0)
522     return 0;
523
524   if (cl->proxy_id)
525     return 1;
526
527   EXEC SQL SELECT acl_type, acl_id INTO :acl_type, :acl_id
528     FROM list WHERE list_id=:lid;
529   return !find_member(acl_type, acl_id, cl);
530 }
531
532
533 /* get_ace_use - given a type and a name, return a type and a name.
534  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
535  * and argv[1] will contain the ID of the entity in question.  The R*
536  * types mean to recursively look at every containing list, not just
537  * when the object in question is a direct member.  On return, the
538  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
539  */
540
541 int get_ace_use(struct query *q, char *argv[], client *cl,
542                 int (*action)(int, char *[], void *), void *actarg)
543 {
544   int found = 0;
545   EXEC SQL BEGIN DECLARE SECTION;
546   char *atype;
547   int aid, listid, id;
548   EXEC SQL END DECLARE SECTION;
549   struct save_queue *sq;
550
551   atype = argv[0];
552   aid = *(int *)argv[1];
553   if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
554       !strcmp(atype, "KERBEROS"))
555     return get_ace_internal(atype, aid, action, actarg);
556
557   sq = sq_create();
558   if (!strcmp(atype, "RLIST"))
559     {
560       sq_save_data(sq, (void *)aid);
561       /* get all the list_id's of containing lists */
562       EXEC SQL DECLARE csr107 CURSOR FOR
563         SELECT list_id FROM imembers
564         WHERE member_type = 'LIST' AND member_id = :aid;
565       if (dbms_errno)
566         return mr_errcode;
567       EXEC SQL OPEN csr107;
568       if (dbms_errno)
569         return mr_errcode;
570       while (1)
571         {
572           EXEC SQL FETCH csr107 INTO :listid;
573           if (sqlca.sqlcode)
574             break;
575           sq_save_unique_data(sq, (void *)listid);
576         }
577       EXEC SQL CLOSE csr107;
578       /* now process each one */
579       while (sq_get_data(sq, &id))
580         {
581           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
582             found++;
583         }
584     }
585
586   if (!strcmp(atype, "RUSER"))
587     {
588       EXEC SQL DECLARE csr108 CURSOR FOR
589         SELECT list_id FROM imembers
590         WHERE member_type = 'USER' AND member_id = :aid;
591       if (dbms_errno)
592         return mr_errcode;
593       EXEC SQL OPEN csr108;
594       if (dbms_errno)
595         return mr_errcode;
596       while (1)
597         {
598           EXEC SQL FETCH csr108 INTO :listid;
599           if (sqlca.sqlcode)
600             break;
601           sq_save_data(sq, (void *)listid);
602         }
603       EXEC SQL CLOSE csr108;
604       /* now process each one */
605       while (sq_get_data(sq, &id))
606         {
607           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
608             found++;
609         }
610       if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
611         found++;
612     }
613
614   if (!strcmp(atype, "RKERBEROS"))
615     {
616       EXEC SQL DECLARE csr109 CURSOR FOR
617         SELECT list_id FROM imembers
618         WHERE member_type = 'KERBEROS' AND member_id = :aid;
619       if (dbms_errno)
620         return mr_errcode;
621       EXEC SQL OPEN csr109;
622       if (dbms_errno)
623         return mr_errcode;
624       while (1)
625         {
626           EXEC SQL FETCH csr109 INTO :listid;
627           if (sqlca.sqlcode)
628             break;
629           sq_save_data(sq, (void *)listid);
630         }
631       EXEC SQL CLOSE csr109;
632       /* now process each one */
633       while (sq_get_data(sq, &id))
634         {
635           if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
636             found++;
637         }
638       if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
639         found++;
640     }
641
642   sq_destroy(sq);
643   if (dbms_errno)
644     return mr_errcode;
645   if (!found)
646     return MR_NO_MATCH;
647   return MR_SUCCESS;
648 }
649
650
651 /* This looks up a single list or user for ace use.  atype must be "USER"
652  * or "LIST", and aid is the ID of the corresponding object.  This is used
653  * by get_ace_use above.
654  */
655
656 int get_ace_internal(char *atype, int aid,
657                      int (*action)(int, char *[], void *), void *actarg)
658 {
659   char *rargv[2];
660   int found = 0;
661   EXEC SQL BEGIN DECLARE SECTION;
662   char name[LIST_NAME_SIZE], *type = atype;
663   int id = aid;
664   EXEC SQL END DECLARE SECTION;
665
666   rargv[1] = name;
667   if (!strcmp(atype, "LIST"))
668     {
669       rargv[0] = "FILESYS";
670       EXEC SQL DECLARE csr110 CURSOR FOR
671         SELECT label FROM filesys
672         WHERE owners = :id;
673       if (dbms_errno)
674         return mr_errcode;
675       EXEC SQL OPEN csr110;
676       if (dbms_errno)
677         return mr_errcode;
678       while (1)
679         {
680           EXEC SQL FETCH csr110 INTO :name;
681           if (sqlca.sqlcode)
682             break;
683           (*action)(2, rargv, actarg);
684           found++;
685         }
686       EXEC SQL CLOSE csr110;
687
688       rargv[0] = "QUERY";
689       EXEC SQL DECLARE csr111 CURSOR FOR
690         SELECT capability FROM capacls
691         WHERE list_id = :id;
692       if (dbms_errno)
693         return mr_errcode;
694       EXEC SQL OPEN csr111;
695       if (dbms_errno)
696         return mr_errcode;
697       while (1)
698         {
699           EXEC SQL FETCH csr111 INTO :name;
700           if (sqlca.sqlcode)
701             break;
702           (*action)(2, rargv, actarg);
703           found++;
704         }
705       EXEC SQL CLOSE csr111;
706     }
707   else if (!strcmp(atype, "USER"))
708     {
709       rargv[0] = "FILESYS";
710       EXEC SQL DECLARE csr112 CURSOR FOR
711         SELECT label FROM filesys
712         WHERE owner = :id;
713       if (dbms_errno)
714         return mr_errcode;
715       EXEC SQL OPEN csr112;
716       if (dbms_errno)
717         return mr_errcode;
718       while (1)
719         {
720           EXEC SQL FETCH csr112 INTO :name;
721           if (sqlca.sqlcode)
722             break;
723           (*action)(2, rargv, actarg);
724           found++;
725         }
726       EXEC SQL CLOSE csr112;
727     }
728
729   rargv[0] = "LIST";
730   EXEC SQL DECLARE csr113 CURSOR FOR
731     SELECT name FROM list
732     WHERE acl_type = :type AND acl_id = :id;
733   if (dbms_errno)
734     return mr_errcode;
735   EXEC SQL OPEN csr113;
736   if (dbms_errno)
737     return mr_errcode;
738   while (1)
739     {
740       EXEC SQL FETCH csr113 INTO :name;
741       if (sqlca.sqlcode)
742         break;
743       (*action)(2, rargv, actarg);
744       found++;
745     }
746   EXEC SQL CLOSE csr113;
747
748   rargv[0] = "SERVICE";
749   EXEC SQL DECLARE csr114 CURSOR FOR
750     SELECT name FROM servers
751     WHERE acl_type = :type AND acl_id = :id;
752   if (dbms_errno)
753     return mr_errcode;
754   EXEC SQL OPEN csr114;
755   if (dbms_errno)
756     return mr_errcode;
757   while (1)
758     {
759       EXEC SQL FETCH csr114 INTO :name;
760       if (sqlca.sqlcode)
761         break;
762       (*action)(2, rargv, actarg);
763       found++;
764     }
765   EXEC SQL CLOSE csr114;
766
767   rargv[0] = "HOSTACCESS";
768   EXEC SQL DECLARE csr115 CURSOR FOR
769     SELECT name FROM machine m, hostaccess ha
770     WHERE m.mach_id = ha.mach_id AND ha.acl_type = :type
771     AND ha.acl_id = :id;
772     if (dbms_errno)
773         return mr_errcode;
774     EXEC SQL OPEN csr115;
775     if (dbms_errno)
776         return mr_errcode;
777     while (1)
778       {
779         EXEC SQL FETCH csr115 INTO :name;
780         if (sqlca.sqlcode)
781           break;
782         (*action)(2, rargv, actarg);
783         found++;
784       }
785     EXEC SQL CLOSE csr115;
786
787     rargv[0] = "ZEPHYR";
788     EXEC SQL DECLARE csr116 CURSOR FOR
789       SELECT class FROM zephyr z
790       WHERE z.xmt_type = :type AND z.xmt_id = :id
791       OR z.sub_type = :type AND z.sub_id = :id
792       OR z.iws_type = :type AND z.iws_id = :id
793       OR z.iui_type = :type AND z.iui_id = :id;
794     if (dbms_errno)
795       return mr_errcode;
796     EXEC SQL OPEN csr116;
797     if (dbms_errno)
798       return mr_errcode;
799     while (1)
800       {
801         EXEC SQL FETCH csr116 INTO :name;
802         if (sqlca.sqlcode)
803           break;
804         (*action)(2, rargv, actarg);
805         found++;
806       }
807     EXEC SQL CLOSE csr116;
808
809     if (!found)
810       return MR_NO_MATCH;
811     return MR_SUCCESS;
812 }
813
814
815 /* get_lists_of_member - given a type and a name, return the name and flags
816  * of all of the lists of the given member.  The member_type is one of
817  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
818  * and argv[1] will contain the ID of the entity in question.  The R*
819  * types mean to recursively look at every containing list, not just
820  * when the object in question is a direct member.
821  */
822
823 int get_lists_of_member(struct query *q, char *argv[], client *cl,
824                         int (*action)(int, char *[], void *), void *actarg)
825 {
826   int found = 0, direct = 1;
827   char *rargv[6];
828   EXEC SQL BEGIN DECLARE SECTION;
829   char *atype;
830   int aid;
831   char name[LIST_NAME_SIZE];
832   char active[5], public[5], hidden[5], maillist[5], grouplist[5];
833   EXEC SQL END DECLARE SECTION;
834
835   atype = argv[0];
836   aid = *(int *)argv[1];
837   if (!strcmp(atype, "RLIST"))
838     {
839       atype = "LIST";
840       direct = 0;
841     }
842   if (!strcmp(atype, "RUSER"))
843     {
844       atype = "USER";
845       direct = 0;
846     }
847   if (!strcmp(atype, "RSTRING"))
848     {
849       atype = "STRING";
850       direct = 0;
851     }
852   if (!strcmp(atype, "RKERBEROS"))
853     {
854       atype = "KERBEROS";
855       direct = 0;
856     }
857
858   rargv[0] = name;
859   rargv[1] = active;
860   rargv[2] = public;
861   rargv[3] = hidden;
862   rargv[4] = maillist;
863   rargv[5] = grouplist;
864   if (direct)
865     {
866       EXEC SQL DECLARE csr117a CURSOR FOR
867         SELECT l.name, l.active, l.publicflg, l.hidden, l.maillist, l.grouplist
868         FROM list l, imembers im
869         WHERE l.list_id = im.list_id AND im.direct = 1
870         AND im.member_type = :atype AND im.member_id = :aid;
871       if (dbms_errno)
872         return mr_errcode;
873       EXEC SQL OPEN csr117a;
874       if (dbms_errno)
875         return mr_errcode;
876       while (1)
877         {
878           EXEC SQL FETCH csr117a
879             INTO :name, :active, :public, :hidden, :maillist, :grouplist;
880           if (sqlca.sqlcode)
881             break;
882           (*action)(6, rargv, actarg);
883           found++;
884         }
885       EXEC SQL CLOSE csr117a;
886     }
887   else
888     {
889       EXEC SQL DECLARE csr117b CURSOR FOR
890         SELECT l.name, l.active, l.publicflg, l.hidden, l.maillist, l.grouplist
891         FROM list l, imembers im
892         WHERE l.list_id = im.list_id
893         AND im.member_type = :atype AND im.member_id = :aid;
894       if (dbms_errno)
895         return mr_errcode;
896       EXEC SQL OPEN csr117b;
897       if (dbms_errno)
898         return mr_errcode;
899       while (1)
900         {
901           EXEC SQL FETCH csr117b
902             INTO :name, :active, :public, :hidden, :maillist, :grouplist;
903           if (sqlca.sqlcode)
904             break;
905           (*action)(6, rargv, actarg);
906           found++;
907         }
908       EXEC SQL CLOSE csr117b;
909     }
910
911   if (dbms_errno)
912     return mr_errcode;
913   if (!found)
914     return MR_NO_MATCH;
915   return MR_SUCCESS;
916 }
917
918
919 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
920  * the five flags associated with each list.  It will return the name of
921  * each list that meets the quailifications.  It does this by building a
922  * where clause based on the arguments, then doing a retrieve.
923  */
924
925 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
926
927 int qualified_get_lists(struct query *q, char *argv[], client *cl,
928                         int (*action)(int, char *[], void *), void *actarg)
929 {
930   return qualified_get(q, argv, action, actarg, "l.list_id != 0",
931                        "l", "name", lflags);
932 }
933
934
935 int get_members_of_list(struct query *q, char *argv[], client *cl,
936                         int (*action)(int, char *[], void *), void *actarg)
937 {
938   EXEC SQL BEGIN DECLARE SECTION;
939   int list_id, direct;
940   char member_name[MAX_FIELD_WIDTH], tag[STRINGS_STRING_SIZE];
941   EXEC SQL END DECLARE SECTION;
942   char *targv[3];
943   int targc;
944
945   /* For gmol or gtml, only get direct members. For geml, get all. */
946   if (!strcmp(q->shortname, "geml"))
947     direct = -1;
948   else
949     direct = 0;
950
951   /* For gmol or geml, only return type and name. For gtml, return tag too. */
952   if (!strcmp(q->shortname, "gtml"))
953     targc = 3;
954   else
955     targc = 2;
956
957   list_id = *(int *)argv[0];
958
959   targv[1] = member_name;
960   targv[2] = tag;
961
962   targv[0] = "USER";
963   EXEC SQL DECLARE csr119 CURSOR FOR
964     SELECT u.login, s.string FROM users u, imembers im, strings s
965     WHERE im.list_id = :list_id AND im.member_type = 'USER'
966     AND im.member_id = u.users_id AND im.direct > :direct
967     AND s.string_id = im.tag ORDER BY 1;
968   if (dbms_errno)
969     return mr_errcode;
970   EXEC SQL OPEN csr119;
971   if (dbms_errno)
972     return mr_errcode;
973   while (1)
974     {
975       EXEC SQL FETCH csr119 INTO :member_name, :tag;
976       if (sqlca.sqlcode)
977         break;
978       (*action)(targc, targv, actarg);
979     }
980   EXEC SQL CLOSE csr119;
981   if (dbms_errno)
982     return mr_errcode;
983
984   targv[0] = "LIST";
985   EXEC SQL DECLARE csr120 CURSOR FOR
986     SELECT l.name, s.string FROM list l, imembers im, strings s
987     WHERE im.list_id = :list_id AND im.member_type = 'LIST'
988     AND im.member_id = l.list_id AND im.direct > :direct
989     AND s.string_id = im.tag ORDER BY 1;
990   if (dbms_errno)
991     return mr_errcode;
992   EXEC SQL OPEN csr120;
993   if (dbms_errno)
994     return mr_errcode;
995   while (1)
996     {
997       EXEC SQL FETCH csr120 INTO :member_name, :tag;
998       if (sqlca.sqlcode)
999         break;
1000       (*action)(targc, targv, actarg);
1001     }
1002   EXEC SQL CLOSE csr120;
1003   if (dbms_errno)
1004     return mr_errcode;
1005
1006   targv[0] = "STRING";
1007   EXEC SQL DECLARE csr121 CURSOR FOR
1008     SELECT str.string, s.string FROM strings str, imembers im, strings s
1009     WHERE im.list_id = :list_id AND im.member_type = 'STRING'
1010     AND im.member_id = str.string_id AND im.direct > :direct
1011     AND s.string_id = im.tag ORDER BY 1;
1012   if (dbms_errno)
1013     return mr_errcode;
1014   EXEC SQL OPEN csr121;
1015   if (dbms_errno)
1016     return mr_errcode;
1017   while (1)
1018     {
1019       EXEC SQL FETCH csr121 INTO :member_name, :tag;
1020       if (sqlca.sqlcode)
1021         break;
1022       (*action)(targc, targv, actarg);
1023     }
1024   EXEC SQL CLOSE csr121;
1025   if (dbms_errno)
1026     return mr_errcode;
1027
1028   targv[0] = "KERBEROS";
1029   EXEC SQL DECLARE csr122 CURSOR FOR
1030     SELECT str.string, s.string FROM strings str, imembers im, strings s
1031     WHERE im.list_id = :list_id AND im.member_type = 'KERBEROS'
1032     AND im.member_id = str.string_id AND im.direct > :direct
1033     AND s.string_id = im.tag ORDER BY 1;
1034   if (dbms_errno)
1035     return mr_errcode;
1036   EXEC SQL OPEN csr122;
1037   if (dbms_errno)
1038     return mr_errcode;
1039   while (1)
1040     {
1041       EXEC SQL FETCH csr122 INTO :member_name, :tag;
1042       if (sqlca.sqlcode)
1043         break;
1044       (*action)(targc, targv, actarg);
1045     }
1046   EXEC SQL CLOSE csr122;
1047   if (dbms_errno)
1048     return mr_errcode;
1049
1050   return MR_SUCCESS;
1051 }
1052
1053
1054 /* count_members_of_list: this is a simple query, but it cannot be done
1055  * through the dispatch table.
1056  */
1057
1058 int count_members_of_list(struct query *q, char *argv[], client *cl,
1059                           int (*action)(int, char *[], void *), void *actarg)
1060 {
1061   EXEC SQL BEGIN DECLARE SECTION;
1062   int  list, ct = 0;
1063   EXEC SQL END DECLARE SECTION;
1064   char *rargv[1], countbuf[5];
1065
1066   list = *(int *)argv[0];
1067   rargv[0] = countbuf;
1068   EXEC SQL SELECT count (*) INTO :ct FROM imembers
1069     WHERE list_id = :list AND direct = 1;
1070   if (dbms_errno)
1071     return mr_errcode;
1072   sprintf(countbuf, "%d", ct);
1073   (*action)(1, rargv, actarg);
1074   return MR_SUCCESS;
1075 }
1076
1077
1078 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
1079  * the three flags associated with each service.  It will return the name of
1080  * each service that meets the quailifications.  It does this by building a
1081  * where clause based on the arguments, then doing a retrieve.
1082  */
1083
1084 static char *sflags[3] = { "enable", "inprogress", "harderror" };
1085
1086 int qualified_get_server(struct query *q, char *argv[], client *cl,
1087                          int (*action)(int, char *[], void *), void *actarg)
1088 {
1089   return qualified_get(q, argv, action, actarg, "s.name is not null",
1090                        "s", "name", sflags);
1091   /* of course, name will never be null, but we need something there
1092      to make qualified_get happy */
1093 }
1094
1095
1096 /* generic qualified get routine, used by qualified_get_lists,
1097  * qualified_get_server, and qualified_get_serverhost.
1098  *   Args:
1099  *      start - a simple where clause, must not be empty
1100  *      range - the name of the range variable
1101  *      field - the field to return
1102  *      flags - an array of strings, names of the flag variables
1103  */
1104
1105 int qualified_get(struct query *q, char *argv[],
1106                   int (*action)(int, char *[], void *), void *actarg,
1107                   char *start, char *range, char *field, char *flags[])
1108 {
1109   char qual[256];
1110   int i;
1111   char buf[32];
1112
1113   strcpy(qual, start);
1114   for (i = 0; i < q->argc; i++)
1115     {
1116       if (!strcmp(argv[i], "TRUE"))
1117         {
1118           sprintf(buf, " AND %s.%s != 0", range, flags[i]);
1119           strcat(qual, buf);
1120         }
1121       else if (!strcmp(argv[i], "FALSE"))
1122         {
1123           sprintf(buf, " AND %s.%s = 0", range, flags[i]);
1124           strcat(qual, buf);
1125         }
1126     }
1127
1128   sprintf(stmt_buf, "SELECT %s.%s FROM %s %s WHERE %s", range, field,
1129           table_name[q->rtable], range, qual);
1130   return do_for_all_rows(stmt_buf, 1, action, actarg);
1131 }
1132
1133
1134 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
1135  * the five flags associated with each serverhost.  It will return the name of
1136  * each service and host that meets the quailifications.  It does this by
1137  * building a where clause based on the arguments, then doing a retrieve.
1138  */
1139
1140 static char *shflags[6] = { "service", "enable", "override", "success",
1141                             "inprogress", "hosterror" };
1142
1143 int qualified_get_serverhost(struct query *q, char *argv[], client *cl,
1144                              int (*action)(int, char *[], void *),
1145                              void *actarg)
1146 {
1147   char qual[256], buf[32];
1148   int i;
1149
1150   sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = UPPER('%s')",
1151           argv[0]);
1152   for (i = 1; i < q->argc; i++)
1153     {
1154       if (!strcmp(argv[i], "TRUE"))
1155         {
1156           sprintf(buf, " AND sh.%s != 0", shflags[i]);
1157           strcat(qual, buf);
1158         }
1159       else if (!strcmp(argv[i], "FALSE"))
1160         {
1161           sprintf(buf, " AND sh.%s = 0", shflags[i]);
1162           strcat(qual, buf);
1163         }
1164     }
1165
1166   sprintf(stmt_buf, "SELECT sh.service, m.name FROM serverhosts sh, "
1167           "machine m WHERE %s", qual);
1168   return do_for_all_rows(stmt_buf, 2, action, actarg);
1169 }
1170
1171
1172 /* register_user - change user's login name and allocate a pobox, group,
1173  * filesystem, and quota for them.  The user's status must start out as 0,
1174  * and is left as 2.  Arguments are: user's UID, new login name, and user's
1175  * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
1176  * MR_FS_STAFF, MR_FS_MISC).
1177  */
1178
1179 int register_user(struct query *q, char **argv, client *cl)
1180 {
1181   EXEC SQL BEGIN DECLARE SECTION;
1182   char *login, *entity;
1183   char directory[FILESYS_NAME_SIZE], machname[MACHINE_NAME_SIZE];
1184   int who, rowcount, mid, uid, users_id, utype, list_id;
1185   int ostatus, nstatus, fsidval;
1186   static int m_id = 0, def_quota = 0;
1187   EXEC SQL END DECLARE SECTION;
1188   char buffer[256], *aargv[3];
1189
1190   entity = cl->entity;
1191   who = cl->client_id;
1192
1193   uid = atoi(argv[0]);
1194   login = argv[1];
1195   utype = atoi(argv[2]);
1196
1197   /* find user */
1198   EXEC SQL SELECT users_id, status INTO :users_id, :ostatus
1199     FROM users
1200     WHERE unix_uid = :uid AND (status = 0 OR status = 5 OR status = 6);
1201
1202   if (sqlca.sqlerrd[2] == 0)
1203     return MR_NO_MATCH;
1204   if (sqlca.sqlerrd[2] > 1)
1205     return MR_NOT_UNIQUE;
1206
1207   /* check new login name */
1208   EXEC SQL SELECT COUNT(login) INTO :rowcount FROM users
1209     WHERE login = :login AND users_id != :users_id;
1210   if (dbms_errno)
1211     return mr_errcode;
1212   if (rowcount > 0)
1213     return MR_IN_USE;
1214   EXEC SQL SELECT COUNT(name) INTO :rowcount FROM list
1215     WHERE LOWER(name) = :login;
1216   if (dbms_errno)
1217     return mr_errcode;
1218   if (rowcount > 0)
1219     return MR_IN_USE;
1220   EXEC SQL SELECT COUNT(label) INTO :rowcount FROM filesys
1221     WHERE label = :login;
1222   if (dbms_errno)
1223     return mr_errcode;
1224   if (rowcount > 0)
1225     return MR_IN_USE;
1226   EXEC SQL SELECT COUNT(name) INTO :rowcount FROM alias
1227     WHERE name = :login AND type = 'FILESYS';
1228   if (dbms_errno)
1229     return mr_errcode;
1230   if (rowcount > 0)
1231     return MR_IN_USE;
1232   com_err(whoami, 0, "login name OK");
1233
1234   /* choose place for pobox, put in mid */
1235   EXEC SQL DECLARE csr130 CURSOR FOR
1236     SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
1237     WHERE sh.service = 'POP' AND sh.mach_id = m.mach_id
1238     AND sh.value2 - sh.value1 = (SELECT MAX(value2 - value1) FROM serverhosts
1239                                  WHERE service = 'POP');
1240   if (dbms_errno)
1241     return mr_errcode;
1242   EXEC SQL OPEN csr130;
1243   if (dbms_errno)
1244     return mr_errcode;
1245   EXEC SQL FETCH csr130 INTO :mid, :machname;
1246   if (sqlca.sqlerrd[2] == 0)
1247     {
1248       EXEC SQL CLOSE csr130;
1249       if (dbms_errno)
1250         return mr_errcode;
1251       return MR_NO_POBOX;
1252     }
1253   else
1254     {
1255       EXEC SQL CLOSE csr130;
1256       if (dbms_errno)
1257         return mr_errcode;
1258     }
1259
1260   /* change login name, set pobox */
1261   sprintf(buffer, "u.users_id = %d", users_id);
1262   incremental_before(USERS_TABLE, buffer, 0);
1263   nstatus = 2;
1264   if (ostatus == 5 || ostatus == 6)
1265     nstatus = 1;
1266   EXEC SQL UPDATE users SET login = :login, status = :nstatus,
1267     modtime = SYSDATE, modby = :who, modwith = :entity, potype = 'POP',
1268     pop_id = :mid, pmodtime = SYSDATE, pmodby = :who, pmodwith = :entity
1269     WHERE users_id = :users_id;
1270
1271   if (dbms_errno)
1272     return mr_errcode;
1273   if (sqlca.sqlerrd[2] != 1)
1274     return MR_INTERNAL;
1275   set_pop_usage(mid, 1);
1276   com_err(whoami, 0, "set login name to %s and pobox to %s", login,
1277           strtrim(machname));
1278   incremental_after(USERS_TABLE, buffer, 0);
1279
1280   if (m_id == 0)
1281     {
1282       /* Cell Name (I know, it shouldn't be hard coded...) */
1283       strcpy(machname, "ATHENA.MIT.EDU");
1284       EXEC SQL SELECT mach_id INTO :m_id FROM machine
1285         WHERE name = :machname;
1286     }
1287
1288   EXEC SQL SELECT list_id INTO :list_id FROM list
1289     WHERE name = 'wheel';
1290
1291   /* create filesystem */
1292   if (set_next_object_id("filsys_id", FILESYS_TABLE, 0))
1293     return MR_NO_ID;
1294   incremental_clear_before();
1295   if (islower(login[0]) && islower(login[1]))
1296     {
1297       sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
1298               login[0], login[1], login);
1299     }
1300   else
1301     sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
1302
1303   EXEC SQL SELECT value INTO :fsidval FROM numvalues
1304     WHERE numvalues.name = 'filsys_id';
1305   EXEC SQL INSERT INTO filesys
1306     (filsys_id, phys_id, label, type, mach_id, name,
1307      mount, rwaccess, comments, owner, owners, createflg,
1308      lockertype, modtime, modby, modwith)
1309     VALUES
1310     (:fsidval, 0, :login, 'AFS', :m_id, :directory,
1311      '/mit/' || :login, 'w', 'User Locker', :users_id, :list_id, 1,
1312      'HOMEDIR', SYSDATE, :who, :entity);
1313
1314   if (dbms_errno)
1315     return mr_errcode;
1316   if (sqlca.sqlerrd[2] != 1)
1317     return MR_INTERNAL;
1318   sprintf(buffer, "fs.filsys_id = %d", fsidval);
1319   incremental_after(FILESYS_TABLE, buffer, 0);
1320
1321   /* set quota */
1322   if (def_quota == 0)
1323     {
1324       EXEC SQL SELECT value INTO :def_quota FROM numvalues
1325         WHERE name = 'def_quota';
1326       if (dbms_errno)
1327         return mr_errcode;
1328       if (sqlca.sqlerrd[2] != 1)
1329         return MR_NO_QUOTA;
1330     }
1331   incremental_clear_before();
1332   EXEC SQL INSERT INTO quota
1333     (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
1334     VALUES (0, :fsidval, 'ANY', :def_quota, 0, SYSDATE, :who, :entity);
1335   if (dbms_errno)
1336     return mr_errcode;
1337   if (sqlca.sqlerrd[2] != 1)
1338     return MR_INTERNAL;
1339   aargv[0] = login;
1340   aargv[1] = "ANY";
1341   aargv[2] = login;
1342   sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'",
1343           fsidval);
1344   incremental_after(QUOTA_TABLE, buffer, aargv);
1345   com_err(whoami, 0, "quota of %d assigned", def_quota);
1346   if (dbms_errno)
1347     return mr_errcode;
1348
1349   cache_entry(login, USERS_TABLE, users_id);
1350
1351   EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = SYSDATE
1352     WHERE table_name = 'users';
1353   EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = SYSDATE
1354     WHERE table_name = 'filesys' OR table_name = 'quota';
1355   if (dbms_errno)
1356     return mr_errcode;
1357   return MR_SUCCESS;
1358 }
1359
1360
1361
1362 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
1363  **
1364  ** Inputs:
1365  **   id of machine
1366  **   delta (will be +/- 1)
1367  **
1368  ** Description:
1369  **   - incr/decr value field in serverhosts table for pop/mach_id
1370  **
1371  **/
1372
1373 int set_pop_usage(id, cnt)
1374     int id, cnt;
1375 {
1376   EXEC SQL BEGIN DECLARE SECTION;
1377   int iid = id, icnt = cnt;
1378   EXEC SQL END DECLARE SECTION;
1379
1380   EXEC SQL UPDATE serverhosts SET value1 = value1 + :icnt
1381     WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :iid;
1382
1383   if (dbms_errno)
1384     return mr_errcode;
1385   return MR_SUCCESS;
1386 }
1387
This page took 0.147267 seconds and 5 git commands to generate.