Merged revisions 84133 via svnmerge from
[asterisk/asterisk.git] / res / snmp / agent.c
1 /*
2  * Copyright (C) 2006 Voop as
3  * Thorsten Lockert <tholo@voop.as>
4  *
5  * This program is free software, distributed under the terms of
6  * the GNU General Public License Version 2. See the LICENSE file
7  * at the top of the source tree.
8  */
9
10 /*! \file
11  *
12  * \brief SNMP Agent / SubAgent support for Asterisk
13  *
14  * \author Thorsten Lockert <tholo@voop.as>
15  */
16
17 #include "asterisk.h"
18
19 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
20
21 #include <net-snmp/net-snmp-config.h>
22 #include <net-snmp/net-snmp-includes.h>
23 #include <net-snmp/agent/net-snmp-agent-includes.h>
24
25 #include "asterisk/channel.h"
26 #include "asterisk/logger.h"
27 #include "asterisk/options.h"
28 #include "asterisk/indications.h"
29 #include "asterisk/version.h"
30 #include "asterisk/pbx.h"
31
32 /* Colission between Net-SNMP and Asterisk */
33 #define unload_module ast_unload_module
34 #include "asterisk/module.h"
35 #undef unload_module
36
37 #include "agent.h"
38
39 /* Helper functions in Net-SNMP, header file not installed by default */
40 int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);
41 int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **, int);
42 int register_sysORTable(oid *, size_t, const char *);
43 int unregister_sysORTable(oid *, size_t);
44
45 /* Not defined in header files */
46 extern char ast_config_AST_SOCKET[];
47
48 /* Forward declaration */
49 static void init_asterisk_mib(void);
50
51 /*
52  * Anchor for all the Asterisk MIB values
53  */
54 static oid asterisk_oid[] = { 1, 3, 6, 1, 4, 1, 22736, 1 };
55
56 /*
57  * MIB values -- these correspond to values in the Asterisk MIB,
58  * and MUST be kept in sync with the MIB for things to work as
59  * expected.
60  */
61 #define ASTVERSION                              1
62 #define         ASTVERSTRING                    1
63 #define         ASTVERTAG                               2
64
65 #define ASTCONFIGURATION                2
66 #define         ASTCONFUPTIME                   1
67 #define         ASTCONFRELOADTIME               2
68 #define         ASTCONFPID                              3
69 #define         ASTCONFSOCKET                   4
70
71 #define ASTMODULES                              3
72 #define         ASTMODCOUNT                             1
73
74 #define ASTINDICATIONS                  4
75 #define         ASTINDCOUNT                             1
76 #define         ASTINDCURRENT                   2
77
78 #define         ASTINDTABLE                             3
79 #define                 ASTINDINDEX                             1
80 #define                 ASTINDCOUNTRY                   2
81 #define                 ASTINDALIAS                             3
82 #define                 ASTINDDESCRIPTION               4
83
84 #define ASTCHANNELS                             5
85 #define         ASTCHANCOUNT                    1
86
87 #define         ASTCHANTABLE                    2
88 #define                 ASTCHANINDEX                    1
89 #define                 ASTCHANNAME                             2
90 #define                 ASTCHANLANGUAGE                 3
91 #define                 ASTCHANTYPE                             4
92 #define                 ASTCHANMUSICCLASS               5
93 #define                 ASTCHANBRIDGE                   6
94 #define                 ASTCHANMASQ                             7
95 #define                 ASTCHANMASQR                    8
96 #define                 ASTCHANWHENHANGUP               9
97 #define                 ASTCHANAPP                              10
98 #define                 ASTCHANDATA                             11
99 #define                 ASTCHANCONTEXT                  12
100 #define                 ASTCHANMACROCONTEXT             13
101 #define                 ASTCHANMACROEXTEN               14
102 #define                 ASTCHANMACROPRI                 15
103 #define                 ASTCHANEXTEN                    16
104 #define                 ASTCHANPRI                              17
105 #define                 ASTCHANACCOUNTCODE              18
106 #define                 ASTCHANFORWARDTO                19
107 #define                 ASTCHANUNIQUEID                 20
108 #define                 ASTCHANCALLGROUP                21
109 #define                 ASTCHANPICKUPGROUP              22
110 #define                 ASTCHANSTATE                    23
111 #define                 ASTCHANMUTED                    24
112 #define                 ASTCHANRINGS                    25
113 #define                 ASTCHANCIDDNID                  26
114 #define                 ASTCHANCIDNUM                   27
115 #define                 ASTCHANCIDNAME                  28
116 #define                 ASTCHANCIDANI                   29
117 #define                 ASTCHANCIDRDNIS                 30
118 #define                 ASTCHANCIDPRES                  31
119 #define                 ASTCHANCIDANI2                  32
120 #define                 ASTCHANCIDTON                   33
121 #define                 ASTCHANCIDTNS                   34
122 #define                 ASTCHANAMAFLAGS                 35
123 #define                 ASTCHANADSI                             36
124 #define                 ASTCHANTONEZONE                 37
125 #define                 ASTCHANHANGUPCAUSE              38
126 #define                 ASTCHANVARIABLES                39
127 #define                 ASTCHANFLAGS                    40
128 #define                 ASTCHANTRANSFERCAP              41
129
130 #define         ASTCHANTYPECOUNT                3
131
132 #define         ASTCHANTYPETABLE                4
133 #define                 ASTCHANTYPEINDEX                1
134 #define                 ASTCHANTYPENAME                 2
135 #define                 ASTCHANTYPEDESC                 3
136 #define                 ASTCHANTYPEDEVSTATE             4
137 #define                 ASTCHANTYPEINDICATIONS  5
138 #define                 ASTCHANTYPETRANSFER             6
139 #define                 ASTCHANTYPECHANNELS             7
140
141 #define         ASTCHANSCALARS                  5
142 #define                 ASTCHANBRIDGECOUNT              1
143
144 void *agent_thread(void *arg)
145 {
146         ast_verbose(VERBOSE_PREFIX_2 "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
147
148         snmp_enable_stderrlog();
149
150         if (res_snmp_agentx_subagent)
151                 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
152                                                            NETSNMP_DS_AGENT_ROLE,
153                                                            1);
154
155         init_agent("asterisk");
156
157         init_asterisk_mib();
158
159         init_snmp("asterisk");
160
161         if (!res_snmp_agentx_subagent)
162                 init_master_agent();
163
164         while (res_snmp_dont_stop)
165                 agent_check_and_process(1);
166
167         snmp_shutdown("asterisk");
168
169         ast_verbose(VERBOSE_PREFIX_2 "Terminating %sAgent\n",
170                                 res_snmp_agentx_subagent ? "Sub" : "");
171
172         return NULL;
173 }
174
175 static u_char *
176 ast_var_channels(struct variable *vp, oid *name, size_t *length,
177                                  int exact, size_t *var_len, WriteMethod **write_method)
178 {
179         static unsigned long long_ret;
180
181         if (header_generic(vp, name, length, exact, var_len, write_method))
182                 return NULL;
183
184         if (vp->magic != ASTCHANCOUNT)
185                 return NULL;
186
187         long_ret = ast_active_channels();
188
189         return (u_char *)&long_ret;
190 }
191
192 static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
193                                                                         int exact, size_t *var_len, WriteMethod **write_method)
194 {
195         static unsigned long long_ret;
196         static u_char bits_ret[2];
197         static char string_ret[256];
198         struct ast_channel *chan, *bridge;
199         struct timeval tval;
200         u_char *ret = NULL;
201         int i, bit;
202         struct ast_str *out = ast_str_alloca(2048);
203
204         if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
205                 return NULL;
206
207         i = name[*length - 1] - 1;
208         for (chan = ast_channel_walk_locked(NULL);
209                  chan && i;
210                  chan = ast_channel_walk_locked(chan), i--)
211                 ast_channel_unlock(chan);
212         if (chan == NULL)
213                 return NULL;
214         *var_len = sizeof(long_ret);
215
216         switch (vp->magic) {
217         case ASTCHANINDEX:
218                 long_ret = name[*length - 1];
219                 ret = (u_char *)&long_ret;
220                 break;
221         case ASTCHANNAME:
222                 if (!ast_strlen_zero(chan->name)) {
223                         strncpy(string_ret, chan->name, sizeof(string_ret));
224                         string_ret[sizeof(string_ret) - 1] = '\0';
225                         *var_len = strlen(string_ret);
226                         ret = (u_char *)string_ret;
227                 }
228                 break;
229         case ASTCHANLANGUAGE:
230                 if (!ast_strlen_zero(chan->language)) {
231                         strncpy(string_ret, chan->language, sizeof(string_ret));
232                         string_ret[sizeof(string_ret) - 1] = '\0';
233                         *var_len = strlen(string_ret);
234                         ret = (u_char *)string_ret;
235                 }
236                 break;
237         case ASTCHANTYPE:
238                 strncpy(string_ret, chan->tech->type, sizeof(string_ret));
239                 string_ret[sizeof(string_ret) - 1] = '\0';
240                 *var_len = strlen(string_ret);
241                 ret = (u_char *)string_ret;
242                 break;
243         case ASTCHANMUSICCLASS:
244                 if (!ast_strlen_zero(chan->musicclass)) {
245                         strncpy(string_ret, chan->musicclass, sizeof(string_ret));
246                         string_ret[sizeof(string_ret) - 1] = '\0';
247                         *var_len = strlen(string_ret);
248                         ret = (u_char *)string_ret;
249                 }
250                 break;
251         case ASTCHANBRIDGE:
252                 if ((bridge = ast_bridged_channel(chan)) != NULL) {
253                         strncpy(string_ret, bridge->name, sizeof(string_ret));
254                         string_ret[sizeof(string_ret) - 1] = '\0';
255                         *var_len = strlen(string_ret);
256                         ret = (u_char *)string_ret;
257                 }
258                 break;
259         case ASTCHANMASQ:
260                 if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
261                         strncpy(string_ret, chan->masq->name, sizeof(string_ret));
262                         string_ret[sizeof(string_ret) - 1] = '\0';
263                         *var_len = strlen(string_ret);
264                         ret = (u_char *)string_ret;
265                 }
266                 break;
267         case ASTCHANMASQR:
268                 if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
269                         strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
270                         string_ret[sizeof(string_ret) - 1] = '\0';
271                         *var_len = strlen(string_ret);
272                         ret = (u_char *)string_ret;
273                 }
274                 break;
275         case ASTCHANWHENHANGUP:
276                 if (chan->whentohangup) {
277                         gettimeofday(&tval, NULL);
278                         long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000;
279                         ret= (u_char *)&long_ret;
280                 }
281                 break;
282         case ASTCHANAPP:
283                 if (chan->appl) {
284                         strncpy(string_ret, chan->appl, sizeof(string_ret));
285                         string_ret[sizeof(string_ret) - 1] = '\0';
286                         *var_len = strlen(string_ret);
287                         ret = (u_char *)string_ret;
288                 }
289                 break;
290         case ASTCHANDATA:
291                 if (chan->data) {
292                         strncpy(string_ret, chan->data, sizeof(string_ret));
293                         string_ret[sizeof(string_ret) - 1] = '\0';
294                         *var_len = strlen(string_ret);
295                         ret = (u_char *)string_ret;
296                 }
297                 break;
298         case ASTCHANCONTEXT:
299                 strncpy(string_ret, chan->context, sizeof(string_ret));
300                 string_ret[sizeof(string_ret) - 1] = '\0';
301                 *var_len = strlen(string_ret);
302                 ret = (u_char *)string_ret;
303                 break;
304         case ASTCHANMACROCONTEXT:
305                 strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
306                 string_ret[sizeof(string_ret) - 1] = '\0';
307                 *var_len = strlen(string_ret);
308                 ret = (u_char *)string_ret;
309                 break;
310         case ASTCHANMACROEXTEN:
311                 strncpy(string_ret, chan->macroexten, sizeof(string_ret));
312                 string_ret[sizeof(string_ret) - 1] = '\0';
313                 *var_len = strlen(string_ret);
314                 ret = (u_char *)string_ret;
315                 break;
316         case ASTCHANMACROPRI:
317                 long_ret = chan->macropriority;
318                 ret = (u_char *)&long_ret;
319                 break;
320         case ASTCHANEXTEN:
321                 strncpy(string_ret, chan->exten, sizeof(string_ret));
322                 string_ret[sizeof(string_ret) - 1] = '\0';
323                 *var_len = strlen(string_ret);
324                 ret = (u_char *)string_ret;
325                 break;
326         case ASTCHANPRI:
327                 long_ret = chan->priority;
328                 ret = (u_char *)&long_ret;
329                 break;
330         case ASTCHANACCOUNTCODE:
331                 if (!ast_strlen_zero(chan->accountcode)) {
332                         strncpy(string_ret, chan->accountcode, sizeof(string_ret));
333                         string_ret[sizeof(string_ret) - 1] = '\0';
334                         *var_len = strlen(string_ret);
335                         ret = (u_char *)string_ret;
336                 }
337                 break;
338         case ASTCHANFORWARDTO:
339                 if (!ast_strlen_zero(chan->call_forward)) {
340                         strncpy(string_ret, chan->call_forward, sizeof(string_ret));
341                         string_ret[sizeof(string_ret) - 1] = '\0';
342                         *var_len = strlen(string_ret);
343                         ret = (u_char *)string_ret;
344                 }
345                 break;
346         case ASTCHANUNIQUEID:
347                 strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
348                 string_ret[sizeof(string_ret) - 1] = '\0';
349                 *var_len = strlen(string_ret);
350                 ret = (u_char *)string_ret;
351                 break;
352         case ASTCHANCALLGROUP:
353                 long_ret = chan->callgroup;
354                 ret = (u_char *)&long_ret;
355                 break;
356         case ASTCHANPICKUPGROUP:
357                 long_ret = chan->pickupgroup;
358                 ret = (u_char *)&long_ret;
359                 break;
360         case ASTCHANSTATE:
361                 long_ret = chan->_state & 0xffff;
362                 ret = (u_char *)&long_ret;
363                 break;
364         case ASTCHANMUTED:
365                 long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
366                 ret = (u_char *)&long_ret;
367                 break;
368         case ASTCHANRINGS:
369                 long_ret = chan->rings;
370                 ret = (u_char *)&long_ret;
371                 break;
372         case ASTCHANCIDDNID:
373                 if (chan->cid.cid_dnid) {
374                         strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
375                         string_ret[sizeof(string_ret) - 1] = '\0';
376                         *var_len = strlen(string_ret);
377                         ret = (u_char *)string_ret;
378                 }
379                 break;
380         case ASTCHANCIDNUM:
381                 if (chan->cid.cid_num) {
382                         strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
383                         string_ret[sizeof(string_ret) - 1] = '\0';
384                         *var_len = strlen(string_ret);
385                         ret = (u_char *)string_ret;
386                 }
387                 break;
388         case ASTCHANCIDNAME:
389                 if (chan->cid.cid_name) {
390                         strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
391                         string_ret[sizeof(string_ret) - 1] = '\0';
392                         *var_len = strlen(string_ret);
393                         ret = (u_char *)string_ret;
394                 }
395                 break;
396         case ASTCHANCIDANI:
397                 if (chan->cid.cid_ani) {
398                         strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
399                         string_ret[sizeof(string_ret) - 1] = '\0';
400                         *var_len = strlen(string_ret);
401                         ret = (u_char *)string_ret;
402                 }
403                 break;
404         case ASTCHANCIDRDNIS:
405                 if (chan->cid.cid_rdnis) {
406                         strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
407                         string_ret[sizeof(string_ret) - 1] = '\0';
408                         *var_len = strlen(string_ret);
409                         ret = (u_char *)string_ret;
410                 }
411                 break;
412         case ASTCHANCIDPRES:
413                 long_ret = chan->cid.cid_pres;
414                 ret = (u_char *)&long_ret;
415                 break;
416         case ASTCHANCIDANI2:
417                 long_ret = chan->cid.cid_ani2;
418                 ret = (u_char *)&long_ret;
419                 break;
420         case ASTCHANCIDTON:
421                 long_ret = chan->cid.cid_ton;
422                 ret = (u_char *)&long_ret;
423                 break;
424         case ASTCHANCIDTNS:
425                 long_ret = chan->cid.cid_tns;
426                 ret = (u_char *)&long_ret;
427                 break;
428         case ASTCHANAMAFLAGS:
429                 long_ret = chan->amaflags;
430                 ret = (u_char *)&long_ret;
431                 break;
432         case ASTCHANADSI:
433                 long_ret = chan->adsicpe;
434                 ret = (u_char *)&long_ret;
435                 break;
436         case ASTCHANTONEZONE:
437                 if (chan->zone) {
438                         strncpy(string_ret, chan->zone->country, sizeof(string_ret));
439                         string_ret[sizeof(string_ret) - 1] = '\0';
440                         *var_len = strlen(string_ret);
441                         ret = (u_char *)string_ret;
442                 }
443                 break;
444         case ASTCHANHANGUPCAUSE:
445                 long_ret = chan->hangupcause;
446                 ret = (u_char *)&long_ret;
447                 break;
448         case ASTCHANVARIABLES:
449                 if (pbx_builtin_serialize_variables(chan, &out)) {
450                         *var_len = strlen(out->str);
451                         ret = (u_char *)out->str;
452                 }
453                 break;
454         case ASTCHANFLAGS:
455                 bits_ret[0] = 0;
456                 for (bit = 0; bit < 8; bit++)
457                         bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
458                 bits_ret[1] = 0;
459                 for (bit = 0; bit < 8; bit++)
460                         bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
461                 *var_len = 2;
462                 ret = bits_ret;
463                 break;
464         case ASTCHANTRANSFERCAP:
465                 long_ret = chan->transfercapability;
466                 ret = (u_char *)&long_ret;
467         default:
468                 break;
469         }
470         ast_channel_unlock(chan);
471         return ret;
472 }
473
474 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
475                                                                    int exact, size_t *var_len, WriteMethod **write_method)
476 {
477         static unsigned long long_ret;
478         struct ast_variable *channel_types, *next;
479
480         if (header_generic(vp, name, length, exact, var_len, write_method))
481                 return NULL;
482
483         if (vp->magic != ASTCHANTYPECOUNT)
484                 return NULL;
485
486         for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
487                 long_ret++;
488         ast_variables_destroy(channel_types);
489
490         return (u_char *)&long_ret;
491 }
492
493 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
494                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
495 {
496         const struct ast_channel_tech *tech = NULL;
497         struct ast_variable *channel_types, *next;
498         static unsigned long long_ret;
499         struct ast_channel *chan;
500         u_long i;
501
502         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
503                 return NULL;
504
505         channel_types = ast_channeltype_list();
506         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
507                 ;
508         if (next != NULL)
509                 tech = ast_get_channel_tech(next->name);
510         ast_variables_destroy(channel_types);
511         if (next == NULL || tech == NULL)
512                 return NULL;
513         
514         switch (vp->magic) {
515         case ASTCHANTYPEINDEX:
516                 long_ret = name[*length - 1];
517                 return (u_char *)&long_ret;
518         case ASTCHANTYPENAME:
519                 *var_len = strlen(tech->type);
520                 return (u_char *)tech->type;
521         case ASTCHANTYPEDESC:
522                 *var_len = strlen(tech->description);
523                 return (u_char *)tech->description;
524         case ASTCHANTYPEDEVSTATE:
525                 long_ret = tech->devicestate ? 1 : 2;
526                 return (u_char *)&long_ret;
527         case ASTCHANTYPEINDICATIONS:
528                 long_ret = tech->indicate ? 1 : 2;
529                 return (u_char *)&long_ret;
530         case ASTCHANTYPETRANSFER:
531                 long_ret = tech->transfer ? 1 : 2;
532                 return (u_char *)&long_ret;
533         case ASTCHANTYPECHANNELS:
534                 long_ret = 0;
535                 for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
536                         ast_channel_unlock(chan);
537                         if (chan->tech == tech)
538                                 long_ret++;
539                 }
540                 return (u_char *)&long_ret;
541         default:
542                 break;
543         }
544         return NULL;
545 }
546
547 static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
548         int exact, size_t *var_len, WriteMethod **write_method)
549 {
550         static unsigned long long_ret;
551         struct ast_channel *chan = NULL;
552
553         long_ret = 0;
554         if (header_generic(vp, name, length, exact, var_len, write_method))
555                 return NULL;
556
557         while ((chan = ast_channel_walk_locked(chan))) {
558                 if (ast_bridged_channel(chan))
559                         long_ret++;
560                 ast_channel_unlock(chan);
561         }
562
563         *var_len = sizeof(long_ret);
564
565         return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;
566 }
567
568 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
569                                                          int exact, size_t *var_len, WriteMethod **write_method)
570 {
571         static unsigned long long_ret;
572         struct timeval tval;
573
574         if (header_generic(vp, name, length, exact, var_len, write_method))
575                 return NULL;
576
577         switch (vp->magic) {
578         case ASTCONFUPTIME:
579                 gettimeofday(&tval, NULL);
580                 long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
581                 return (u_char *)&long_ret;
582         case ASTCONFRELOADTIME:
583                 gettimeofday(&tval, NULL);
584                 if (ast_lastreloadtime.tv_sec)
585                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
586                 else
587                         long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
588                 return (u_char *)&long_ret;
589         case ASTCONFPID:
590                 long_ret = getpid();
591                 return (u_char *)&long_ret;
592         case ASTCONFSOCKET:
593                 *var_len = strlen(ast_config_AST_SOCKET);
594                 return (u_char *)ast_config_AST_SOCKET;
595         default:
596                 break;
597         }
598         return NULL;
599 }
600
601 static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
602                                                                   int exact, size_t *var_len, WriteMethod **write_method)
603 {
604         static unsigned long long_ret;
605         struct ind_tone_zone *tz = NULL;
606
607         if (header_generic(vp, name, length, exact, var_len, write_method))
608                 return NULL;
609
610         switch (vp->magic) {
611         case ASTINDCOUNT:
612                 long_ret = 0;
613                 while ( (tz = ast_walk_indications(tz)) )
614                         long_ret++;
615
616                 return (u_char *)&long_ret;
617         case ASTINDCURRENT:
618                 tz = ast_get_indication_zone(NULL);
619                 if (tz) {
620                         *var_len = strlen(tz->country);
621                         return (u_char *)tz->country;
622                 }
623                 *var_len = 0;
624                 return NULL;
625         default:
626                 break;
627         }
628         return NULL;
629 }
630
631 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
632                                                                            int exact, size_t *var_len, WriteMethod **write_method)
633 {
634         static unsigned long long_ret;
635         struct ind_tone_zone *tz = NULL;
636         int i;
637
638         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
639                 return NULL;
640
641         i = name[*length - 1] - 1;
642         while ( (tz = ast_walk_indications(tz)) && i )
643         i--;
644         if (tz == NULL)
645                 return NULL;
646
647         switch (vp->magic) {
648         case ASTINDINDEX:
649                 long_ret = name[*length - 1];
650                 return (u_char *)&long_ret;
651         case ASTINDCOUNTRY:
652                 *var_len = strlen(tz->country);
653                 return (u_char *)tz->country;
654         case ASTINDALIAS:
655                 if (tz->alias) {
656                         *var_len = strlen(tz->alias);
657                         return (u_char *)tz->alias;
658                 }
659                 return NULL;
660         case ASTINDDESCRIPTION:
661                 *var_len = strlen(tz->description);
662                 return (u_char *)tz->description;
663         default:
664                 break;
665         }
666         return NULL;
667 }
668
669 static int countmodule(const char *mod, const char *desc, int use, const char *like)
670 {
671         return 1;
672 }
673
674 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
675                                                           int exact, size_t *var_len, WriteMethod **write_method)
676 {
677         static unsigned long long_ret;
678
679         if (header_generic(vp, name, length, exact, var_len, write_method))
680                 return NULL;
681
682         if (vp->magic != ASTMODCOUNT)
683                 return NULL;
684
685         long_ret = ast_update_module_list(countmodule, NULL);
686
687         return (u_char *)&long_ret;
688 }
689
690 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
691                                                           int exact, size_t *var_len, WriteMethod **write_method)
692 {
693         static unsigned long long_ret;
694
695         if (header_generic(vp, name, length, exact, var_len, write_method))
696                 return NULL;
697
698         switch (vp->magic) {
699         case ASTVERSTRING:
700                 *var_len = strlen(ASTERISK_VERSION);
701                 return (u_char *)ASTERISK_VERSION;
702         case ASTVERTAG:
703                 long_ret = ASTERISK_VERSION_NUM;
704                 return (u_char *)&long_ret;
705         default:
706                 break;
707         }
708         return NULL;
709 }
710
711 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
712 {
713         unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
714         return 0;
715 }
716
717 static void init_asterisk_mib(void)
718 {
719         static struct variable4 asterisk_vars[] = {
720                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
721                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
722                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
723                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
724                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
725                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
726                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
727                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
728                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
729                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
730                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
731                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
732                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
733                 {ASTCHANCOUNT,           ASN_INTEGER,   RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
734                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
735                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
736                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
737                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
738                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
739                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
740                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
741                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
742                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
743                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
744                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
745                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
746                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
747                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
748                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
749                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
750                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
751                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
752                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
753                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
754                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
755                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
756                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
757                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
758                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
759                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
760                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
761                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
762                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
763                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
764                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
765                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
766                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
767                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
768                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
769                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
770                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
771                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
772                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
773                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
774                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
775                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
776                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
777                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
778                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
779                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
780                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
781                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
782                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
783                 {ASTCHANBRIDGECOUNT,     ASN_GAUGE,     RONLY, ast_var_channel_bridge,      3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
784         };
785
786         register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
787                         "ASTERISK-MIB implementation for Asterisk.");
788
789         REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
790
791         snmp_register_callback(SNMP_CALLBACK_LIBRARY,
792                            SNMP_CALLBACK_SHUTDOWN,
793                            term_asterisk_mib, NULL);
794 }
795
796 /*
797  * Local Variables:
798  * c-basic-offset: 4
799  * c-file-offsets: ((case-label . 0))
800  * tab-width: 4
801  * indent-tabs-mode: t
802  * End:
803  */