Phone provisioning application for the asterisk internal http server. More...
#include "asterisk.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/paths.h"
#include "asterisk/pbx.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/strings.h"
#include "asterisk/stringfields.h"
#include "asterisk/options.h"
#include "asterisk/config.h"
#include "asterisk/acl.h"
#include "asterisk/astobj2.h"
#include "asterisk/ast_version.h"
Go to the source code of this file.
Data Structures | |
struct | extension |
struct | http_route |
structure to hold http routes (valid URIs, and the files they link to) More... | |
struct | phone_profile |
structure to hold phone profiles read from phoneprov.conf More... | |
struct | phoneprov_file |
structure to hold file data More... | |
struct | pp_variable_lookup |
Lookup table to translate between users.conf property names and variables for use in phoneprov templates. More... | |
struct | user |
structure to hold users read from users.conf More... | |
Defines | |
#define | FORMAT "%-40.40s %-30.30s\n" |
#define | MAX_PROFILE_BUCKETS 17 |
#define | MAX_ROUTE_BUCKETS 563 |
#define | MAX_USER_BUCKETS 563 |
#define | VAR_BUF_SIZE 4096 |
Enumerations | |
enum | pp_variables { PP_MACADDRESS, PP_USERNAME, PP_FULLNAME, PP_SECRET, PP_LABEL, PP_CALLERID, PP_TIMEZONE, PP_LINENUMBER, PP_LINEKEYS, PP_VAR_LIST_LENGTH } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | add_user_extension (struct user *user, struct extension *exten) |
Add an extension to a user ordered by index/linenumber. | |
static struct extension * | build_extension (struct ast_config *cfg, const char *name) |
static void | build_profile (const char *name, struct ast_variable *v) |
Build a phone profile and add it to the list of phone profiles. | |
static void | build_route (struct phoneprov_file *pp_file, struct user *user, char *uri) |
Build a route structure and add it to the list of available http routes. | |
static struct user * | build_user (const char *mac, struct phone_profile *profile) |
Build and return a user structure based on gathered config data. | |
static int | build_user_routes (struct user *user) |
Add an http route for dynamic files attached to the profile of the user. | |
static struct extension * | delete_extension (struct extension *exten) |
static void | delete_file (struct phoneprov_file *file) |
static void | delete_profiles (void) |
Delete all phone profiles, freeing their memory. | |
static void | delete_routes (void) |
Delete all http routes, freeing their memory. | |
static void | delete_users (void) |
Delete all users. | |
static struct phone_profile * | find_profile (const char *name) |
Return a phone profile looked up by name. | |
static struct user * | find_user (const char *macaddress) |
Return a user looked up by name. | |
static char * | handle_show_routes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
CLI command to list static and dynamic routes. | |
static int | load_file (const char *filename, char **ret) |
Read a TEXT file into a string and return the length. | |
static int | load_module (void) |
static int | lookup_iface (const char *iface, struct in_addr *address) |
static int | phoneprov_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) |
Callback that is executed everytime an http request is received by this module. | |
static int | pp_each_extension_helper (struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, int len) |
A dialplan function that can be used to output a template for each extension attached to a user. | |
static int | pp_each_extension_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | pp_each_extension_read2 (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | pp_each_user_helper (struct ast_channel *chan, char *data, char *buf, struct ast_str **bufstr, int len) |
A dialplan function that can be used to print a string for each phoneprov user. | |
static int | pp_each_user_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | pp_each_user_read2 (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) |
static int | profile_cmp_fn (void *obj, void *arg, int flags) |
static void | profile_destructor (void *obj) |
static int | profile_hash_fn (const void *obj, const int flags) |
static int | reload (void) |
static void | route_destructor (void *obj) |
static int | routes_cmp_fn (void *obj, void *arg, int flags) |
static int | routes_hash_fn (const void *obj, const int flags) |
static int | set_config (void) |
static void | set_timezone_variables (struct varshead *headp, const char *zone) |
Set all timezone-related variables based on a zone (i.e. America/New_York). | |
static int | unload_module (void) |
static struct phone_profile * | unref_profile (struct phone_profile *prof) |
static struct http_route * | unref_route (struct http_route *route) |
static struct user * | unref_user (struct user *user) |
static void | user_destructor (void *obj) |
Free all memory associated with a user. | |
static int | users_cmp_fn (void *obj, void *arg, int flags) |
static int | users_hash_fn (const void *obj, const int flags) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP Phone Provisioning" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, } |
static struct in_addr | __ourip = { .s_addr = 0x00000000, } |
for use in lookup_iface | |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char | global_default_profile [80] = "" |
static char | global_server [80] = "" |
static char | global_serverport [6] = "" |
static struct varshead | global_variables |
List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH. | |
static ast_mutex_t | globals_lock |
static struct ao2_container * | http_routes |
static struct ast_http_uri | phoneprovuri |
static struct ast_cli_entry | pp_cli [] |
static struct ast_custom_function | pp_each_extension_function |
static struct ast_custom_function | pp_each_user_function |
static struct pp_variable_lookup | pp_variable_list [] |
Lookup table to translate between users.conf property names and variables for use in phoneprov templates. | |
static struct ao2_container * | profiles |
static struct ao2_container * | users |
Phone provisioning application for the asterisk internal http server.
Definition in file res_phoneprov.c.
#define FORMAT "%-40.40s %-30.30s\n" |
#define MAX_PROFILE_BUCKETS 17 |
Definition at line 65 of file res_phoneprov.c.
Referenced by load_module().
#define MAX_ROUTE_BUCKETS 563 |
Definition at line 66 of file res_phoneprov.c.
Referenced by load_module().
#define MAX_USER_BUCKETS 563 |
Definition at line 67 of file res_phoneprov.c.
#define VAR_BUF_SIZE 4096 |
Definition at line 70 of file res_phoneprov.c.
enum pp_variables |
PP_MACADDRESS | |
PP_USERNAME | |
PP_FULLNAME | |
PP_SECRET | |
PP_LABEL | |
PP_CALLERID | |
PP_TIMEZONE | |
PP_LINENUMBER | |
PP_LINEKEYS | |
PP_VAR_LIST_LENGTH |
Definition at line 108 of file res_phoneprov.c.
00108 { 00109 PP_MACADDRESS, 00110 PP_USERNAME, 00111 PP_FULLNAME, 00112 PP_SECRET, 00113 PP_LABEL, 00114 PP_CALLERID, 00115 PP_TIMEZONE, 00116 PP_LINENUMBER, 00117 PP_LINEKEYS, 00118 PP_VAR_LIST_LENGTH, /* This entry must always be the last in the list */ 00119 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1344 of file res_phoneprov.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1344 of file res_phoneprov.c.
Add an extension to a user ordered by index/linenumber.
Definition at line 843 of file res_phoneprov.c.
References ast_free, AST_LIST_EMPTY, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_substitute_variables_varshead(), ast_var_assign(), user::extensions, extension::headp, phone_profile::headp, extension::index, LOG_WARNING, user::macaddress, ast_var_t::name, user::profile, str, ast_var_t::value, and var.
Referenced by set_config().
00844 { 00845 struct ast_var_t *var; 00846 struct ast_str *str = ast_str_create(16); 00847 00848 if (!str) { 00849 return -1; 00850 } 00851 00852 /* Append profile variables here, and substitute variables on profile 00853 * setvars, so that we can use user specific variables in them */ 00854 AST_LIST_TRAVERSE(user->profile->headp, var, entries) { 00855 struct ast_var_t *var2; 00856 00857 ast_str_substitute_variables_varshead(&str, 0, exten->headp, var->value); 00858 if ((var2 = ast_var_assign(var->name, ast_str_buffer(str)))) { 00859 AST_LIST_INSERT_TAIL(exten->headp, var2, entries); 00860 } 00861 } 00862 00863 ast_free(str); 00864 00865 if (AST_LIST_EMPTY(&user->extensions)) { 00866 AST_LIST_INSERT_HEAD(&user->extensions, exten, entry); 00867 } else { 00868 struct extension *exten_iter; 00869 00870 AST_LIST_TRAVERSE_SAFE_BEGIN(&user->extensions, exten_iter, entry) { 00871 if (exten->index < exten_iter->index) { 00872 AST_LIST_INSERT_BEFORE_CURRENT(exten, entry); 00873 } else if (exten->index == exten_iter->index) { 00874 ast_log(LOG_WARNING, "Duplicate linenumber=%d for %s\n", exten->index, user->macaddress); 00875 return -1; 00876 } else if (!AST_LIST_NEXT(exten_iter, entry)) { 00877 AST_LIST_INSERT_TAIL(&user->extensions, exten, entry); 00878 } 00879 } 00880 AST_LIST_TRAVERSE_SAFE_END; 00881 } 00882 00883 return 0; 00884 }
static struct extension* build_extension | ( | struct ast_config * | cfg, | |
const char * | name | |||
) | [static, read] |
Definition at line 698 of file res_phoneprov.c.
References ast_calloc, ast_calloc_with_stringfields, ast_free, AST_LIST_INSERT_TAIL, ast_string_field_set, ast_strlen_zero(), ast_var_assign(), ast_variable_retrieve(), exten, extension::headp, extension::index, extension::name, PP_LINEKEYS, PP_LINENUMBER, PP_TIMEZONE, PP_USERNAME, PP_VAR_LIST_LENGTH, pp_variable_list, set_timezone_variables(), and var.
Referenced by set_config().
00699 { 00700 struct extension *exten; 00701 struct ast_var_t *var; 00702 const char *tmp; 00703 int i; 00704 00705 if (!(exten = ast_calloc_with_stringfields(1, struct extension, 32))) { 00706 return NULL; 00707 } 00708 00709 ast_string_field_set(exten, name, name); 00710 00711 if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) { 00712 ast_free(exten); 00713 exten = NULL; 00714 return NULL; 00715 } 00716 00717 for (i = 0; i < PP_VAR_LIST_LENGTH; i++) { 00718 tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var); 00719 00720 /* If we didn't get a USERNAME variable, set it to the user->name */ 00721 if (i == PP_USERNAME && !tmp) { 00722 if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) { 00723 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00724 } 00725 continue; 00726 } else if (i == PP_TIMEZONE) { 00727 /* perfectly ok if tmp is NULL, will set variables based on server's time zone */ 00728 set_timezone_variables(exten->headp, tmp); 00729 } else if (i == PP_LINENUMBER) { 00730 if (!tmp) { 00731 tmp = "1"; 00732 } 00733 exten->index = atoi(tmp); 00734 } else if (i == PP_LINEKEYS) { 00735 if (!tmp) { 00736 tmp = "1"; 00737 } 00738 } 00739 00740 if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) { 00741 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00742 } 00743 } 00744 00745 if (!ast_strlen_zero(global_server)) { 00746 if ((var = ast_var_assign("SERVER", global_server))) 00747 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00748 } 00749 00750 if (!ast_strlen_zero(global_serverport)) { 00751 if ((var = ast_var_assign("SERVER_PORT", global_serverport))) 00752 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00753 } 00754 00755 return exten; 00756 }
static void build_profile | ( | const char * | name, | |
struct ast_variable * | v | |||
) | [static] |
Build a phone profile and add it to the list of phone profiles.
name | the name of the profile | |
v | ast_variable from parsing phoneprov.conf |
Definition at line 576 of file res_phoneprov.c.
References ao2_alloc, ao2_link, args, AST_APP_ARG, ast_calloc, ast_calloc_with_stringfields, AST_DECLARE_APP_ARGS, ast_http_ftype2mtype(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_mutex_lock, ast_mutex_unlock, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_string_field_build, ast_string_field_init, ast_string_field_set, ast_strip(), ast_strlen_zero(), ast_var_assign(), build_route(), phone_profile::default_mime_type, phone_profile::dynamic_files, phoneprov_file::format, global_variables, phone_profile::headp, phoneprov_file::mime_type, ast_var_t::name, ast_variable::name, ast_variable::next, profile_destructor(), S_OR, phone_profile::static_files, phone_profile::staticdir, unref_profile(), ast_var_t::value, ast_variable::value, and var.
Referenced by set_config().
00577 { 00578 struct phone_profile *profile; 00579 struct ast_var_t *var; 00580 00581 if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) { 00582 return; 00583 } 00584 00585 if (ast_string_field_init(profile, 32)) { 00586 profile = unref_profile(profile); 00587 return; 00588 } 00589 00590 if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) { 00591 profile = unref_profile(profile); 00592 return; 00593 } 00594 00595 AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files); 00596 AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files); 00597 00598 ast_string_field_set(profile, name, name); 00599 for (; v; v = v->next) { 00600 if (!strcasecmp(v->name, "mime_type")) { 00601 ast_string_field_set(profile, default_mime_type, v->value); 00602 } else if (!strcasecmp(v->name, "setvar")) { 00603 struct ast_var_t *variable; 00604 char *value_copy = ast_strdupa(v->value); 00605 00606 AST_DECLARE_APP_ARGS(args, 00607 AST_APP_ARG(varname); 00608 AST_APP_ARG(varval); 00609 ); 00610 00611 AST_NONSTANDARD_APP_ARGS(args, value_copy, '='); 00612 do { 00613 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval)) 00614 break; 00615 args.varname = ast_strip(args.varname); 00616 args.varval = ast_strip(args.varval); 00617 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval)) 00618 break; 00619 if ((variable = ast_var_assign(args.varname, args.varval))) 00620 AST_LIST_INSERT_TAIL(profile->headp, variable, entries); 00621 } while (0); 00622 } else if (!strcasecmp(v->name, "staticdir")) { 00623 ast_string_field_set(profile, staticdir, v->value); 00624 } else { 00625 struct phoneprov_file *pp_file; 00626 char *file_extension; 00627 char *value_copy = ast_strdupa(v->value); 00628 00629 AST_DECLARE_APP_ARGS(args, 00630 AST_APP_ARG(filename); 00631 AST_APP_ARG(mimetype); 00632 ); 00633 00634 if (!(pp_file = ast_calloc_with_stringfields(1, struct phoneprov_file, 32))) { 00635 profile = unref_profile(profile); 00636 return; 00637 } 00638 00639 if ((file_extension = strrchr(pp_file->format, '.'))) 00640 file_extension++; 00641 00642 AST_STANDARD_APP_ARGS(args, value_copy); 00643 00644 /* Mime type order of preference 00645 * 1) Specific mime-type defined for file in profile 00646 * 2) Mime determined by extension 00647 * 3) Default mime type specified in profile 00648 * 4) text/plain 00649 */ 00650 ast_string_field_set(pp_file, mime_type, S_OR(args.mimetype, 00651 (S_OR(S_OR(ast_http_ftype2mtype(file_extension), profile->default_mime_type), "text/plain")))); 00652 00653 if (!strcasecmp(v->name, "static_file")) { 00654 ast_string_field_set(pp_file, format, args.filename); 00655 ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename); 00656 AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry); 00657 /* Add a route for the static files, as their filenames won't change per-user */ 00658 build_route(pp_file, NULL, NULL); 00659 } else { 00660 ast_string_field_set(pp_file, format, v->name); 00661 ast_string_field_set(pp_file, template, args.filename); 00662 AST_LIST_INSERT_TAIL(&profile->dynamic_files, pp_file, entry); 00663 } 00664 } 00665 } 00666 00667 /* Append the global variables to the variables list for this profile. 00668 * This is for convenience later, when we need to provide a single 00669 * variable list for use in substitution. */ 00670 ast_mutex_lock(&globals_lock); 00671 AST_LIST_TRAVERSE(&global_variables, var, entries) { 00672 struct ast_var_t *new_var; 00673 if ((new_var = ast_var_assign(var->name, var->value))) { 00674 AST_LIST_INSERT_TAIL(profile->headp, new_var, entries); 00675 } 00676 } 00677 ast_mutex_unlock(&globals_lock); 00678 00679 ao2_link(profiles, profile); 00680 00681 profile = unref_profile(profile); 00682 }
static void build_route | ( | struct phoneprov_file * | pp_file, | |
struct user * | user, | |||
char * | uri | |||
) | [static] |
Build a route structure and add it to the list of available http routes.
pp_file | File to link to the route | |
user | User to link to the route (NULL means static route) | |
uri | URI of the route |
Definition at line 549 of file res_phoneprov.c.
References ao2_alloc, ao2_link, ast_log(), ast_string_field_init, ast_string_field_set, http_route::file, phoneprov_file::format, LOG_ERROR, route_destructor(), S_OR, unref_route(), and http_route::user.
Referenced by build_profile(), and build_user_routes().
00550 { 00551 struct http_route *route; 00552 00553 if (!(route = ao2_alloc(sizeof(*route), route_destructor))) { 00554 return; 00555 } 00556 00557 if (ast_string_field_init(route, 32)) { 00558 ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", pp_file->format); 00559 route = unref_route(route); 00560 return; 00561 } 00562 00563 ast_string_field_set(route, uri, S_OR(uri, pp_file->format)); 00564 route->user = user; 00565 route->file = pp_file; 00566 00567 ao2_link(http_routes, route); 00568 00569 route = unref_route(route); 00570 }
static struct user* build_user | ( | const char * | mac, | |
struct phone_profile * | profile | |||
) | [static, read] |
Build and return a user structure based on gathered config data.
Definition at line 821 of file res_phoneprov.c.
References ao2_alloc, ast_string_field_init, ast_string_field_set, user::macaddress, user::profile, unref_profile(), unref_user(), and user_destructor().
Referenced by set_config().
00822 { 00823 struct user *user; 00824 00825 if (!(user = ao2_alloc(sizeof(*user), user_destructor))) { 00826 profile = unref_profile(profile); 00827 return NULL; 00828 } 00829 00830 if (ast_string_field_init(user, 32)) { 00831 profile = unref_profile(profile); 00832 user = unref_user(user); 00833 return NULL; 00834 } 00835 00836 ast_string_field_set(user, macaddress, mac); 00837 user->profile = profile; /* already ref counted by find_profile */ 00838 00839 return user; 00840 }
static int build_user_routes | ( | struct user * | user | ) | [static] |
Add an http route for dynamic files attached to the profile of the user.
Definition at line 887 of file res_phoneprov.c.
References ast_free, AST_LIST_FIRST, AST_LIST_TRAVERSE, ast_str_buffer(), ast_str_create(), ast_str_substitute_variables_varshead(), build_route(), phone_profile::dynamic_files, user::extensions, phoneprov_file::format, user::profile, and str.
Referenced by set_config().
00888 { 00889 struct phoneprov_file *pp_file; 00890 struct ast_str *str; 00891 00892 if (!(str = ast_str_create(16))) { 00893 return -1; 00894 } 00895 00896 AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) { 00897 ast_str_substitute_variables_varshead(&str, 0, AST_LIST_FIRST(&user->extensions)->headp, pp_file->format); 00898 build_route(pp_file, user, ast_str_buffer(str)); 00899 } 00900 00901 ast_free(str); 00902 return 0; 00903 }
Definition at line 684 of file res_phoneprov.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_var_delete(), extension::headp, and var.
Referenced by set_config(), and user_destructor().
00685 { 00686 struct ast_var_t *var; 00687 while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) { 00688 ast_var_delete(var); 00689 } 00690 ast_free(exten->headp); 00691 ast_string_field_free_memory(exten); 00692 00693 ast_free(exten); 00694 00695 return NULL; 00696 }
static void delete_file | ( | struct phoneprov_file * | file | ) | [static] |
Definition at line 263 of file res_phoneprov.c.
References ast_string_field_free_memory, and free.
Referenced by profile_destructor().
00264 { 00265 ast_string_field_free_memory(file); 00266 free(file); 00267 }
static void delete_profiles | ( | void | ) | [static] |
Delete all phone profiles, freeing their memory.
Definition at line 1068 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_unlink, and unref_profile().
Referenced by reload(), and unload_module().
01069 { 01070 struct ao2_iterator i; 01071 struct phone_profile *profile; 01072 01073 i = ao2_iterator_init(profiles, 0); 01074 while ((profile = ao2_iterator_next(&i))) { 01075 ao2_unlink(profiles, profile); 01076 profile = unref_profile(profile); 01077 } 01078 ao2_iterator_destroy(&i); 01079 }
static void delete_routes | ( | void | ) | [static] |
Delete all http routes, freeing their memory.
Definition at line 1054 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_unlink, and unref_route().
Referenced by reload(), and unload_module().
01055 { 01056 struct ao2_iterator i; 01057 struct http_route *route; 01058 01059 i = ao2_iterator_init(http_routes, 0); 01060 while ((route = ao2_iterator_next(&i))) { 01061 ao2_unlink(http_routes, route); 01062 route = unref_route(route); 01063 } 01064 ao2_iterator_destroy(&i); 01065 }
static void delete_users | ( | void | ) | [static] |
Delete all users.
Definition at line 807 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_unlink, and unref_user().
Referenced by reload(), and unload_module().
00808 { 00809 struct ao2_iterator i; 00810 struct user *user; 00811 00812 i = ao2_iterator_init(users, 0); 00813 while ((user = ao2_iterator_next(&i))) { 00814 ao2_unlink(users, user); 00815 user = unref_user(user); 00816 } 00817 ao2_iterator_destroy(&i); 00818 }
static struct phone_profile* find_profile | ( | const char * | name | ) | [static, read] |
Return a phone profile looked up by name.
Definition at line 240 of file res_phoneprov.c.
References ao2_find, phone_profile::name, and OBJ_POINTER.
Referenced by set_config().
00241 { 00242 struct phone_profile tmp = { 00243 .name = name, 00244 }; 00245 00246 return ao2_find(profiles, &tmp, OBJ_POINTER); 00247 }
static struct user* find_user | ( | const char * | macaddress | ) | [static, read] |
Return a user looked up by name.
Definition at line 766 of file res_phoneprov.c.
References ao2_find, user::macaddress, and OBJ_POINTER.
Referenced by pp_each_extension_helper(), and set_config().
00767 { 00768 struct user tmp = { 00769 .macaddress = macaddress, 00770 }; 00771 00772 return ao2_find(users, &tmp, OBJ_POINTER); 00773 }
static char* handle_show_routes | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to list static and dynamic routes.
Definition at line 1217 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, http_route::file, FORMAT, phoneprov_file::template, unref_route(), http_route::uri, ast_cli_entry::usage, and http_route::user.
01218 { 01219 #define FORMAT "%-40.40s %-30.30s\n" 01220 struct ao2_iterator i; 01221 struct http_route *route; 01222 01223 switch(cmd) { 01224 case CLI_INIT: 01225 e->command = "phoneprov show routes"; 01226 e->usage = 01227 "Usage: phoneprov show routes\n" 01228 " Lists all registered phoneprov http routes.\n"; 01229 return NULL; 01230 case CLI_GENERATE: 01231 return NULL; 01232 } 01233 01234 /* This currently iterates over routes twice, but it is the only place I've needed 01235 * to really separate static an dynamic routes, so I've just left it this way. */ 01236 ast_cli(a->fd, "Static routes\n\n"); 01237 ast_cli(a->fd, FORMAT, "Relative URI", "Physical location"); 01238 i = ao2_iterator_init(http_routes, 0); 01239 while ((route = ao2_iterator_next(&i))) { 01240 if (!route->user) 01241 ast_cli(a->fd, FORMAT, route->uri, route->file->template); 01242 route = unref_route(route); 01243 } 01244 ao2_iterator_destroy(&i); 01245 01246 ast_cli(a->fd, "\nDynamic routes\n\n"); 01247 ast_cli(a->fd, FORMAT, "Relative URI", "Template"); 01248 01249 i = ao2_iterator_init(http_routes, 0); 01250 while ((route = ao2_iterator_next(&i))) { 01251 if (route->user) 01252 ast_cli(a->fd, FORMAT, route->uri, route->file->template); 01253 route = unref_route(route); 01254 } 01255 ao2_iterator_destroy(&i); 01256 01257 return CLI_SUCCESS; 01258 }
static int load_file | ( | const char * | filename, | |
char ** | ret | |||
) | [static] |
Read a TEXT file into a string and return the length.
Definition at line 317 of file res_phoneprov.c.
References ast_malloc, f, free, and len().
Referenced by phoneprov_callback(), and pp_each_extension_helper().
00318 { 00319 int len = 0; 00320 FILE *f; 00321 00322 if (!(f = fopen(filename, "r"))) { 00323 *ret = NULL; 00324 return -1; 00325 } 00326 00327 fseek(f, 0, SEEK_END); 00328 len = ftell(f); 00329 fseek(f, 0, SEEK_SET); 00330 if (!(*ret = ast_malloc(len + 1))) 00331 return -2; 00332 00333 if (len != fread(*ret, sizeof(char), len, f)) { 00334 free(*ret); 00335 *ret = NULL; 00336 return -3; 00337 } 00338 00339 fclose(f); 00340 00341 (*ret)[len] = '\0'; 00342 00343 return len; 00344 }
static int load_module | ( | void | ) | [static] |
Definition at line 1273 of file res_phoneprov.c.
References ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_http_uri_link(), AST_LIST_HEAD_INIT_NOLOCK, ast_mutex_init, global_variables, MAX_PROFILE_BUCKETS, MAX_ROUTE_BUCKETS, MAX_USER_BUCKETS, profile_cmp_fn(), profile_hash_fn(), routes_cmp_fn(), routes_hash_fn(), set_config(), users_cmp_fn(), and users_hash_fn().
01274 { 01275 profiles = ao2_container_alloc(MAX_PROFILE_BUCKETS, profile_hash_fn, profile_cmp_fn); 01276 01277 http_routes = ao2_container_alloc(MAX_ROUTE_BUCKETS, routes_hash_fn, routes_cmp_fn); 01278 01279 users = ao2_container_alloc(MAX_USER_BUCKETS, users_hash_fn, users_cmp_fn); 01280 01281 AST_LIST_HEAD_INIT_NOLOCK(&global_variables); 01282 ast_mutex_init(&globals_lock); 01283 01284 ast_custom_function_register(&pp_each_user_function); 01285 ast_custom_function_register(&pp_each_extension_function); 01286 ast_cli_register_multiple(pp_cli, ARRAY_LEN(pp_cli)); 01287 01288 set_config(); 01289 ast_http_uri_link(&phoneprovuri); 01290 01291 return 0; 01292 }
static int lookup_iface | ( | const char * | iface, | |
struct in_addr * | address | |||
) | [static] |
Definition at line 202 of file res_phoneprov.c.
References ast_copy_string(), ast_log(), errno, LOG_ERROR, and LOG_WARNING.
Referenced by set_config().
00203 { 00204 int mysock, res = 0; 00205 struct ifreq ifr; 00206 struct sockaddr_in *sin; 00207 00208 memset(&ifr, 0, sizeof(ifr)); 00209 ast_copy_string(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 00210 00211 mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 00212 if (mysock < 0) { 00213 ast_log(LOG_ERROR, "Failed to create socket: %s\n", strerror(errno)); 00214 return -1; 00215 } 00216 00217 res = ioctl(mysock, SIOCGIFADDR, &ifr); 00218 00219 close(mysock); 00220 00221 if (res < 0) { 00222 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno)); 00223 memcpy(address, &__ourip, sizeof(__ourip)); 00224 return -1; 00225 } else { 00226 sin = (struct sockaddr_in *)&ifr.ifr_addr; 00227 memcpy(address, &sin->sin_addr, sizeof(*address)); 00228 return 0; 00229 } 00230 }
static int phoneprov_callback | ( | struct ast_tcptls_session_instance * | ser, | |
const struct ast_http_uri * | urih, | |||
const char * | uri, | |||
enum ast_http_method | method, | |||
struct ast_variable * | get_vars, | |||
struct ast_variable * | headers | |||
) | [static] |
Callback that is executed everytime an http request is received by this module.
Definition at line 407 of file res_phoneprov.c.
References ao2_find, ast_config_AST_DATA_DIR, ast_free, ast_http_error(), AST_HTTP_GET, AST_HTTP_HEAD, ast_http_send(), ast_inet_ntoa(), AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_substitute_variables_varshead(), ast_strlen_zero(), ast_var_assign(), user::extensions, ast_tcptls_session_instance::fd, http_route::file, extension::headp, len(), load_file(), LOG_ERROR, LOG_WARNING, phoneprov_file::mime_type, name, OBJ_POINTER, phoneprov_file::template, unref_route(), http_route::uri, http_route::user, and var.
00408 { 00409 struct http_route *route; 00410 struct http_route search_route = { 00411 .uri = uri, 00412 }; 00413 struct ast_str *result; 00414 char path[PATH_MAX]; 00415 char *file = NULL; 00416 int len; 00417 int fd; 00418 struct ast_str *http_header; 00419 00420 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) { 00421 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 00422 return -1; 00423 } 00424 00425 if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) { 00426 goto out404; 00427 } 00428 00429 snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template); 00430 00431 if (!route->user) { /* Static file */ 00432 00433 fd = open(path, O_RDONLY); 00434 if (fd < 0) { 00435 goto out500; 00436 } 00437 00438 len = lseek(fd, 0, SEEK_END); 00439 lseek(fd, 0, SEEK_SET); 00440 if (len < 0) { 00441 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len); 00442 close(fd); 00443 goto out500; 00444 } 00445 00446 http_header = ast_str_create(80); 00447 ast_str_set(&http_header, 0, "Content-type: %s\r\n", 00448 route->file->mime_type); 00449 00450 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0); 00451 00452 close(fd); 00453 route = unref_route(route); 00454 return 0; 00455 } else { /* Dynamic file */ 00456 struct ast_str *tmp; 00457 00458 len = load_file(path, &file); 00459 if (len < 0) { 00460 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len); 00461 if (file) { 00462 ast_free(file); 00463 } 00464 00465 goto out500; 00466 } 00467 00468 if (!file) { 00469 goto out500; 00470 } 00471 00472 if (!(tmp = ast_str_create(len))) { 00473 if (file) { 00474 ast_free(file); 00475 } 00476 00477 goto out500; 00478 } 00479 00480 /* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to 00481 * the IP address we are listening on that the phone contacted for this config file */ 00482 if (ast_strlen_zero(global_server)) { 00483 union { 00484 struct sockaddr sa; 00485 struct sockaddr_in sa_in; 00486 } name; 00487 socklen_t namelen = sizeof(name.sa); 00488 int res; 00489 00490 if ((res = getsockname(ser->fd, &name.sa, &namelen))) { 00491 ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n"); 00492 } else { 00493 struct ast_var_t *var; 00494 struct extension *exten_iter; 00495 00496 if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) { 00497 AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) { 00498 AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries); 00499 } 00500 } 00501 } 00502 } 00503 00504 ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file); 00505 00506 if (file) { 00507 ast_free(file); 00508 } 00509 00510 http_header = ast_str_create(80); 00511 ast_str_set(&http_header, 0, "Content-type: %s\r\n", 00512 route->file->mime_type); 00513 00514 if (!(result = ast_str_create(512))) { 00515 ast_log(LOG_ERROR, "Could not create result string!\n"); 00516 if (tmp) { 00517 ast_free(tmp); 00518 } 00519 ast_free(http_header); 00520 goto out500; 00521 } 00522 ast_str_append(&result, 0, "%s", ast_str_buffer(tmp)); 00523 00524 ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0); 00525 if (tmp) { 00526 ast_free(tmp); 00527 } 00528 00529 route = unref_route(route); 00530 00531 return 0; 00532 } 00533 00534 out404: 00535 ast_http_error(ser, 404, "Not Found", "Nothing to see here. Move along."); 00536 return -1; 00537 00538 out500: 00539 route = unref_route(route); 00540 ast_http_error(ser, 500, "Internal Error", "An internal error has occured."); 00541 return -1; 00542 }
static int pp_each_extension_helper | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
struct ast_str ** | bufstr, | |||
int | len | |||
) | [static] |
A dialplan function that can be used to output a template for each extension attached to a user.
Definition at line 1139 of file res_phoneprov.c.
References args, AST_APP_ARG, ast_build_string(), ast_config_AST_DATA_DIR, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_substitute_variables_varshead(), ast_strlen_zero(), exten, user::extensions, find_user(), extension::headp, load_file(), LOG_WARNING, str, and unref_user().
Referenced by pp_each_extension_read(), and pp_each_extension_read2().
01140 { 01141 struct user *user; 01142 struct extension *exten; 01143 char path[PATH_MAX]; 01144 char *file; 01145 int filelen; 01146 struct ast_str *str; 01147 AST_DECLARE_APP_ARGS(args, 01148 AST_APP_ARG(mac); 01149 AST_APP_ARG(template); 01150 ); 01151 01152 AST_STANDARD_APP_ARGS(args, data); 01153 01154 if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) { 01155 ast_log(LOG_WARNING, "PP_EACH_EXTENSION requries both a macaddress and template filename.\n"); 01156 return 0; 01157 } 01158 01159 if (!(user = find_user(args.mac))) { 01160 ast_log(LOG_WARNING, "Could not find user with mac = '%s'\n", args.mac); 01161 return 0; 01162 } 01163 01164 snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, args.template); 01165 filelen = load_file(path, &file); 01166 if (filelen < 0) { 01167 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, filelen); 01168 if (file) { 01169 ast_free(file); 01170 } 01171 return 0; 01172 } 01173 01174 if (!file) { 01175 return 0; 01176 } 01177 01178 if (!(str = ast_str_create(filelen))) { 01179 return 0; 01180 } 01181 01182 AST_LIST_TRAVERSE(&user->extensions, exten, entry) { 01183 ast_str_substitute_variables_varshead(&str, 0, exten->headp, file); 01184 if (buf) { 01185 size_t slen = len; 01186 ast_build_string(&buf, &slen, "%s", ast_str_buffer(str)); 01187 } else { 01188 ast_str_append(bufstr, len, "%s", ast_str_buffer(str)); 01189 } 01190 } 01191 01192 ast_free(file); 01193 ast_free(str); 01194 01195 user = unref_user(user); 01196 01197 return 0; 01198 }
static int pp_each_extension_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1200 of file res_phoneprov.c.
References pp_each_extension_helper().
01201 { 01202 return pp_each_extension_helper(chan, cmd, data, buf, NULL, len); 01203 }
static int pp_each_extension_read2 | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 1205 of file res_phoneprov.c.
References pp_each_extension_helper().
01206 { 01207 return pp_each_extension_helper(chan, cmd, data, NULL, buf, len); 01208 }
static int pp_each_user_helper | ( | struct ast_channel * | chan, | |
char * | data, | |||
char * | buf, | |||
struct ast_str ** | bufstr, | |||
int | len | |||
) | [static] |
A dialplan function that can be used to print a string for each phoneprov user.
Definition at line 1082 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, args, AST_APP_ARG, ast_build_string(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_FIRST, AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_substitute_variables_varshead(), ast_strlen_zero(), user::extensions, user::macaddress, str, and unref_user().
Referenced by pp_each_user_read(), and pp_each_user_read2().
01083 { 01084 char *tmp; 01085 struct ao2_iterator i; 01086 struct user *user; 01087 struct ast_str *str; 01088 AST_DECLARE_APP_ARGS(args, 01089 AST_APP_ARG(string); 01090 AST_APP_ARG(exclude_mac); 01091 ); 01092 AST_STANDARD_APP_ARGS(args, data); 01093 01094 if (!(str = ast_str_create(16))) { 01095 return -1; 01096 } 01097 01098 /* Fix data by turning %{ into ${ */ 01099 while ((tmp = strstr(args.string, "%{"))) 01100 *tmp = '$'; 01101 01102 i = ao2_iterator_init(users, 0); 01103 while ((user = ao2_iterator_next(&i))) { 01104 if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->macaddress, args.exclude_mac)) { 01105 continue; 01106 } 01107 ast_str_substitute_variables_varshead(&str, len, AST_LIST_FIRST(&user->extensions)->headp, args.string); 01108 if (buf) { 01109 size_t slen = len; 01110 ast_build_string(&buf, &slen, "%s", ast_str_buffer(str)); 01111 } else { 01112 ast_str_append(bufstr, len, "%s", ast_str_buffer(str)); 01113 } 01114 user = unref_user(user); 01115 } 01116 ao2_iterator_destroy(&i); 01117 01118 ast_free(str); 01119 return 0; 01120 }
static int pp_each_user_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1122 of file res_phoneprov.c.
References pp_each_user_helper().
01123 { 01124 return pp_each_user_helper(chan, data, buf, NULL, len); 01125 }
static int pp_each_user_read2 | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 1127 of file res_phoneprov.c.
References pp_each_user_helper().
01128 { 01129 return pp_each_user_helper(chan, data, NULL, buf, len); 01130 }
static int profile_cmp_fn | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 256 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and phone_profile::name.
Referenced by load_module().
00257 { 00258 const struct phone_profile *profile1 = obj, *profile2 = arg; 00259 00260 return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0; 00261 }
static void profile_destructor | ( | void * | obj | ) | [static] |
Definition at line 269 of file res_phoneprov.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_var_delete(), delete_file(), phone_profile::dynamic_files, phone_profile::headp, phone_profile::static_files, and var.
Referenced by build_profile().
00270 { 00271 struct phone_profile *profile = obj; 00272 struct phoneprov_file *file; 00273 struct ast_var_t *var; 00274 00275 while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry))) 00276 delete_file(file); 00277 00278 while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry))) 00279 delete_file(file); 00280 00281 while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries))) 00282 ast_var_delete(var); 00283 00284 ast_free(profile->headp); 00285 ast_string_field_free_memory(profile); 00286 }
static int profile_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 249 of file res_phoneprov.c.
References ast_str_case_hash(), and phone_profile::name.
Referenced by load_module().
00250 { 00251 const struct phone_profile *profile = obj; 00252 00253 return ast_str_case_hash(profile->name); 00254 }
static int reload | ( | void | ) | [static] |
Definition at line 1321 of file res_phoneprov.c.
References AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, ast_var_delete(), delete_profiles(), delete_routes(), delete_users(), global_variables, set_config(), and var.
01322 { 01323 struct ast_var_t *var; 01324 01325 delete_routes(); 01326 delete_users(); 01327 delete_profiles(); 01328 01329 ast_mutex_lock(&globals_lock); 01330 while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) { 01331 ast_var_delete(var); 01332 } 01333 ast_mutex_unlock(&globals_lock); 01334 01335 set_config(); 01336 01337 return 0; 01338 }
static void route_destructor | ( | void * | obj | ) | [static] |
Definition at line 309 of file res_phoneprov.c.
References ast_string_field_free_memory.
Referenced by build_route().
00310 { 00311 struct http_route *route = obj; 00312 00313 ast_string_field_free_memory(route); 00314 }
static int routes_cmp_fn | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 302 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and http_route::uri.
Referenced by load_module().
00303 { 00304 const struct http_route *route1 = obj, *route2 = arg; 00305 00306 return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0; 00307 }
static int routes_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 295 of file res_phoneprov.c.
References ast_str_case_hash(), and http_route::uri.
Referenced by load_module().
00296 { 00297 const struct http_route *route = obj; 00298 00299 return ast_str_case_hash(route->uri); 00300 }
static int set_config | ( | void | ) | [static] |
Definition at line 906 of file res_phoneprov.c.
References add_user_extension(), ao2_link, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_inet_ntoa(), AST_LIST_INSERT_TAIL, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_true(), ast_var_assign(), ast_variable_browse(), ast_variable_retrieve(), build_extension(), build_profile(), build_user(), build_user_routes(), CONFIG_STATUS_FILEINVALID, delete_extension(), exten, find_profile(), find_user(), global_variables, LOG_ERROR, LOG_WARNING, lookup_iface(), user::macaddress, extension::name, ast_variable::name, ast_variable::next, S_OR, unref_user(), ast_variable::value, and var.
Referenced by load_module(), and reload().
00907 { 00908 struct ast_config *cfg, *phoneprov_cfg; 00909 char *cat; 00910 struct ast_variable *v; 00911 struct ast_flags config_flags = { 0 }; 00912 struct ast_var_t *var; 00913 00914 /* Try to grab the port from sip.conf. If we don't get it here, we'll set it 00915 * to whatever is set in phoneprov.conf or default to 5060 */ 00916 if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { 00917 ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport)); 00918 ast_config_destroy(cfg); 00919 } 00920 00921 if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 00922 ast_log(LOG_WARNING, "Unable to load users.conf\n"); 00923 return 0; 00924 } 00925 00926 /* Go ahead and load global variables from users.conf so we can append to profiles */ 00927 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { 00928 if (!strcasecmp(v->name, "vmexten")) { 00929 if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) { 00930 ast_mutex_lock(&globals_lock); 00931 AST_LIST_INSERT_TAIL(&global_variables, var, entries); 00932 ast_mutex_unlock(&globals_lock); 00933 } 00934 } 00935 if (!strcasecmp(v->name, "localextenlength")) { 00936 if ((var = ast_var_assign("EXTENSION_LENGTH", v->value))) 00937 ast_mutex_lock(&globals_lock); 00938 AST_LIST_INSERT_TAIL(&global_variables, var, entries); 00939 ast_mutex_unlock(&globals_lock); 00940 } 00941 } 00942 00943 if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) { 00944 ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n"); 00945 ast_config_destroy(cfg); 00946 return -1; 00947 } 00948 00949 cat = NULL; 00950 while ((cat = ast_category_browse(phoneprov_cfg, cat))) { 00951 if (!strcasecmp(cat, "general")) { 00952 for (v = ast_variable_browse(phoneprov_cfg, cat); v; v = v->next) { 00953 if (!strcasecmp(v->name, "serveraddr")) 00954 ast_copy_string(global_server, v->value, sizeof(global_server)); 00955 else if (!strcasecmp(v->name, "serveriface")) { 00956 struct in_addr addr; 00957 lookup_iface(v->value, &addr); 00958 ast_copy_string(global_server, ast_inet_ntoa(addr), sizeof(global_server)); 00959 } else if (!strcasecmp(v->name, "serverport")) 00960 ast_copy_string(global_serverport, v->value, sizeof(global_serverport)); 00961 else if (!strcasecmp(v->name, "default_profile")) 00962 ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile)); 00963 } 00964 } else 00965 build_profile(cat, ast_variable_browse(phoneprov_cfg, cat)); 00966 } 00967 00968 ast_config_destroy(phoneprov_cfg); 00969 00970 cat = NULL; 00971 while ((cat = ast_category_browse(cfg, cat))) { 00972 const char *tmp, *mac; 00973 struct user *user; 00974 struct phone_profile *profile; 00975 struct extension *exten; 00976 00977 if (!strcasecmp(cat, "general")) { 00978 continue; 00979 } 00980 00981 if (!strcasecmp(cat, "authentication")) 00982 continue; 00983 00984 if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp))) 00985 continue; 00986 00987 if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) { 00988 ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat); 00989 continue; 00990 } 00991 00992 tmp = S_OR(ast_variable_retrieve(cfg, cat, "profile"), global_default_profile); 00993 if (ast_strlen_zero(tmp)) { 00994 ast_log(LOG_WARNING, "No profile for user [%s] with mac '%s' - skipping\n", cat, mac); 00995 continue; 00996 } 00997 00998 if (!(user = find_user(mac))) { 00999 if (!(profile = find_profile(tmp))) { 01000 ast_log(LOG_WARNING, "Could not look up profile '%s' - skipping.\n", tmp); 01001 continue; 01002 } 01003 01004 if (!(user = build_user(mac, profile))) { 01005 ast_log(LOG_WARNING, "Could not create user for '%s' - skipping\n", user->macaddress); 01006 continue; 01007 } 01008 01009 if (!(exten = build_extension(cfg, cat))) { 01010 ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress); 01011 user = unref_user(user); 01012 continue; 01013 } 01014 01015 if (add_user_extension(user, exten)) { 01016 ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress); 01017 user = unref_user(user); 01018 exten = delete_extension(exten); 01019 continue; 01020 } 01021 01022 if (build_user_routes(user)) { 01023 ast_log(LOG_WARNING, "Could not create http routes for %s - skipping\n", user->macaddress); 01024 user = unref_user(user); 01025 continue; 01026 } 01027 01028 ao2_link(users, user); 01029 user = unref_user(user); 01030 } else { 01031 if (!(exten = build_extension(cfg, cat))) { 01032 ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress); 01033 user = unref_user(user); 01034 continue; 01035 } 01036 01037 if (add_user_extension(user, exten)) { 01038 ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress); 01039 user = unref_user(user); 01040 exten = delete_extension(exten); 01041 continue; 01042 } 01043 01044 user = unref_user(user); 01045 } 01046 } 01047 01048 ast_config_destroy(cfg); 01049 01050 return 0; 01051 }
static void set_timezone_variables | ( | struct varshead * | headp, | |
const char * | zone | |||
) | [static] |
Set all timezone-related variables based on a zone (i.e. America/New_York).
headp | pointer to list of user variables | |
zone | A time zone. NULL sets variables based on timezone of the machine |
Definition at line 350 of file res_phoneprov.c.
References ast_get_dst_info(), AST_LIST_INSERT_TAIL, ast_localtime(), ast_var_assign(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_mon, and var.
Referenced by build_extension().
00351 { 00352 time_t utc_time; 00353 int dstenable; 00354 time_t dststart; 00355 time_t dstend; 00356 struct ast_tm tm_info; 00357 int tzoffset; 00358 char buffer[21]; 00359 struct ast_var_t *var; 00360 struct timeval when; 00361 00362 time(&utc_time); 00363 ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone); 00364 snprintf(buffer, sizeof(buffer), "%d", tzoffset); 00365 var = ast_var_assign("TZOFFSET", buffer); 00366 if (var) 00367 AST_LIST_INSERT_TAIL(headp, var, entries); 00368 00369 if (!dstenable) 00370 return; 00371 00372 if ((var = ast_var_assign("DST_ENABLE", "1"))) 00373 AST_LIST_INSERT_TAIL(headp, var, entries); 00374 00375 when.tv_sec = dststart; 00376 ast_localtime(&when, &tm_info, zone); 00377 00378 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1); 00379 if ((var = ast_var_assign("DST_START_MONTH", buffer))) 00380 AST_LIST_INSERT_TAIL(headp, var, entries); 00381 00382 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday); 00383 if ((var = ast_var_assign("DST_START_MDAY", buffer))) 00384 AST_LIST_INSERT_TAIL(headp, var, entries); 00385 00386 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour); 00387 if ((var = ast_var_assign("DST_START_HOUR", buffer))) 00388 AST_LIST_INSERT_TAIL(headp, var, entries); 00389 00390 when.tv_sec = dstend; 00391 ast_localtime(&when, &tm_info, zone); 00392 00393 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1); 00394 if ((var = ast_var_assign("DST_END_MONTH", buffer))) 00395 AST_LIST_INSERT_TAIL(headp, var, entries); 00396 00397 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday); 00398 if ((var = ast_var_assign("DST_END_MDAY", buffer))) 00399 AST_LIST_INSERT_TAIL(headp, var, entries); 00400 00401 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour); 00402 if ((var = ast_var_assign("DST_END_HOUR", buffer))) 00403 AST_LIST_INSERT_TAIL(headp, var, entries); 00404 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1294 of file res_phoneprov.c.
References ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_http_uri_unlink(), AST_LIST_REMOVE_HEAD, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_var_delete(), delete_profiles(), delete_routes(), delete_users(), global_variables, and var.
01295 { 01296 struct ast_var_t *var; 01297 01298 ast_http_uri_unlink(&phoneprovuri); 01299 ast_custom_function_unregister(&pp_each_user_function); 01300 ast_custom_function_unregister(&pp_each_extension_function); 01301 ast_cli_unregister_multiple(pp_cli, ARRAY_LEN(pp_cli)); 01302 01303 delete_routes(); 01304 delete_users(); 01305 delete_profiles(); 01306 ao2_ref(profiles, -1); 01307 ao2_ref(http_routes, -1); 01308 ao2_ref(users, -1); 01309 01310 ast_mutex_lock(&globals_lock); 01311 while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) { 01312 ast_var_delete(var); 01313 } 01314 ast_mutex_unlock(&globals_lock); 01315 01316 ast_mutex_destroy(&globals_lock); 01317 01318 return 0; 01319 }
static struct phone_profile* unref_profile | ( | struct phone_profile * | prof | ) | [static, read] |
Definition at line 232 of file res_phoneprov.c.
References ao2_ref.
Referenced by build_profile(), build_user(), delete_profiles(), and user_destructor().
00233 { 00234 ao2_ref(prof, -1); 00235 00236 return NULL; 00237 }
static struct http_route* unref_route | ( | struct http_route * | route | ) | [static, read] |
Definition at line 288 of file res_phoneprov.c.
References ao2_ref.
Referenced by build_route(), delete_routes(), handle_show_routes(), and phoneprov_callback().
00289 { 00290 ao2_ref(route, -1); 00291 00292 return NULL; 00293 }
Definition at line 758 of file res_phoneprov.c.
References ao2_ref.
Referenced by build_user(), delete_users(), pp_each_extension_helper(), pp_each_user_helper(), and set_config().
00759 { 00760 ao2_ref(user, -1); 00761 00762 return NULL; 00763 }
static void user_destructor | ( | void * | obj | ) | [static] |
Free all memory associated with a user.
Definition at line 790 of file res_phoneprov.c.
References AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, delete_extension(), exten, user::extensions, user::profile, and unref_profile().
Referenced by build_user().
00791 { 00792 struct user *user = obj; 00793 struct extension *exten; 00794 00795 while ((exten = AST_LIST_REMOVE_HEAD(&user->extensions, entry))) { 00796 exten = delete_extension(exten); 00797 } 00798 00799 if (user->profile) { 00800 user->profile = unref_profile(user->profile); 00801 } 00802 00803 ast_string_field_free_memory(user); 00804 }
static int users_cmp_fn | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 782 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and user::macaddress.
Referenced by load_module().
00783 { 00784 const struct user *user1 = obj, *user2 = arg; 00785 00786 return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0; 00787 }
static int users_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 775 of file res_phoneprov.c.
References ast_str_case_hash(), and user::macaddress.
Referenced by load_module().
00776 { 00777 const struct user *user = obj; 00778 00779 return ast_str_case_hash(user->macaddress); 00780 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP Phone Provisioning" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1344 of file res_phoneprov.c.
struct in_addr __ourip = { .s_addr = 0x00000000, } [static] |
for use in lookup_iface
Definition at line 104 of file res_phoneprov.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1344 of file res_phoneprov.c.
char global_default_profile[80] = "" [static] |
Default profile to use if one isn't specified
Definition at line 195 of file res_phoneprov.c.
char global_server[80] = "" [static] |
Server to substitute into templates
Definition at line 193 of file res_phoneprov.c.
char global_serverport[6] = "" [static] |
Server port to substitute into templates
Definition at line 194 of file res_phoneprov.c.
struct varshead global_variables [static] |
List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH.
Definition at line 198 of file res_phoneprov.c.
Referenced by build_profile(), load_module(), reload(), set_config(), and unload_module().
ast_mutex_t globals_lock [static] |
Definition at line 199 of file res_phoneprov.c.
Referenced by load_config(), and set_pvt_defaults().
struct ao2_container* http_routes [static] |
Definition at line 190 of file res_phoneprov.c.
struct ast_http_uri phoneprovuri [static] |
Definition at line 1264 of file res_phoneprov.c.
struct ast_cli_entry pp_cli[] [static] |
{ AST_CLI_DEFINE(handle_show_routes, "Show registered phoneprov http routes"), }
Definition at line 1260 of file res_phoneprov.c.
struct ast_custom_function pp_each_extension_function [static] |
{ .name = "PP_EACH_EXTENSION", .read = pp_each_extension_read, .read2 = pp_each_extension_read2, }
Definition at line 1210 of file res_phoneprov.c.
struct ast_custom_function pp_each_user_function [static] |
{ .name = "PP_EACH_USER", .read = pp_each_user_read, .read2 = pp_each_user_read2, }
Definition at line 1132 of file res_phoneprov.c.
struct pp_variable_lookup pp_variable_list[] [static] |
Lookup table to translate between users.conf property names and variables for use in phoneprov templates.
Referenced by build_extension().
struct ao2_container* profiles [static] |
Definition at line 189 of file res_phoneprov.c.
struct ao2_container* users [static] |
Definition at line 191 of file res_phoneprov.c.