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