added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / mibII / mta_sendmail.c
1 /*
2  *  MTA-MIB implementation for sendmail - mibII/mta_sendmail.c
3  *  Christoph Mammitzsch <Christoph.Mammitzsch@tu-clausthal.de>
4  *
5  * todo: put queue directory into description?
6  *
7  *  13.02.2002:
8  *    - support sendmail 8.12 queue groups
9  *
10  *
11  *  05.04.2000:
12  *
13  *    - supports sendmail 8.10.0 statistics files now
14  *    - function read_option has been removed
15  *
16  *  12.04.2000:
17  *
18  *    - renamed configuration tokens:
19  *        sendmail config        -> sendmail_config
20  *        sendmail stats         -> sendmail_stats
21  *        sendmail queue         -> sendmail_queue
22  *        sendmail index         -> sendmail_index
23  *        sendmail statcachetime -> sendmail_stats_t
24  *        sendmail dircacetime   -> sendmail_queue_t
25  *
26  *    - now using snmpd_register_config_handler instead of config_parse_dot_conf
27  *
28  *  15.04.2000:
29  *
30  *    - introduced new function print_error
31  *    - changed open_sendmailst and read_sendmailcf to use the new function
32  *    - changed calls to open_sendmailst and read_sendmailcf
33  *    - added some error handling to calls to chdir(), close() and closedir()
34  *
35  */
36
37
38 /** "include files" */
39 #ifdef __lint
40 # define SNMP_NO_DEBUGGING 1    /* keeps lint from complaining about the DEBUGMSG* macros */
41 #endif
42
43 #include <net-snmp/net-snmp-config.h>
44
45 #include <net-snmp/net-snmp-includes.h>
46 #include <net-snmp/agent/net-snmp-agent-includes.h>
47
48 #include "mta_sendmail.h"
49
50 #include <sys/types.h>
51
52 #include <stdio.h>
53
54 #include <ctype.h>
55
56 #ifdef HAVE_STRING_H
57 # include <string.h>
58 #else
59 # include <strings.h>
60 #endif
61
62 #if HAVE_STDLIB_H
63 #include <stdlib.h>
64 #endif
65
66 #ifdef HAVE_UNISTD_H
67 # include <unistd.h>
68 #endif
69
70 #ifdef HAVE_FCNTL_H
71 # include <fcntl.h>
72 #endif
73
74 #if HAVE_DIRENT_H
75 #include <dirent.h>
76 #else
77 # define dirent direct
78 # if HAVE_SYS_NDIR_H
79 #  include <sys/ndir.h>
80 # endif
81 # if HAVE_SYS_DIR_H
82 #  include <sys/dir.h>
83 # endif
84 # if HAVE_NDIR_H
85 #  include <ndir.h>
86 # endif
87 #endif
88
89 #ifdef HAVE_SYS_STAT_H
90 # include <sys/stat.h>
91 #endif
92
93 #if TIME_WITH_SYS_TIME
94 # include <sys/time.h>
95 # include <time.h>
96 #else
97 # if HAVE_SYS_TIME_H
98 #  include <sys/time.h>
99 # else
100 #  include <time.h>
101 # endif
102 #endif
103
104 #if HAVE_STDARG_H
105 #include <stdarg.h>
106 #else
107 #include <varargs.h>
108 #endif
109
110 #include <errno.h>
111
112  /**/
113 /** "macros and variables for registering the OID tree" */
114     /*
115      * prefix for all OIDs 
116      */
117
118 static FindVarMethod var_mtaEntry;
119 static FindVarMethod var_mtaGroupEntry;
120
121 static oid      mta_variables_oid[] = { 1, 3, 6, 1, 2, 1, 28 };
122
123 /*
124  * bits that indicate what's needed to compute the value 
125  */
126 #define   NEEDS_STATS   (1 << 6)
127 #define   NEEDS_DIR     (1 << 7)
128 #define   NEEDS         (NEEDS_STATS | NEEDS_DIR)
129
130 /*
131  * symbolic names for the magic values 
132  */
133 enum {
134     MTARECEIVEDMESSAGES = 3 | NEEDS_STATS,
135     MTASTOREDMESSAGES = 4 | NEEDS_DIR,
136     MTATRANSMITTEDMESSAGES = 5 | NEEDS_STATS,
137     MTARECEIVEDVOLUME = 6 | NEEDS_STATS,
138     MTASTOREDVOLUME = 7 | NEEDS_DIR,
139     MTATRANSMITTEDVOLUME = 8 | NEEDS_STATS,
140     MTAGROUPSTOREDMESSAGES = 17 | NEEDS_DIR,
141     MTAGROUPSTOREDVOLUME = 18 | NEEDS_DIR,
142     MTAGROUPRECEIVEDMESSAGES = 19 | NEEDS_STATS,
143     MTAGROUPREJECTEDMESSAGES = 20 | NEEDS_STATS,
144     MTAGROUPTRANSMITTEDMESSAGES = 22 | NEEDS_STATS,
145     MTAGROUPRECEIVEDVOLUME = 23 | NEEDS_STATS,
146     MTAGROUPTRANSMITTEDVOLUME = 25 | NEEDS_STATS,
147     MTAGROUPNAME = 43,
148     MTAGROUPHIERARCHY = 49,
149 };
150
151 /*
152  * structure that tells the agent, which function returns what values 
153  */
154 static struct variable3 mta_variables[] = {
155     {MTARECEIVEDMESSAGES, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 1}},
156     {MTASTOREDMESSAGES, ASN_GAUGE, RONLY, var_mtaEntry, 3, {1, 1, 2}},
157     {MTATRANSMITTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaEntry, 3,
158      {1, 1, 3}},
159     {MTARECEIVEDVOLUME, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 4}},
160     {MTASTOREDVOLUME, ASN_GAUGE, RONLY, var_mtaEntry, 3, {1, 1, 5}},
161     {MTATRANSMITTEDVOLUME, ASN_COUNTER, RONLY, var_mtaEntry, 3, {1, 1, 6}},
162
163     {MTAGROUPRECEIVEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
164      {2, 1, 2}},
165     {MTAGROUPREJECTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
166      {2, 1, 3}},
167     {MTAGROUPSTOREDMESSAGES, ASN_GAUGE, RONLY, var_mtaGroupEntry, 3,
168      {2, 1, 4}},
169     {MTAGROUPTRANSMITTEDMESSAGES, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
170      {2, 1, 5}},
171     {MTAGROUPRECEIVEDVOLUME, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
172      {2, 1, 6}},
173     {MTAGROUPSTOREDVOLUME, ASN_GAUGE, RONLY, var_mtaGroupEntry, 3,
174      {2, 1, 7}},
175     {MTAGROUPTRANSMITTEDVOLUME, ASN_COUNTER, RONLY, var_mtaGroupEntry, 3,
176      {2, 1, 8}},
177     {MTAGROUPNAME, ASN_OCTET_STR, RONLY, var_mtaGroupEntry, 3, {2, 1, 25}},
178     {MTAGROUPHIERARCHY, ASN_INTEGER, RONLY, var_mtaGroupEntry, 3,
179      {2, 1, 31}},
180 };
181  /**/
182 /** "other macros and structures" */
183     /*
184      * for boolean values 
185      */
186 #ifndef FALSE
187 #define FALSE 0
188 #endif
189 #ifndef TRUE
190 #define TRUE  1
191 #endif
192 #ifndef BOOL
193 #define BOOL  short
194 #endif
195     /*
196      * important constants 
197      */
198 #define FILENAMELEN     200     /* maximum length for filenames */
199 #define MAXMAILERS       25     /* maximum number of mailers (copied from the sendmail sources) */
200 #define MAXQUEUEGROUPS   50     /* maximum # of queue groups (copied from sendmail) */
201 #define MNAMELEN         20     /* maximum length of mailernames (copied from the sendmail sources) */
202 #define STAT_VERSION_8_9  2     /* version of sendmail V8.9.x statistics files (copied from the sendmail sources) */
203 #define STAT_VERSION_8_10 3     /* version of sendmail V8.10.x statistics files (copied from the sendmail sources) */
204 #define STAT_MAGIC  0x1B1DE     /* magic value to identify statistics files from sendmail V8.9.x or higher (copied from the sendmail sources) */
205     /*
206      * structure of sendmail.st file from sendmail V8.10.x (copied from the sendmail sources) 
207      */
208     struct statisticsV8_10 {
209     int             stat_magic; /* magic number */
210     int             stat_version;       /* stat file version */
211     time_t          stat_itime; /* file initialization time */
212     short           stat_size;  /* size of this structure */
213     long            stat_cf;    /* # from connections */
214     long            stat_ct;    /* # to connections */
215     long            stat_cr;    /* # rejected connections */
216     long            stat_nf[MAXMAILERS];        /* # msgs from each mailer */
217     long            stat_bf[MAXMAILERS];        /* kbytes from each mailer */
218     long            stat_nt[MAXMAILERS];        /* # msgs to each mailer */
219     long            stat_bt[MAXMAILERS];        /* kbytes to each mailer */
220     long            stat_nr[MAXMAILERS];        /* # rejects by each mailer */
221     long            stat_nd[MAXMAILERS];        /* # discards by each mailer */
222 };
223
224 /*
225  * structure of sendmail.st file from sendmail V8.9.x (copied from the sendmail sources) 
226  */
227 struct statisticsV8_9 {
228     int             stat_magic; /* magic number */
229     int             stat_version;       /* stat file version */
230     time_t          stat_itime; /* file initialization time */
231     short           stat_size;  /* size of this structure */
232     long            stat_nf[MAXMAILERS];        /* # msgs from each mailer */
233     long            stat_bf[MAXMAILERS];        /* kbytes from each mailer */
234     long            stat_nt[MAXMAILERS];        /* # msgs to each mailer */
235     long            stat_bt[MAXMAILERS];        /* kbytes to each mailer */
236     long            stat_nr[MAXMAILERS];        /* # rejects by each mailer */
237     long            stat_nd[MAXMAILERS];        /* # discards by each mailer */
238 };
239
240 /*
241  * structure of sendmail.st file from sendmail V8.8.x (copied from the sendmail sources) 
242  */
243 struct statisticsV8_8 {
244     time_t          stat_itime; /* file initialization time */
245     short           stat_size;  /* size of this structure */
246     long            stat_nf[MAXMAILERS];        /* # msgs from each mailer */
247     long            stat_bf[MAXMAILERS];        /* kbytes from each mailer */
248     long            stat_nt[MAXMAILERS];        /* # msgs to each mailer */
249     long            stat_bt[MAXMAILERS];        /* kbytes to each mailer */
250 };
251  /**/
252     /*
253      * queue groups (strictly a sendmail 8.12+ thing 
254      */
255     struct QDir {
256     char            dir[FILENAMELEN + 1];
257     struct QDir    *next;
258 };
259
260 struct QGrp {
261     char           *name;       /* name of queuegroup */
262
263     time_t          last;       /* last time we counted */
264     int             count;      /* # of files */
265     int             size;       /* size of files */
266
267     struct QDir    *dirs;       /* directories in queue group */
268 };
269
270 /** "static variables" */
271
272 /*
273  * a list of all the queue groups, NULL terminated 
274  */
275 static struct QGrp qgrps[MAXQUEUEGROUPS];
276 static int      nqgrps = 0;
277
278 static char     sendmailst_fn[FILENAMELEN + 1]; /* name of statistics file */
279 static int      sendmailst_fh = -1;     /* filehandle for statistics file */
280 static char     sendmailcf_fn[FILENAMELEN + 1]; /* name of sendmails config file */
281 static char     mailernames[MAXMAILERS][MNAMELEN + 1];  /* array of mailer names */
282 static int      mailers = MAXMAILERS;   /* number of mailer names in array */
283
284 static long    *stat_nf;        /* pointer to stat_nf array within the statistics structure */
285 static long    *stat_bf;        /* pointer to stat_bf array within the statistics structure */
286 static long    *stat_nt;        /* pointer to stat_nt array within the statistics structure */
287 static long    *stat_bt;        /* pointer to stat_bt array within the statistics structure */
288 static long    *stat_nr;        /* pointer to stat_nr array within the statistics structure,
289                                  * only valid for statistics files from sendmail >=V8.9.0    */
290 static long    *stat_nd;        /* pointer to stat_nd array within the statistics structure,
291                                  * only valid for statistics files from sendmail >=V8.9.0    */
292 static int      stats_size;     /* size of statistics structure */
293 static long     stats[sizeof(struct statisticsV8_10) / sizeof(long) + 1];       /* buffer for statistics structure */
294 static time_t   lastreadstats;  /* time stats file has been read */
295 static long     applindex = 1;  /* ApplIndex value for OIDs */
296 static long     stat_cache_time = 5;    /* time (in seconds) to wait before reading stats file again */
297 static long     dir_cache_time = 10;    /* time (in seconds) to wait before scanning queue directoy again */
298
299  /**/
300 /** static void print_error(int priority, BOOL config, BOOL config_only, char *function, char *format, ...)
301  *
302  *  Description:
303  *
304  *    Called to print errors. It uses the config_perror or the snmp_log function
305  *    depending on whether the config parameter is TRUE or FALSE.
306  *
307  *  Parameters:
308  *
309  *    priority:    priority to be used when calling the snmp_log function
310  *
311  *    config:      indicates whether this function has been called during the
312  *                 configuration process or not. If set to TRUE, the function
313  *                 config_perror will be used to report the error.
314  *
315  *    config_only: if set to TRUE, the error will only be printed when function
316  *                 has been called during the configuration process.
317  *
318  *    function:    name of the calling function. Used when printing via snmp_log.
319  *
320  *    format:      format string for the error message
321  *
322  *    ...:         additional parameters to insert into the error message string
323  *
324  */
325 #if HAVE_STDARG_H
326     static void
327 print_error(int priority, BOOL config, BOOL config_only,
328             const char *function, const char *format, ...)
329 #else
330     static void
331 print_error(va_alist)
332      va_dcl
333 #endif
334 {
335     va_list         ap;
336     char            buffer[2 * FILENAMELEN + 200];      /* I know, that's not perfectly safe, but since I don't use more
337                                                          * than two filenames in one error message, that should be enough */
338
339 #if HAVE_STDARG_H
340     va_start(ap, format);
341 #else
342     int             priority;
343     BOOL            config;
344     BOOL            config_only;
345     const char     *function;
346     const char     *format;
347
348     va_start(ap);
349     priority = va_arg(ap, int);
350     config = va_arg(ap, BOOL);
351     config_only = va_arg(ap, BOOL);
352     function = va_arg(ap, char *);
353     format = va_arg(ap, char *);
354 #endif
355
356     vsnprintf(buffer, sizeof(buffer), format, ap);
357
358     if (config) {
359         config_perror(buffer);
360     } else if (!config_only) {
361         snmp_log(priority, "%s: %s\n", function, buffer);
362     }
363     va_end(ap);
364 }
365
366  /**/
367 /** static void open_sendmailst(BOOL config)
368  *
369  *  Description:
370  *
371  *    Closes old sendmail.st file, then tries to open the new sendmail.st file
372  *    and guess it's version. If it succeeds, it initializes the stat_*
373  *    pointers and the stats_size variable.
374  *
375  *  Parameters:
376  *
377  *    config: TRUE if function has been called during the configuration process
378  *
379  *  Returns:
380  *
381  *    nothing
382  *
383  */
384     static void
385 open_sendmailst(BOOL config)
386 {
387     int             filelen;
388
389     if (sendmailst_fh != -1) {
390         while (close(sendmailst_fh) == -1 && errno == EINTR) {
391             /*
392              * do nothing 
393              */
394         }
395     }
396
397     sendmailst_fh = open(sendmailst_fn, O_RDONLY);
398
399     if (sendmailst_fh == -1) {
400         print_error(LOG_ERR, config, TRUE,
401                     "mibII/mta_sendmail.c:open_sendmailst",
402                     "could not open file \"%s\"\n", sendmailst_fn);
403         return;
404     }
405
406     filelen = read(sendmailst_fh, (void *) &stats, sizeof stats);
407
408     if (((struct statisticsV8_10 *) stats)->stat_magic == STAT_MAGIC) {
409         if (((struct statisticsV8_10 *) stats)->stat_version ==
410             STAT_VERSION_8_10
411             && ((struct statisticsV8_10 *) stats)->stat_size ==
412             sizeof(struct statisticsV8_10)
413             && filelen == sizeof(struct statisticsV8_10)) {
414             DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
415                         "looks like file \"%s\" has been created by sendmail V8.10.0 or newer\n",
416                         sendmailst_fn));
417             stat_nf = (((struct statisticsV8_10 *) stats)->stat_nf);
418             stat_bf = (((struct statisticsV8_10 *) stats)->stat_bf);
419             stat_nt = (((struct statisticsV8_10 *) stats)->stat_nt);
420             stat_bt = (((struct statisticsV8_10 *) stats)->stat_bt);
421             stat_nr = (((struct statisticsV8_10 *) stats)->stat_nr);
422             stat_nd = (((struct statisticsV8_10 *) stats)->stat_nd);
423             stats_size = sizeof(struct statisticsV8_10);
424         } else if (((struct statisticsV8_9 *) stats)->stat_version ==
425                    STAT_VERSION_8_9
426                    && ((struct statisticsV8_9 *) stats)->stat_size ==
427                    sizeof(struct statisticsV8_9)
428                    && filelen == sizeof(struct statisticsV8_9)) {
429             DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
430                         "looks like file \"%s\" has been created by sendmail V8.9.x\n",
431                         sendmailst_fn));
432             stat_nf = (((struct statisticsV8_9 *) stats)->stat_nf);
433             stat_bf = (((struct statisticsV8_9 *) stats)->stat_bf);
434             stat_nt = (((struct statisticsV8_9 *) stats)->stat_nt);
435             stat_bt = (((struct statisticsV8_9 *) stats)->stat_bt);
436             stat_nr = (((struct statisticsV8_9 *) stats)->stat_nr);
437             stat_nd = (((struct statisticsV8_9 *) stats)->stat_nd);
438             stats_size = sizeof(struct statisticsV8_9);
439         } else {
440             print_error(LOG_WARNING, config, FALSE,
441                         "mibII/mta_sendmail.c:open_sendmailst",
442                         "could not guess version of statistics file \"%s\"\n",
443                         sendmailst_fn);
444             while (close(sendmailst_fh) == -1 && errno == EINTR) {
445                 /*
446                  * do nothing 
447                  */
448             }
449             sendmailst_fh = -1;
450         }
451     } else {
452         if (((struct statisticsV8_8 *) stats)->stat_size ==
453             sizeof(struct statisticsV8_8)
454             && filelen == sizeof(struct statisticsV8_8)) {
455             DEBUGMSGTL(("mibII/mta_sendmail.c:open_sendmailst",
456                         "looks like file \"%s\" has been created by sendmail V8.8.x\n",
457                         sendmailst_fn));
458             stat_nf = (((struct statisticsV8_8 *) stats)->stat_nf);
459             stat_bf = (((struct statisticsV8_8 *) stats)->stat_bf);
460             stat_nt = (((struct statisticsV8_8 *) stats)->stat_nt);
461             stat_bt = (((struct statisticsV8_8 *) stats)->stat_bt);
462             stat_nr = (long *) NULL;
463             stat_nd = (long *) NULL;
464             stats_size = sizeof(struct statisticsV8_8);
465         } else {
466             print_error(LOG_WARNING, config, FALSE,
467                         "mibII/mta_sendmail.c:open_sendmailst",
468                         "could not guess version of statistics file \"%s\"\n",
469                         sendmailst_fn);
470             while (close(sendmailst_fh) == -1 && errno == EINTR) {
471                 /*
472                  * do nothing 
473                  */
474             }
475             sendmailst_fh = -1;
476         }
477     }
478 }
479
480  /**/ static void
481 count_queuegroup(struct QGrp *qg)
482 {
483     struct QDir    *d;
484     char            cwd[200];
485     time_t          current_time = time(NULL);
486
487     if (current_time <= (qg->last + dir_cache_time)) {
488         return;
489     }
490
491     if (getcwd(cwd, sizeof cwd) == NULL) {
492         snmp_log(LOG_ERR,
493                  "mibII/mta_sendmail.c:count_queuegroup: could not get current working directory\n");
494         return;
495     }
496
497     qg->count = 0;
498     qg->size = 0;
499
500     for (d = qg->dirs; d != NULL; d = d->next) {
501         DIR            *dp;
502         struct dirent  *dirp;
503         struct stat     filestat;
504
505         if (chdir(d->dir) != 0)
506             continue;
507         dp = opendir(".");
508         if (dp == NULL)
509             continue;
510         while ((dirp = readdir(dp)) != NULL) {
511             if (dirp->d_name[0] == 'd' && dirp->d_name[1] == 'f') {
512                 if (stat(dirp->d_name, &filestat) == 0) {
513                     qg->size += (filestat.st_size + 999) / 1000;
514                 }
515             } else if (dirp->d_name[0] == 'q' && dirp->d_name[1] == 'f') {
516                 qg->count++;
517             }
518         }
519         closedir(dp);
520     }
521
522     qg->last = current_time;
523
524     chdir(cwd);
525 }
526
527 /** static void add_queuegroup(const char *name, const char *path)
528  *
529  * Description:
530  *
531  *   Adds a queuegroup of 'name' with root path 'path' to the static
532  *   list of queue groups.  if 'path' ends in a *, we expand it out to
533  *   all matching subdirs.  also look for 'qf' subdirectories.
534  *
535  * Parameters:
536  *
537  *   qgname: name of the queuegroup discovered
538  *   path: path of queuegroup discovered
539  */
540 static void
541 add_queuegroup(const char *name, char *path)
542 {
543     char            parentdir[FILENAMELEN];
544     char           *p;
545     struct QDir    *new = NULL;
546     struct QDir    *subdir = NULL;
547     DIR            *dp;
548     struct dirent  *dirp;
549
550     if (nqgrps == MAXQUEUEGROUPS) {
551         /*
552          * xxx error 
553          */
554         return;
555     }
556
557     if (strlen(path) > FILENAMELEN - 10) {
558         /*
559          * xxx error 
560          */
561         return;
562     }
563
564     p = path + strlen(path) - 1;
565     if (*p == '*') {            /* multiple queue dirs */
566         /*
567          * remove * 
568          */
569         *p = '\0';
570
571         strcpy(parentdir, path);
572         /*
573          * remove last directory component from parentdir 
574          */
575         for (p = parentdir + strlen(parentdir) - 1; p >= parentdir; p--) {
576             if (*p == '/') {
577                 *p = '\0';
578                 break;
579             }
580         }
581
582         if (p < parentdir) {
583             /*
584              * no trailing / ?!? 
585              */
586
587             /*
588              * xxx error 
589              */
590             return;
591         }
592         p++;
593
594         /*
595          * p is now the prefix we need to match 
596          */
597         if ((dp = opendir(parentdir)) == NULL) {
598             /*
599              * xxx can't open parentdir 
600              */
601             return;
602         }
603
604         while ((dirp = readdir(dp)) != NULL) {
605             if (!strncmp(dirp->d_name, p, strlen(p)) &&
606                 dirp->d_name[0] != '.') {
607                 /*
608                  * match, add it to the list 
609                  */
610
611                 /*
612                  * single queue directory 
613                  */
614                 subdir = (struct QDir *) malloc(sizeof(struct QDir));
615                 snprintf(subdir->dir, FILENAMELEN - 5, "%s/%s", parentdir,
616                          dirp->d_name);
617                 subdir->next = new;
618                 new = subdir;
619             }
620         }
621
622         closedir(dp);
623     } else {
624         /*
625          * single queue directory 
626          */
627         new = (struct QDir *) malloc(sizeof(struct QDir));
628         strcpy(new->dir, path);
629         new->next = NULL;
630     }
631
632     /*
633      * check 'new' for /qf directories 
634      */
635     for (subdir = new; subdir != NULL; subdir = subdir->next) {
636         char            qf[FILENAMELEN + 1];
637
638         snprintf(qf, FILENAMELEN, "%s/qf", subdir->dir);
639         if ((dp = opendir(qf)) != NULL) {
640             /*
641              * it exists ! 
642              */
643             strcpy(subdir->dir, qf);
644             closedir(dp);
645         }
646     }
647
648     /*
649      * we now have the list of directories in 'new'; create the queuegroup
650      * object 
651      */
652     qgrps[nqgrps].name = strdup(name);
653     qgrps[nqgrps].last = 0;
654     qgrps[nqgrps].count = 0;
655     qgrps[nqgrps].size = 0;
656     qgrps[nqgrps].dirs = new;
657
658     nqgrps++;
659 }
660
661 /** static BOOL read_sendmailcf(BOOL config)
662  *
663  *  Description:
664  *
665  *    Tries to open the file named in sendmailcf_fn and to get the names of
666  *    the mailers, the status file and the mailqueue directories.
667  *
668  *  Parameters:
669  *
670  *    config: TRUE if function has been called during the configuration process
671  *
672  *  Returns:
673  *
674  *    TRUE  : config file has been successfully opened
675  *
676  *    FALSE : could not open config file
677  *
678  */
679
680 static BOOL
681 read_sendmailcf(BOOL config)
682 {
683     FILE           *sendmailcf_fp;
684     char            line[500];
685     char           *filename;
686     char           *qgname, *p;
687     int             linenr;
688     int             linelen;
689     int             found_sendmailst = FALSE;
690     int             i;
691
692
693     sendmailcf_fp = fopen(sendmailcf_fn, "r");
694     if (sendmailcf_fp == NULL) {
695         print_error(LOG_ERR, config, TRUE,
696                     "mibII/mta_sendmail.c:read_sendmailcf",
697                     "could not open file \"%s\"\n", sendmailcf_fn);
698         return FALSE;
699     }
700
701     /*
702      * initializes the standard mailers, which aren't necessarily mentioned in the sendmail.cf file 
703      */
704     strcpy(mailernames[0], "prog");
705     strcpy(mailernames[1], "*file*");
706     strcpy(mailernames[2], "*include*");
707     mailers = 3;
708
709     /*
710      * reset queuegroups 
711      */
712
713     linenr = 1;
714     while (fgets(line, sizeof line, sendmailcf_fp) != NULL) {
715         linelen = strlen(line);
716
717         if (line[linelen - 1] != '\n') {
718             print_error(LOG_WARNING, config, FALSE,
719                         "mibII/mta_sendmail.c:read_sendmailcf",
720                         "line %d in config file \"%s\" is too long\n",
721                         linenr, sendmailcf_fn);
722             while (fgets(line, sizeof line, sendmailcf_fp) != NULL && line[strlen(line) - 1] != '\n') { /* skip rest of the line */
723                 /*
724                  * nothing to do 
725                  */
726             }
727             linenr++;
728             continue;
729         }
730
731         line[--linelen] = '\0';
732
733         switch (line[0]) {
734
735         case 'M':
736
737             if (mailers < MAXMAILERS) {
738                 for (i = 1;
739                      line[i] != ',' && !isspace(line[i]) && line[i] != '\0'
740                      && i <= MNAMELEN; i++) {
741                     mailernames[mailers][i - 1] = line[i];
742                 }
743                 mailernames[mailers][i - 1] = '\0';
744
745                 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
746                             "found mailer \"%s\"\n",
747                             mailernames[mailers]));
748
749                 for (i = 0;
750                      i < mailers
751                      && strcmp(mailernames[mailers], mailernames[i]) != 0;
752                      i++) {
753                     /*
754                      * nothing to do 
755                      */
756                 }
757
758                 if (i == mailers) {
759                     mailers++;
760                 } else {
761                     if (i < 3) {
762                         DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
763                                     "mailer \"%s\" already existed, but since it's one of the predefined mailers, that's probably nothing to worry about\n",
764                                     mailernames[mailers]));
765                     } else {
766                         DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
767                                     "mailer \"%s\" already existed\n",
768                                     mailernames[mailers]));
769                     }
770                     mailernames[mailers][0] = '\0';
771                 }
772             } else {
773                 print_error(LOG_WARNING, config, FALSE,
774                             "mibII/mta_sendmail.c:read_sendmailcf",
775                             "found too many mailers in config file \"%s\"\n",
776                             sendmailcf_fn);
777             }
778
779
780             break;
781
782         case 'O':
783             switch (line[1]) {
784             case ' ':
785                 /*
786                  * long option 
787                  */
788                 if (strncasecmp(line + 2, "StatusFile", 10) == 0) {
789                     filename = line + 12;
790                 } else if (strncasecmp(line + 2, "QueueDirectory", 14) ==
791                            0) {
792                     filename = line + 16;
793                 } else {
794                     /*
795                      * not an option we care about 
796                      */
797                     break;
798                 }
799
800                 /*
801                  * make sure it's the end of the option 
802                  */
803                 if (*filename != ' ' && *filename != '=')
804                     break;
805
806                 /*
807                  * skip WS 
808                  */
809                 while (*filename == ' ')
810                     filename++;
811
812                 /*
813                  * must be O <option> = <file> 
814                  */
815                 if (*filename++ != '=') {
816                     print_error(LOG_WARNING, config, FALSE,
817                                 "mibII/mta_sendmail.c:read_sendmailcf",
818                                 "line %d in config file \"%s\" ist missing an '='\n",
819                                 linenr, sendmailcf_fn);
820                     break;
821                 }
822
823                 /*
824                  * skip WS 
825                  */
826                 while (*filename == ' ')
827                     filename++;
828
829                 if (strlen(filename) > FILENAMELEN) {
830                     print_error(LOG_WARNING, config, FALSE,
831                                 "mibII/mta_sendmail.c:read_sendmailcf",
832                                 "line %d config file \"%s\" contains a filename that's too long\n",
833                                 linenr, sendmailcf_fn);
834                     break;
835                 }
836
837                 if (strncasecmp(line + 2, "StatusFile", 10) == 0) {
838                     strncpy(sendmailst_fn, filename, sizeof(sendmailst_fn));
839                     sendmailst_fn[ sizeof(sendmailst_fn)-1 ] = 0;
840                     found_sendmailst = TRUE;
841                     DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
842                                 "found statatistics file \"%s\"\n",
843                                 sendmailst_fn));
844                 } else if (strncasecmp(line + 2, "QueueDirectory", 14) ==
845                            0) {
846                     add_queuegroup("mqueue", filename);
847                 } else {
848                     print_error(LOG_CRIT, config, FALSE,
849                                 "mibII/mta_sendmail.c:read_sendmailcf",
850                                 "This shouldn't happen.\n");
851                     abort();
852                 }
853                 break;
854
855             case 'S':
856                 if (strlen(line + 2) > FILENAMELEN) {
857                     print_error(LOG_WARNING, config, FALSE,
858                                 "mibII/mta_sendmail.c:read_sendmailcf",
859                                 "line %d config file \"%s\" contains a filename that's too long\n",
860                                 linenr, sendmailcf_fn);
861                     break;
862                 }
863                 strcpy(sendmailst_fn, line + 2);
864                 found_sendmailst = TRUE;
865                 DEBUGMSGTL(("mibII/mta_sendmail.c:read_sendmailcf",
866                             "found statatistics file \"%s\"\n",
867                             sendmailst_fn));
868                 break;
869
870             case 'Q':
871                 if (strlen(line + 2) > FILENAMELEN) {
872                     print_error(LOG_WARNING, config, FALSE,
873                                 "mibII/mta_sendmail.c:read_sendmailcf",
874                                 "line %d config file \"%s\" contains a filename that's too long\n",
875                                 linenr, sendmailcf_fn);
876                     break;
877                 }
878
879                 add_queuegroup("mqueue", line + 2);
880                 break;
881             }
882             break;
883
884         case 'Q':
885             /*
886              * found a queue group 
887              */
888             p = qgname = line + 1;
889             while (*p && *p != ',') {
890                 p++;
891             }
892             if (*p == '\0') {
893                 print_error(LOG_WARNING, config, FALSE,
894                             "mibII/mta_sendmail.c:read_sendmailcf",
895                             "line %d config file \"%s\" contains a weird queuegroup\n",
896                             linenr, sendmailcf_fn);
897                 break;
898             }
899
900             /*
901              * look for the directory 
902              */
903             filename = NULL;
904             *p++ = '\0';
905             while (*p != '\0') {
906                 /*
907                  * skip WS 
908                  */
909                 while (*p && *p == ' ')
910                     p++;
911
912                 if (*p == 'P') {        /* found path */
913                     while (*p && *p != '=')
914                         p++;
915                     if (*p++ != '=') {
916                         print_error(LOG_WARNING, config, FALSE,
917                                     "mibII/mta_sendmail.c:read_sendmailcf",
918                                     "line %d config file \"%s\" contains a weird queuegroup\n",
919                                     linenr, sendmailcf_fn);
920                         break;
921                     }
922                     filename = p;
923
924                     /*
925                      * find next ',', turn into \0 
926                      */
927                     while (*p && *p != ',')
928                         p++;
929                     *p = '\0';
930                 }
931
932                 /*
933                  * skip to next , 
934                  */
935                 while (*p && *p != ',')
936                     p++;
937             }
938
939             /*
940              * we found a directory 
941              */
942             if (filename) {
943                 add_queuegroup(qgname, filename);
944             } else {
945                 print_error(LOG_WARNING, config, FALSE,
946                             "mibII/mta_sendmail.c:read_sendmailcf",
947                             "line %d config file \"%s\" contains a weird queuegroup: no directory\n",
948                             linenr, sendmailcf_fn);
949             }
950
951             break;
952         }
953
954         linenr++;
955     }
956
957     for (i = 0; i < 10 && fclose(sendmailcf_fp) != 0; i++) {
958         /*
959          * nothing to do 
960          */
961     }
962
963     for (i = mailers; i < MAXMAILERS; i++) {
964         mailernames[i][0] = '\0';
965     }
966
967     if (found_sendmailst) {
968         open_sendmailst(config);
969     }
970
971     return TRUE;
972 }
973
974  /**/
975 /** static void mta_sendmail_parse_config(const char* token, char *line)
976  *
977  *  Description:
978  *
979  *    Called by the agent for each configuration line that belongs to this module.
980  *    The possible tokens are:
981  *
982  *    sendmail_config  - filename of the sendmail configutarion file
983  *    sendmail_stats   - filename of the sendmail statistics file
984  *    sendmail_queue   - name of the sendmail mailqueue directory
985  *    sendmail_index   - the ApplIndex to use for the table
986  *    sendmail_stats_t - the time (in seconds) to cache statistics
987  *    sendmail_queue_t - the time (in seconds) to cache the directory scanning results
988  *
989  *    For "sendmail_config", "sendmail_stats" and "sendmail_queue", the copy_nword
990  *    function is used to copy the filename.
991  *
992  *  Parameters:
993  *
994  *    token: first word of the line
995  *
996  *    line:  rest of the line
997  *
998  *  Returns:
999  *
1000  *    nothing
1001  *
1002  */
1003     static void
1004 mta_sendmail_parse_config(const char *token, char *line)
1005 {
1006     if (strlen(line) > FILENAMELEN) {   /* Might give some false alarm, but better to be safe than sorry */
1007         config_perror("line too long");
1008         return;
1009     }
1010
1011     if (strcasecmp(token, "sendmail_stats") == 0) {
1012         while (isspace(*line)) {
1013             line++;
1014         }
1015         copy_nword(line, sendmailst_fn, sizeof(sendmailst_fn));
1016
1017         open_sendmailst(TRUE);
1018
1019         if (sendmailst_fh == -1) {
1020             char            str[FILENAMELEN + 50];
1021             sprintf(str, "couldn't open file \"%s\"", sendmailst_fn);
1022             config_perror(str);
1023             return;
1024         }
1025
1026         DEBUGMSGTL(("mibII/mta_sendmail.c:mta_sendmail_parse_config",
1027                     "opened statistics file \"%s\"\n", sendmailst_fn));
1028         return;
1029     } else if (strcasecmp(token, "sendmail_config") == 0) {
1030         while (isspace(*line)) {
1031             line++;
1032         }
1033         copy_nword(line, sendmailcf_fn, sizeof(sendmailcf_fn));
1034
1035         read_sendmailcf(TRUE);
1036
1037         DEBUGMSGTL(("mibII/mta_sendmail.c:mta_sendmail_parse_config",
1038                     "read config file \"%s\"\n", sendmailcf_fn));
1039         return;
1040     } else if (strcasecmp(token, "sendmail_queue") == 0) {
1041         while (isspace(*line)) {
1042             line++;
1043         }
1044         add_queuegroup("mqueue", line);
1045
1046         return;
1047     } else if (strcasecmp(token, "sendmail_index") == 0) {
1048         while (isspace(*line)) {
1049             line++;
1050         }
1051         applindex = atol(line);
1052         if (applindex < 1) {
1053             config_perror("invalid index number");
1054             applindex = 1;
1055         }
1056     } else if (strcasecmp(token, "sendmail_stats_t") == 0) {
1057         while (isspace(*line)) {
1058             line++;
1059         }
1060         stat_cache_time = atol(line);
1061         if (stat_cache_time < 1) {
1062             config_perror("invalid cache time");
1063             applindex = 5;
1064         }
1065     } else if (strcasecmp(token, "sendmail_queue_t") == 0) {
1066         while (isspace(*line)) {
1067             line++;
1068         }
1069         dir_cache_time = atol(line);
1070         if (dir_cache_time < 1) {
1071             config_perror("invalid cache time");
1072             applindex = 10;
1073         }
1074     } else {
1075         config_perror
1076             ("mibII/mta_sendmail.c says: What should I do with that token? Did you ./configure the agent properly?");
1077     }
1078
1079     return;
1080 }
1081
1082  /**/
1083 /** void init_mta_sendmail(void)
1084  *
1085  *  Description:
1086  *
1087  *    Called by the agent to initialize the module. The function will register
1088  *    the OID tree and the config handler and try some default values for the
1089  *    sendmail.cf and sendmail.st files and for the mailqueue directory.
1090  *
1091  *  Parameters:
1092  *
1093  *    none
1094  *
1095  *  Returns:
1096  *
1097  *    nothing
1098  *
1099  */
1100     void
1101 init_mta_sendmail(void)
1102 {
1103     REGISTER_MIB("mibII/mta_sendmail", mta_variables, variable3,
1104                  mta_variables_oid);
1105
1106     snmpd_register_config_handler("sendmail_config",
1107                                   mta_sendmail_parse_config, NULL, "file");
1108     snmpd_register_config_handler("sendmail_stats",
1109                                   mta_sendmail_parse_config, NULL, "file");
1110     snmpd_register_config_handler("sendmail_queue",
1111                                   mta_sendmail_parse_config, NULL,
1112                                   "directory");
1113     snmpd_register_config_handler("sendmail_index",
1114                                   mta_sendmail_parse_config, NULL,
1115                                   "integer");
1116     snmpd_register_config_handler("sendmail_stats_t",
1117                                   mta_sendmail_parse_config, NULL,
1118                                   "cachetime/sec");
1119     snmpd_register_config_handler("sendmail_queue_t",
1120                                   mta_sendmail_parse_config, NULL,
1121                                   "cachetime/sec");
1122
1123     strcpy(sendmailcf_fn, "/etc/mail/sendmail.cf");
1124     if (read_sendmailcf(FALSE) == FALSE) {
1125         strcpy(sendmailcf_fn, "/etc/sendmail.cf");
1126         read_sendmailcf(FALSE);
1127     }
1128
1129     if (sendmailst_fh == -1) {
1130         strcpy(sendmailst_fn, "/etc/mail/statistics");
1131         open_sendmailst(FALSE);
1132         if (sendmailst_fh == -1) {
1133             strcpy(sendmailst_fn, "/etc/mail/sendmail.st");
1134             open_sendmailst(FALSE);
1135         }
1136     }
1137
1138 }
1139
1140  /**/
1141 /** unsigned char *var_mtaEntry(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method)
1142  *
1143  *  Description:
1144  *
1145  *    Called by the agent in order to get the values for the mtaTable.
1146  *
1147  *  Parameters:
1148  *
1149  *    see agent documentation
1150  *
1151  *  Returns:
1152  *
1153  *    see agent documentation
1154  *
1155  */
1156 unsigned char  *
1157 var_mtaEntry(struct variable *vp,
1158              oid * name,
1159              size_t * length,
1160              int exact, size_t * var_len, WriteMethod ** write_method)
1161 {
1162
1163
1164     static long     long_ret;
1165     auto int        i;
1166     auto int        result;
1167     auto time_t     current_time;
1168     int             global_count = 0;
1169     int             global_size = 0;
1170
1171     if (exact) {
1172         if (*length != vp->namelen + 1) {
1173             return NULL;
1174         }
1175         result =
1176             snmp_oid_compare(name, *length - 1, vp->name, vp->namelen);
1177         if (result != 0 || name[*length - 1] != applindex) {
1178             return NULL;
1179         }
1180     } else {
1181         if (*length <= vp->namelen) {
1182             result = -1;
1183         } else {
1184             result =
1185                 snmp_oid_compare(name, *length - 1, vp->name, vp->namelen);
1186         }
1187         if (result > 0) {
1188             return NULL;
1189         }
1190         if (result == 0 && name[*length - 1] >= applindex) {
1191             return NULL;
1192         }
1193         if (result < 0) {
1194             memcpy(name, vp->name, (int) vp->namelen * (int) sizeof *name);
1195             *length = vp->namelen + 1;
1196         }
1197         name[vp->namelen] = applindex;
1198     }
1199
1200     *write_method = (WriteMethod *) NULL;
1201     *var_len = sizeof(long);    /* default to 'long' results */
1202
1203     if (vp->magic & NEEDS_STATS) {
1204         if (sendmailst_fh == -1)
1205             return NULL;
1206         current_time = time(NULL);
1207         if (current_time == (time_t) - 1
1208             || current_time > lastreadstats + stat_cache_time) {
1209             if (lseek(sendmailst_fh, 0, SEEK_SET) == -1) {
1210                 snmp_log(LOG_ERR,
1211                          "mibII/mta_sendmail.c:var_mtaEntry: could not rewind to the beginning of file \"%s\"\n",
1212                          sendmailst_fn);
1213                 return NULL;
1214             }
1215             if (read(sendmailst_fh, (void *) &stats, stats_size) !=
1216                 stats_size) {
1217                 snmp_log(LOG_ERR,
1218                          "mibII/mta_sendmail.c:var_mtaEntry: could not read from statistics file \"%s\"\n",
1219                          sendmailst_fn);
1220                 return NULL;
1221             }
1222             if (current_time != (time_t) - 1) {
1223                 lastreadstats = current_time;
1224             }
1225         }
1226     }
1227
1228     if (vp->magic & NEEDS_DIR) {
1229         global_count = 0;
1230         global_size = 0;
1231         /*
1232          * count all queue group messages 
1233          */
1234         for (i = 0; i < nqgrps; i++) {
1235             count_queuegroup(&qgrps[i]);
1236             global_count += qgrps[i].count;
1237             global_size += qgrps[i].size;
1238         }
1239     }
1240
1241     switch (vp->magic) {
1242
1243     case MTARECEIVEDMESSAGES:
1244
1245         long_ret = 0;
1246         for (i = 0; i < MAXMAILERS; i++) {
1247             long_ret += stat_nf[i];
1248         }
1249         return (unsigned char *) &long_ret;
1250
1251     case MTASTOREDMESSAGES:
1252
1253         long_ret = global_count;
1254         return (unsigned char *) &long_ret;
1255
1256     case MTATRANSMITTEDMESSAGES:
1257
1258         long_ret = 0;
1259         for (i = 0; i < MAXMAILERS; i++) {
1260             long_ret += stat_nt[i];
1261         }
1262         return (unsigned char *) &long_ret;
1263
1264     case MTARECEIVEDVOLUME:
1265
1266         long_ret = 0;
1267         for (i = 0; i < MAXMAILERS; i++) {
1268             long_ret += stat_bf[i];
1269         }
1270         return (unsigned char *) &long_ret;
1271
1272     case MTASTOREDVOLUME:
1273
1274         long_ret = global_size;
1275         return (unsigned char *) &long_ret;
1276
1277     case MTATRANSMITTEDVOLUME:
1278
1279         long_ret = 0;
1280         for (i = 0; i < MAXMAILERS; i++) {
1281             long_ret += stat_bt[i];
1282         }
1283         return (unsigned char *) &long_ret;
1284
1285     default:
1286         snmp_log(LOG_ERR,
1287                  "mibII/mta_sendmail.c:mtaEntry: unknown magic value\n");
1288     }
1289     return NULL;
1290 }
1291
1292  /**/
1293 /** unsigned char *var_mtaGroupEntry(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method)
1294  *
1295  *  Description:
1296  *
1297  *    Called by the agent in order to get the values for the mtaGroupTable.
1298  *
1299  *  Parameters:
1300  *
1301  *    see agent documentation
1302  *
1303  *  Returns:
1304  *
1305  *    see agent documentation
1306  *
1307  */
1308 unsigned char  *
1309 var_mtaGroupEntry(struct variable *vp,
1310                   oid * name,
1311                   size_t * length,
1312                   int exact, size_t * var_len, WriteMethod ** write_method)
1313 {
1314     static long     long_ret;
1315     auto long       row;
1316     auto int        result;
1317     auto time_t     current_time;
1318
1319
1320     if (exact) {
1321         if (*length != vp->namelen + 2) {
1322             return NULL;
1323         }
1324         result =
1325             snmp_oid_compare(name, *length - 2, vp->name, vp->namelen);
1326         if (result != 0 || name[*length - 2] != applindex
1327             || name[*length - 1] <= 0
1328             || name[*length - 1] > mailers + nqgrps) {
1329             return NULL;
1330         }
1331     } else {
1332         if (*length < vp->namelen) {
1333             result = -1;
1334         } else {
1335             result =
1336                 snmp_oid_compare(name, vp->namelen, vp->name, vp->namelen);
1337         }
1338
1339         if (result > 0) {
1340             /*
1341              * OID prefix too large 
1342              */
1343             return NULL;
1344         }
1345
1346         if (result == 0) {
1347             /*
1348              * OID prefix matches exactly,... 
1349              */
1350             if (*length > vp->namelen && name[vp->namelen] > applindex) {
1351                 /*
1352                  * ... but ApplIndex too large 
1353                  */
1354                 return NULL;
1355             }
1356             if (*length > vp->namelen && name[vp->namelen] == applindex) {
1357                 /*
1358                  * ... ApplIndex ok,... 
1359                  */
1360                 if (*length > vp->namelen + 1
1361                     && name[vp->namelen + 1] >= 1) {
1362                     if (name[vp->namelen + 1] >= mailers + nqgrps) {
1363                         /*
1364                          * ... but mailernr too large 
1365                          */
1366                         return NULL;
1367                     } else {
1368                         name[vp->namelen + 1]++;
1369                     }
1370                 } else {
1371                     name[vp->namelen + 1] = 1;
1372                 }
1373             } else {
1374                 name[vp->namelen] = applindex;
1375                 name[vp->namelen + 1] = 1;
1376             }
1377         } else {                /* OID prefix too small */
1378             memcpy(name, vp->name, (int) vp->namelen * (int) sizeof *name);
1379             name[vp->namelen] = applindex;
1380             name[vp->namelen + 1] = 1;
1381         }
1382         *length = vp->namelen + 2;
1383     }
1384
1385     *write_method = 0;
1386     *var_len = sizeof(long);    /* default to 'long' results */
1387
1388     if (vp->magic & NEEDS_STATS) {
1389         if (sendmailst_fh == -1)
1390             return NULL;
1391         current_time = time(NULL);
1392         if (current_time == (time_t) - 1 ||
1393             current_time > lastreadstats + stat_cache_time) {
1394             if (lseek(sendmailst_fh, 0, SEEK_SET) == -1) {
1395                 snmp_log(LOG_ERR,
1396                          "mibII/mta_sendmail.c:var_mtaGroupEntry: could not rewind to beginning of file \"%s\"\n",
1397                          sendmailst_fn);
1398                 return NULL;
1399             }
1400             if (read(sendmailst_fh, (void *) &stats, stats_size) !=
1401                 stats_size) {
1402                 snmp_log(LOG_ERR,
1403                          "mibII/mta_sendmail.c:var_mtaGroupEntry: could not read statistics file \"%s\"\n",
1404                          sendmailst_fn);
1405                 return NULL;
1406             }
1407             if (current_time != (time_t) - 1) {
1408                 lastreadstats = current_time;
1409             }
1410         }
1411     }
1412
1413     row = name[*length - 1] - 1;
1414
1415     /*
1416      * if this is a mailer but we're asking for queue-group only info, 
1417      * bump there 
1418      */
1419     if (!exact && row < mailers && (vp->magic == MTAGROUPSTOREDMESSAGES ||
1420                                     vp->magic == MTAGROUPSTOREDVOLUME)) {
1421         row = mailers;
1422         name[*length - 1] = row + 1;
1423     }
1424
1425     if (row < mailers) {
1426         switch (vp->magic) {
1427         case MTAGROUPRECEIVEDMESSAGES:
1428             long_ret = (long) stat_nf[row];
1429             return (unsigned char *) &long_ret;
1430
1431         case MTAGROUPREJECTEDMESSAGES:
1432             if (stat_nr != NULL && stat_nd != NULL) {
1433                 long_ret = (long) (stat_nr[row] + stat_nd[row]);        /* Number of rejected plus number of discarded messages */
1434                 return (unsigned char *) &long_ret;
1435             } else {
1436                 return NULL;
1437             }
1438
1439         case MTAGROUPTRANSMITTEDMESSAGES:
1440             long_ret = (long) stat_nt[row];
1441             return (unsigned char *) &long_ret;
1442
1443         case MTAGROUPRECEIVEDVOLUME:
1444             long_ret = (long) stat_bf[row];
1445             return (unsigned char *) &long_ret;
1446
1447         case MTAGROUPTRANSMITTEDVOLUME:
1448             long_ret = (long) stat_bt[row];
1449             return (unsigned char *) &long_ret;
1450
1451         case MTAGROUPNAME:
1452             *var_len = strlen(mailernames[row]);
1453             return (unsigned char *) (*var_len >
1454                                       0 ? mailernames[row] : NULL);
1455
1456         case MTAGROUPHIERARCHY:
1457             long_ret = (long) -1;
1458             return (unsigned char *) &long_ret;
1459
1460         default:
1461             return NULL;
1462         }
1463     } else {
1464         /*
1465          * this is the queue group part of the table 
1466          */
1467         row -= mailers;
1468         switch (vp->magic) {
1469         case MTAGROUPSTOREDMESSAGES:
1470             count_queuegroup(&qgrps[row]);
1471             long_ret = (long) qgrps[row].count;
1472             return (unsigned char *) &long_ret;
1473
1474         case MTAGROUPSTOREDVOLUME:
1475             count_queuegroup(&qgrps[row]);
1476             long_ret = (long) qgrps[row].size;
1477             return (unsigned char *) &long_ret;
1478
1479         case MTAGROUPNAME:
1480             *var_len = strlen(qgrps[row].name);
1481             return (unsigned char *) (*var_len >
1482                                       0 ? qgrps[row].name : NULL);
1483
1484         case MTAGROUPHIERARCHY:
1485             long_ret = (long) -2;
1486             return (unsigned char *) &long_ret;
1487
1488         default:
1489             return NULL;
1490         }
1491
1492     }
1493     return NULL;
1494 }
1495
1496  /**/