Merged revisions 61694 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 void *agent_thread(void *arg)
142 {
143     ast_verbose(VERBOSE_PREFIX_2 "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
144
145     snmp_enable_stderrlog();
146
147     if (res_snmp_agentx_subagent)
148                 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
149                                                            NETSNMP_DS_AGENT_ROLE,
150                                                            1);
151
152     init_agent("asterisk");
153
154     init_asterisk_mib();
155
156     init_snmp("asterisk");
157
158     if (!res_snmp_agentx_subagent)
159                 init_master_agent();
160
161     while (res_snmp_dont_stop)
162                 agent_check_and_process(1);
163
164     snmp_shutdown("asterisk");
165
166     ast_verbose(VERBOSE_PREFIX_2 "Terminating %sAgent\n",
167                                 res_snmp_agentx_subagent ? "Sub" : "");
168
169     return NULL;
170 }
171
172 static u_char *
173 ast_var_channels(struct variable *vp, oid *name, size_t *length,
174                                  int exact, size_t *var_len, WriteMethod **write_method)
175 {
176     static unsigned long long_ret;
177
178     if (header_generic(vp, name, length, exact, var_len, write_method))
179                 return NULL;
180
181     switch (vp->magic) {
182         case ASTCHANCOUNT:
183                 long_ret = ast_active_channels();
184                 return (u_char *)&long_ret;
185         default:
186                 break;
187     }
188     return NULL;
189 }
190
191 static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
192                                                                         int exact, size_t *var_len, WriteMethod **write_method)
193 {
194     static unsigned long long_ret;
195     static u_char bits_ret[2];
196     static char string_ret[256];
197     struct ast_channel *chan, *bridge;
198     struct timeval tval;
199     u_char *ret;
200     int i, bit;
201         struct ast_str *out = ast_str_alloca(2048);
202
203     if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
204                 return NULL;
205
206     i = name[*length - 1] - 1;
207     for (chan = ast_channel_walk_locked(NULL);
208                  chan && i;
209                  chan = ast_channel_walk_locked(chan), i--)
210                 ast_channel_unlock(chan);
211     if (chan == NULL)
212                 return NULL;
213         *var_len = sizeof(long_ret);
214
215     switch (vp->magic) {
216         case ASTCHANINDEX:
217                 long_ret = name[*length - 1];
218                 ret = (u_char *)&long_ret;
219                 break;
220         case ASTCHANNAME:
221                 if (!ast_strlen_zero(chan->name)) {
222                         strncpy(string_ret, chan->name, sizeof(string_ret));
223                         string_ret[sizeof(string_ret) - 1] = '\0';
224                         *var_len = strlen(string_ret);
225                         ret = (u_char *)string_ret;
226                 }
227                 else
228                         ret = NULL;
229                 break;
230         case ASTCHANLANGUAGE:
231                 if (!ast_strlen_zero(chan->language)) {
232                         strncpy(string_ret, chan->language, sizeof(string_ret));
233                         string_ret[sizeof(string_ret) - 1] = '\0';
234                         *var_len = strlen(string_ret);
235                         ret = (u_char *)string_ret;
236                 }
237                 else
238                         ret = NULL;
239                 break;
240         case ASTCHANTYPE:
241                 strncpy(string_ret, chan->tech->type, sizeof(string_ret));
242                 string_ret[sizeof(string_ret) - 1] = '\0';
243                 *var_len = strlen(string_ret);
244                 ret = (u_char *)string_ret;
245                 break;
246         case ASTCHANMUSICCLASS:
247                 if (!ast_strlen_zero(chan->musicclass)) {
248                         strncpy(string_ret, chan->musicclass, sizeof(string_ret));
249                         string_ret[sizeof(string_ret) - 1] = '\0';
250                         *var_len = strlen(string_ret);
251                         ret = (u_char *)string_ret;
252                 }
253                 else
254                         ret = NULL;
255                 break;
256         case ASTCHANBRIDGE:
257                 if ((bridge = ast_bridged_channel(chan)) != NULL) {
258                         strncpy(string_ret, bridge->name, sizeof(string_ret));
259                         string_ret[sizeof(string_ret) - 1] = '\0';
260                         *var_len = strlen(string_ret);
261                         ret = (u_char *)string_ret;
262                 }
263                 else
264                         ret = NULL;
265                 break;
266         case ASTCHANMASQ:
267                 if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
268                         strncpy(string_ret, chan->masq->name, sizeof(string_ret));
269                         string_ret[sizeof(string_ret) - 1] = '\0';
270                         *var_len = strlen(string_ret);
271                         ret = (u_char *)string_ret;
272                 }
273                 else
274                         ret = NULL;
275                 break;
276         case ASTCHANMASQR:
277                 if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
278                         strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
279                         string_ret[sizeof(string_ret) - 1] = '\0';
280                         *var_len = strlen(string_ret);
281                         ret = (u_char *)string_ret;
282                 }
283                 else
284                         ret = NULL;
285                 break;
286         case ASTCHANWHENHANGUP:
287                 if (chan->whentohangup) {
288                         gettimeofday(&tval, NULL);
289                         long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000;
290                         ret= (u_char *)&long_ret;
291                 }
292                 else
293                         ret = NULL;
294                 break;
295         case ASTCHANAPP:
296                 if (chan->appl) {
297                         strncpy(string_ret, chan->appl, sizeof(string_ret));
298                         string_ret[sizeof(string_ret) - 1] = '\0';
299                         *var_len = strlen(string_ret);
300                         ret = (u_char *)string_ret;
301                 }
302                 else
303                         ret = NULL;
304                 break;
305         case ASTCHANDATA:
306                 if (chan->data) {
307                         strncpy(string_ret, chan->data, sizeof(string_ret));
308                         string_ret[sizeof(string_ret) - 1] = '\0';
309                         *var_len = strlen(string_ret);
310                         ret = (u_char *)string_ret;
311                 }
312                 else
313                         ret = NULL;
314                 break;
315         case ASTCHANCONTEXT:
316                 strncpy(string_ret, chan->context, sizeof(string_ret));
317                 string_ret[sizeof(string_ret) - 1] = '\0';
318                 *var_len = strlen(string_ret);
319                 ret = (u_char *)string_ret;
320                 break;
321         case ASTCHANMACROCONTEXT:
322                 strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
323                 string_ret[sizeof(string_ret) - 1] = '\0';
324                 *var_len = strlen(string_ret);
325                 ret = (u_char *)string_ret;
326                 break;
327         case ASTCHANMACROEXTEN:
328                 strncpy(string_ret, chan->macroexten, sizeof(string_ret));
329                 string_ret[sizeof(string_ret) - 1] = '\0';
330                 *var_len = strlen(string_ret);
331                 ret = (u_char *)string_ret;
332                 break;
333         case ASTCHANMACROPRI:
334                 long_ret = chan->macropriority;
335                 ret = (u_char *)&long_ret;
336                 break;
337         case ASTCHANEXTEN:
338                 strncpy(string_ret, chan->exten, sizeof(string_ret));
339                 string_ret[sizeof(string_ret) - 1] = '\0';
340                 *var_len = strlen(string_ret);
341                 ret = (u_char *)string_ret;
342                 break;
343         case ASTCHANPRI:
344                 long_ret = chan->priority;
345                 ret = (u_char *)&long_ret;
346                 break;
347         case ASTCHANACCOUNTCODE:
348                 if (!ast_strlen_zero(chan->accountcode)) {
349                         strncpy(string_ret, chan->accountcode, sizeof(string_ret));
350                         string_ret[sizeof(string_ret) - 1] = '\0';
351                         *var_len = strlen(string_ret);
352                         ret = (u_char *)string_ret;
353                 }
354                 else
355                         ret = NULL;
356                 break;
357         case ASTCHANFORWARDTO:
358                 if (!ast_strlen_zero(chan->call_forward)) {
359                         strncpy(string_ret, chan->call_forward, sizeof(string_ret));
360                         string_ret[sizeof(string_ret) - 1] = '\0';
361                         *var_len = strlen(string_ret);
362                         ret = (u_char *)string_ret;
363                 }
364                 else
365                         ret = NULL;
366                 break;
367         case ASTCHANUNIQUEID:
368                 strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
369                 string_ret[sizeof(string_ret) - 1] = '\0';
370                 *var_len = strlen(string_ret);
371                 ret = (u_char *)string_ret;
372                 break;
373         case ASTCHANCALLGROUP:
374                 long_ret = chan->callgroup;
375                 ret = (u_char *)&long_ret;
376                 break;
377         case ASTCHANPICKUPGROUP:
378                 long_ret = chan->pickupgroup;
379                 ret = (u_char *)&long_ret;
380                 break;
381         case ASTCHANSTATE:
382                 long_ret = chan->_state & 0xffff;
383                 ret = (u_char *)&long_ret;
384                 break;
385         case ASTCHANMUTED:
386                 long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
387                 ret = (u_char *)&long_ret;
388                 break;
389         case ASTCHANRINGS:
390                 long_ret = chan->rings;
391                 ret = (u_char *)&long_ret;
392                 break;
393         case ASTCHANCIDDNID:
394                 if (chan->cid.cid_dnid) {
395                         strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
396                         string_ret[sizeof(string_ret) - 1] = '\0';
397                         *var_len = strlen(string_ret);
398                         ret = (u_char *)string_ret;
399                 }
400                 else
401                         ret = NULL;
402                 break;
403         case ASTCHANCIDNUM:
404                 if (chan->cid.cid_num) {
405                         strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
406                         string_ret[sizeof(string_ret) - 1] = '\0';
407                         *var_len = strlen(string_ret);
408                         ret = (u_char *)string_ret;
409                 }
410                 else
411                         ret = NULL;
412                 break;
413         case ASTCHANCIDNAME:
414                 if (chan->cid.cid_name) {
415                         strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
416                         string_ret[sizeof(string_ret) - 1] = '\0';
417                         *var_len = strlen(string_ret);
418                         ret = (u_char *)string_ret;
419                 }
420                 else
421                         ret = NULL;
422                 break;
423         case ASTCHANCIDANI:
424                 if (chan->cid.cid_ani) {
425                         strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
426                         string_ret[sizeof(string_ret) - 1] = '\0';
427                         *var_len = strlen(string_ret);
428                         ret = (u_char *)string_ret;
429                 }
430                 else
431                         ret = NULL;
432                 break;
433         case ASTCHANCIDRDNIS:
434                 if (chan->cid.cid_rdnis) {
435                         strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
436                         string_ret[sizeof(string_ret) - 1] = '\0';
437                         *var_len = strlen(string_ret);
438                         ret = (u_char *)string_ret;
439                 }
440                 else
441                         ret = NULL;
442                 break;
443         case ASTCHANCIDPRES:
444                 long_ret = chan->cid.cid_pres;
445                 ret = (u_char *)&long_ret;
446                 break;
447         case ASTCHANCIDANI2:
448                 long_ret = chan->cid.cid_ani2;
449                 ret = (u_char *)&long_ret;
450                 break;
451         case ASTCHANCIDTON:
452                 long_ret = chan->cid.cid_ton;
453                 ret = (u_char *)&long_ret;
454                 break;
455         case ASTCHANCIDTNS:
456                 long_ret = chan->cid.cid_tns;
457                 ret = (u_char *)&long_ret;
458                 break;
459         case ASTCHANAMAFLAGS:
460                 long_ret = chan->amaflags;
461                 ret = (u_char *)&long_ret;
462                 break;
463         case ASTCHANADSI:
464                 long_ret = chan->adsicpe;
465                 ret = (u_char *)&long_ret;
466                 break;
467         case ASTCHANTONEZONE:
468                 if (chan->zone) {
469                         strncpy(string_ret, chan->zone->country, sizeof(string_ret));
470                         string_ret[sizeof(string_ret) - 1] = '\0';
471                         *var_len = strlen(string_ret);
472                         ret = (u_char *)string_ret;
473                 }
474                 else
475                         ret = NULL;
476                 break;
477         case ASTCHANHANGUPCAUSE:
478                 long_ret = chan->hangupcause;
479                 ret = (u_char *)&long_ret;
480                 break;
481         case ASTCHANVARIABLES:
482                 if (pbx_builtin_serialize_variables(chan, &out)) {
483                         *var_len = strlen(out->str);
484                         ret = (u_char *)out->str;
485                 }
486                 else
487                         ret = NULL;
488                 break;
489         case ASTCHANFLAGS:
490                 bits_ret[0] = 0;
491                 for (bit = 0; bit < 8; bit++)
492                         bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
493                 bits_ret[1] = 0;
494                 for (bit = 0; bit < 8; bit++)
495                         bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
496                 *var_len = 2;
497                 ret = bits_ret;
498                 break;
499         case ASTCHANTRANSFERCAP:
500                 long_ret = chan->transfercapability;
501                 ret = (u_char *)&long_ret;
502                 break;
503         default:
504                 ret = NULL;
505                 break;
506     }
507     ast_channel_unlock(chan);
508     return ret;
509 }
510
511 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
512                                                                    int exact, size_t *var_len, WriteMethod **write_method)
513 {
514     static unsigned long long_ret;
515         struct ast_variable *channel_types, *next;
516
517     if (header_generic(vp, name, length, exact, var_len, write_method))
518                 return NULL;
519
520     switch (vp->magic) {
521         case ASTCHANTYPECOUNT:
522                 long_ret = 0;
523                 for (channel_types = next = ast_channeltype_list(); next; next = next->next) {
524                         long_ret++;
525                 }
526                 ast_variables_destroy(channel_types);
527                 return (u_char *)&long_ret;
528         default:
529                 break;
530     }
531     return NULL;
532 }
533
534 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
535                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
536 {
537         const struct ast_channel_tech *tech = NULL;
538         struct ast_variable *channel_types, *next;
539     static unsigned long long_ret;
540     struct ast_channel *chan;
541     u_long i;
542
543     if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
544                 return NULL;
545
546         channel_types = ast_channeltype_list();
547         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
548                 ;
549         if (next != NULL)
550                 tech = ast_get_channel_tech(next->name);
551         ast_variables_destroy(channel_types);
552     if (next == NULL || tech == NULL)
553                 return NULL;
554     
555     switch (vp->magic) {
556         case ASTCHANTYPEINDEX:
557                 long_ret = name[*length - 1];
558                 return (u_char *)&long_ret;
559         case ASTCHANTYPENAME:
560                 *var_len = strlen(tech->type);
561                 return (u_char *)tech->type;
562         case ASTCHANTYPEDESC:
563                 *var_len = strlen(tech->description);
564                 return (u_char *)tech->description;
565         case ASTCHANTYPEDEVSTATE:
566                 long_ret = tech->devicestate ? 1 : 2;
567                 return (u_char *)&long_ret;
568         case ASTCHANTYPEINDICATIONS:
569                 long_ret = tech->indicate ? 1 : 2;
570                 return (u_char *)&long_ret;
571         case ASTCHANTYPETRANSFER:
572                 long_ret = tech->transfer ? 1 : 2;
573                 return (u_char *)&long_ret;
574         case ASTCHANTYPECHANNELS:
575                 long_ret = 0;
576                 for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
577                         ast_channel_unlock(chan);
578                         if (chan->tech == tech)
579                                 long_ret++;
580                 }
581                 return (u_char *)&long_ret;
582         default:
583                 break;
584     }
585     return NULL;
586 }
587
588 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
589                                                          int exact, size_t *var_len, WriteMethod **write_method)
590 {
591     static unsigned long long_ret;
592     struct timeval tval;
593
594     if (header_generic(vp, name, length, exact, var_len, write_method))
595                 return NULL;
596
597     switch (vp->magic) {
598         case ASTCONFUPTIME:
599                 gettimeofday(&tval, NULL);
600                 long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000;
601                 return (u_char *)&long_ret;
602         case ASTCONFRELOADTIME:
603                 gettimeofday(&tval, NULL);
604                 if (ast_lastreloadtime)
605                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime) * 100 + tval.tv_usec / 10000;
606                 else
607                         long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000;
608                 return (u_char *)&long_ret;
609         case ASTCONFPID:
610                 long_ret = getpid();
611                 return (u_char *)&long_ret;
612         case ASTCONFSOCKET:
613                 *var_len = strlen(ast_config_AST_SOCKET);
614                 return (u_char *)ast_config_AST_SOCKET;
615         default:
616                 break;
617     }
618     return NULL;
619 }
620
621 static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
622                                                                   int exact, size_t *var_len, WriteMethod **write_method)
623 {
624     static unsigned long long_ret;
625     struct ind_tone_zone *tz = NULL;
626
627     if (header_generic(vp, name, length, exact, var_len, write_method))
628                 return NULL;
629
630     switch (vp->magic) {
631         case ASTINDCOUNT:
632                 long_ret = 0;
633                 while ( (tz = ast_walk_indications(tz)) )
634                         long_ret++;
635
636                 return (u_char *)&long_ret;
637         case ASTINDCURRENT:
638                 tz = ast_get_indication_zone(NULL);
639                 if (tz) {
640                         *var_len = strlen(tz->country);
641                         return (u_char *)tz->country;
642                 }
643                 *var_len = 0;
644                 return NULL;
645         default:
646                 break;
647     }
648     return NULL;
649 }
650
651 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
652                                                                            int exact, size_t *var_len, WriteMethod **write_method)
653 {
654     static unsigned long long_ret;
655     struct ind_tone_zone *tz = NULL;
656     int i;
657
658     if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
659                 return NULL;
660
661     i = name[*length - 1] - 1;
662     while ( (tz = ast_walk_indications(tz)) && i )
663         i--;
664     if (tz == NULL)
665                 return NULL;
666
667     switch (vp->magic) {
668         case ASTINDINDEX:
669                 long_ret = name[*length - 1];
670                 return (u_char *)&long_ret;
671         case ASTINDCOUNTRY:
672                 *var_len = strlen(tz->country);
673                 return (u_char *)tz->country;
674         case ASTINDALIAS:
675                 if (tz->alias) {
676                         *var_len = strlen(tz->alias);
677                         return (u_char *)tz->alias;
678                 }
679                 return NULL;
680         case ASTINDDESCRIPTION:
681                 *var_len = strlen(tz->description);
682                 return (u_char *)tz->description;
683         default:
684                 break;
685     }
686     return NULL;
687 }
688
689 static int countmodule(const char *mod, const char *desc, int use, const char *like)
690 {
691     return 1;
692 }
693
694 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
695                                                           int exact, size_t *var_len, WriteMethod **write_method)
696 {
697     static unsigned long long_ret;
698
699     if (header_generic(vp, name, length, exact, var_len, write_method))
700                 return NULL;
701
702     switch (vp->magic) {
703         case ASTMODCOUNT:
704                 long_ret = ast_update_module_list(countmodule, NULL);
705                 return (u_char *)&long_ret;
706         default:
707                 break;
708     }
709     return NULL;
710 }
711
712 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
713                                                           int exact, size_t *var_len, WriteMethod **write_method)
714 {
715     static unsigned long long_ret;
716
717     if (header_generic(vp, name, length, exact, var_len, write_method))
718                 return NULL;
719
720     switch (vp->magic) {
721         case ASTVERSTRING:
722                 *var_len = strlen(ASTERISK_VERSION);
723                 return (u_char *)ASTERISK_VERSION;
724         case ASTVERTAG:
725                 long_ret = ASTERISK_VERSION_NUM;
726                 return (u_char *)&long_ret;
727         default:
728                 break;
729     }
730     return NULL;
731 }
732
733 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
734 {
735     unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
736     return 0;
737 }
738
739 static void init_asterisk_mib(void)
740 {
741     static struct variable4 asterisk_vars[] = {
742                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
743                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
744                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
745                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
746                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
747                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
748                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
749                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
750                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
751                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
752                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
753                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
754                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
755                 {ASTCHANCOUNT,           ASN_INTEGER,   RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
756                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
757                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
758                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
759                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
760                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
761                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
762                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
763                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
764                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
765                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
766                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
767                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
768                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
769                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
770                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
771                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
772                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
773                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
774                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
775                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
776                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
777                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
778                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
779                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
780                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
781                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
782                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
783                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
784                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
785                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
786                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
787                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
788                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
789                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
790                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
791                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
792                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
793                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
794                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
795                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
796                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
797                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
798                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
799                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
800                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
801                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
802                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
803                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
804                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
805     };
806
807     register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
808                         "ASTERISK-MIB implementation for Asterisk.");
809
810     REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
811
812     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
813                            SNMP_CALLBACK_SHUTDOWN,
814                            term_asterisk_mib, NULL);
815 }
816
817 /*
818  * Local Variables:
819  * c-basic-offset: 4
820  * c-file-offsets: ((case-label . 0))
821  * tab-width: 4
822  * indent-tabs-mode: t
823  * End:
824  */