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