#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 = AST_BUILDOPT_SUM, .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 |
Definition in file res_phoneprov.c.
| #define FORMAT "%-40.40s %-30.30s\n" |
| #define MAX_PROFILE_BUCKETS 17 |
| #define MAX_ROUTE_BUCKETS 563 |
| #define MAX_USER_BUCKETS 563 |
Definition at line 63 of file res_phoneprov.c.
| #define VAR_BUF_SIZE 4096 |
Definition at line 66 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 104 of file res_phoneprov.c.
00104 { 00105 PP_MACADDRESS, 00106 PP_USERNAME, 00107 PP_FULLNAME, 00108 PP_SECRET, 00109 PP_LABEL, 00110 PP_CALLERID, 00111 PP_TIMEZONE, 00112 PP_LINENUMBER, 00113 PP_LINEKEYS, 00114 PP_VAR_LIST_LENGTH, /* This entry must always be the last in the list */ 00115 };
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1360 of file res_phoneprov.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1360 of file res_phoneprov.c.
Add an extension to a user ordered by index/linenumber.
Definition at line 859 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(), ast_var_t::entries, 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().
00860 { 00861 struct ast_var_t *var; 00862 struct ast_str *str = ast_str_create(16); 00863 00864 if (!str) { 00865 return -1; 00866 } 00867 00868 /* Append profile variables here, and substitute variables on profile 00869 * setvars, so that we can use user specific variables in them */ 00870 AST_LIST_TRAVERSE(user->profile->headp, var, entries) { 00871 struct ast_var_t *var2; 00872 00873 ast_str_substitute_variables_varshead(&str, 0, exten->headp, var->value); 00874 if ((var2 = ast_var_assign(var->name, ast_str_buffer(str)))) { 00875 AST_LIST_INSERT_TAIL(exten->headp, var2, entries); 00876 } 00877 } 00878 00879 ast_free(str); 00880 00881 if (AST_LIST_EMPTY(&user->extensions)) { 00882 AST_LIST_INSERT_HEAD(&user->extensions, exten, entry); 00883 } else { 00884 struct extension *exten_iter; 00885 00886 AST_LIST_TRAVERSE_SAFE_BEGIN(&user->extensions, exten_iter, entry) { 00887 if (exten->index < exten_iter->index) { 00888 AST_LIST_INSERT_BEFORE_CURRENT(exten, entry); 00889 } else if (exten->index == exten_iter->index) { 00890 ast_log(LOG_WARNING, "Duplicate linenumber=%d for %s\n", exten->index, user->macaddress); 00891 return -1; 00892 } else if (!AST_LIST_NEXT(exten_iter, entry)) { 00893 AST_LIST_INSERT_TAIL(&user->extensions, exten, entry); 00894 } 00895 } 00896 AST_LIST_TRAVERSE_SAFE_END; 00897 } 00898 00899 return 0; 00900 }
| static struct extension* build_extension | ( | struct ast_config * | cfg, | |
| const char * | name | |||
| ) | [static, read] |
Definition at line 708 of file res_phoneprov.c.
References ast_calloc, ast_free, AST_LIST_INSERT_TAIL, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_var_assign(), ast_variable_retrieve(), ast_var_t::entries, 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().
00709 { 00710 struct extension *exten; 00711 struct ast_var_t *var; 00712 const char *tmp; 00713 int i; 00714 00715 if (!(exten = ast_calloc(1, sizeof(*exten)))) { 00716 return NULL; 00717 } 00718 00719 if (ast_string_field_init(exten, 32)) { 00720 ast_free(exten); 00721 exten = NULL; 00722 return NULL; 00723 } 00724 00725 ast_string_field_set(exten, name, name); 00726 00727 if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) { 00728 ast_free(exten); 00729 exten = NULL; 00730 return NULL; 00731 } 00732 00733 for (i = 0; i < PP_VAR_LIST_LENGTH; i++) { 00734 tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var); 00735 00736 /* If we didn't get a USERNAME variable, set it to the user->name */ 00737 if (i == PP_USERNAME && !tmp) { 00738 if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) { 00739 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00740 } 00741 continue; 00742 } else if (i == PP_TIMEZONE) { 00743 /* perfectly ok if tmp is NULL, will set variables based on server's time zone */ 00744 set_timezone_variables(exten->headp, tmp); 00745 } else if (i == PP_LINENUMBER) { 00746 if (!tmp) { 00747 tmp = "1"; 00748 } 00749 exten->index = atoi(tmp); 00750 } else if (i == PP_LINEKEYS) { 00751 if (!tmp) { 00752 tmp = "1"; 00753 } 00754 } 00755 00756 if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) { 00757 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00758 } 00759 } 00760 00761 if (!ast_strlen_zero(global_server)) { 00762 if ((var = ast_var_assign("SERVER", global_server))) 00763 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00764 } 00765 00766 if (!ast_strlen_zero(global_serverport)) { 00767 if ((var = ast_var_assign("SERVER_PORT", global_serverport))) 00768 AST_LIST_INSERT_TAIL(exten->headp, var, entries); 00769 } 00770 00771 return exten; 00772 }
| 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 581 of file res_phoneprov.c.
References ao2_alloc, ao2_link, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, ast_free, 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, ast_var_t::entries, 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().
00582 { 00583 struct phone_profile *profile; 00584 struct ast_var_t *var; 00585 00586 if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) { 00587 return; 00588 } 00589 00590 if (ast_string_field_init(profile, 32)) { 00591 profile = unref_profile(profile); 00592 return; 00593 } 00594 00595 if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) { 00596 profile = unref_profile(profile); 00597 return; 00598 } 00599 00600 AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files); 00601 AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files); 00602 00603 ast_string_field_set(profile, name, name); 00604 for (; v; v = v->next) { 00605 if (!strcasecmp(v->name, "mime_type")) { 00606 ast_string_field_set(profile, default_mime_type, v->value); 00607 } else if (!strcasecmp(v->name, "setvar")) { 00608 struct ast_var_t *variable; 00609 char *value_copy = ast_strdupa(v->value); 00610 00611 AST_DECLARE_APP_ARGS(args, 00612 AST_APP_ARG(varname); 00613 AST_APP_ARG(varval); 00614 ); 00615 00616 AST_NONSTANDARD_APP_ARGS(args, value_copy, '='); 00617 do { 00618 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval)) 00619 break; 00620 args.varname = ast_strip(args.varname); 00621 args.varval = ast_strip(args.varval); 00622 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval)) 00623 break; 00624 if ((variable = ast_var_assign(args.varname, args.varval))) 00625 AST_LIST_INSERT_TAIL(profile->headp, variable, entries); 00626 } while (0); 00627 } else if (!strcasecmp(v->name, "staticdir")) { 00628 ast_string_field_set(profile, staticdir, v->value); 00629 } else { 00630 struct phoneprov_file *pp_file; 00631 char *file_extension; 00632 char *value_copy = ast_strdupa(v->value); 00633 00634 AST_DECLARE_APP_ARGS(args, 00635 AST_APP_ARG(filename); 00636 AST_APP_ARG(mimetype); 00637 ); 00638 00639 if (!(pp_file = ast_calloc(1, sizeof(*pp_file)))) { 00640 profile = unref_profile(profile); 00641 return; 00642 } 00643 if (ast_string_field_init(pp_file, 32)) { 00644 ast_free(pp_file); 00645 profile = unref_profile(profile); 00646 return; 00647 } 00648 00649 if ((file_extension = strrchr(pp_file->format, '.'))) 00650 file_extension++; 00651 00652 AST_STANDARD_APP_ARGS(args, value_copy); 00653 00654 /* Mime type order of preference 00655 * 1) Specific mime-type defined for file in profile 00656 * 2) Mime determined by extension 00657 * 3) Default mime type specified in profile 00658 * 4) text/plain 00659 */ 00660 ast_string_field_set(pp_file, mime_type, S_OR(args.mimetype, 00661 (S_OR(S_OR(ast_http_ftype2mtype(file_extension), profile->default_mime_type), "text/plain")))); 00662 00663 if (!strcasecmp(v->name, "static_file")) { 00664 ast_string_field_set(pp_file, format, args.filename); 00665 ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename); 00666 AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry); 00667 /* Add a route for the static files, as their filenames won't change per-user */ 00668 build_route(pp_file, NULL, NULL); 00669 } else { 00670 ast_string_field_set(pp_file, format, v->name); 00671 ast_string_field_set(pp_file, template, args.filename); 00672 AST_LIST_INSERT_TAIL(&profile->dynamic_files, pp_file, entry); 00673 } 00674 } 00675 } 00676 00677 /* Append the global variables to the variables list for this profile. 00678 * This is for convenience later, when we need to provide a single 00679 * variable list for use in substitution. */ 00680 ast_mutex_lock(&globals_lock); 00681 AST_LIST_TRAVERSE(&global_variables, var, entries) { 00682 struct ast_var_t *new_var; 00683 if ((new_var = ast_var_assign(var->name, var->value))) { 00684 AST_LIST_INSERT_TAIL(profile->headp, new_var, entries); 00685 } 00686 } 00687 ast_mutex_unlock(&globals_lock); 00688 00689 ao2_link(profiles, profile); 00690 00691 profile = unref_profile(profile); 00692 }
| 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 554 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.
00555 { 00556 struct http_route *route; 00557 00558 if (!(route = ao2_alloc(sizeof(*route), route_destructor))) { 00559 return; 00560 } 00561 00562 if (ast_string_field_init(route, 32)) { 00563 ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", pp_file->format); 00564 route = unref_route(route); 00565 return; 00566 } 00567 00568 ast_string_field_set(route, uri, S_OR(uri, pp_file->format)); 00569 route->user = user; 00570 route->file = pp_file; 00571 00572 ao2_link(http_routes, route); 00573 00574 route = unref_route(route); 00575 }
| 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 837 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().
00838 { 00839 struct user *user; 00840 00841 if (!(user = ao2_alloc(sizeof(*user), user_destructor))) { 00842 profile = unref_profile(profile); 00843 return NULL; 00844 } 00845 00846 if (ast_string_field_init(user, 32)) { 00847 profile = unref_profile(profile); 00848 user = unref_user(user); 00849 return NULL; 00850 } 00851 00852 ast_string_field_set(user, macaddress, mac); 00853 user->profile = profile; /* already ref counted by find_profile */ 00854 00855 return user; 00856 }
| 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 903 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().
00904 { 00905 struct phoneprov_file *pp_file; 00906 struct ast_str *str; 00907 00908 if (!(str = ast_str_create(16))) { 00909 return -1; 00910 } 00911 00912 AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) { 00913 ast_str_substitute_variables_varshead(&str, 0, AST_LIST_FIRST(&user->extensions)->headp, pp_file->format); 00914 build_route(pp_file, user, ast_str_buffer(str)); 00915 } 00916 00917 ast_free(str); 00918 return 0; 00919 }
Definition at line 694 of file res_phoneprov.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_var_delete(), ast_var_t::entries, extension::headp, and var.
Referenced by set_config(), and user_destructor().
00695 { 00696 struct ast_var_t *var; 00697 while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) { 00698 ast_var_delete(var); 00699 } 00700 ast_free(exten->headp); 00701 ast_string_field_free_memory(exten); 00702 00703 ast_free(exten); 00704 00705 return NULL; 00706 }
| static void delete_file | ( | struct phoneprov_file * | file | ) | [static] |
Definition at line 259 of file res_phoneprov.c.
References ast_string_field_free_memory, and free.
Referenced by profile_destructor().
00260 { 00261 ast_string_field_free_memory(file); 00262 free(file); 00263 }
| static void delete_profiles | ( | void | ) | [static] |
Delete all phone profiles, freeing their memory.
Definition at line 1084 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().
01085 { 01086 struct ao2_iterator i; 01087 struct phone_profile *profile; 01088 01089 i = ao2_iterator_init(profiles, 0); 01090 while ((profile = ao2_iterator_next(&i))) { 01091 ao2_unlink(profiles, profile); 01092 profile = unref_profile(profile); 01093 } 01094 ao2_iterator_destroy(&i); 01095 }
| static void delete_routes | ( | void | ) | [static] |
Delete all http routes, freeing their memory.
Definition at line 1070 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().
01071 { 01072 struct ao2_iterator i; 01073 struct http_route *route; 01074 01075 i = ao2_iterator_init(http_routes, 0); 01076 while ((route = ao2_iterator_next(&i))) { 01077 ao2_unlink(http_routes, route); 01078 route = unref_route(route); 01079 } 01080 ao2_iterator_destroy(&i); 01081 }
| static void delete_users | ( | void | ) | [static] |
Delete all users.
Definition at line 823 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_unlink, and unref_user().
00824 { 00825 struct ao2_iterator i; 00826 struct user *user; 00827 00828 i = ao2_iterator_init(users, 0); 00829 while ((user = ao2_iterator_next(&i))) { 00830 ao2_unlink(users, user); 00831 user = unref_user(user); 00832 } 00833 ao2_iterator_destroy(&i); 00834 }
| static struct phone_profile* find_profile | ( | const char * | name | ) | [static, read] |
Return a phone profile looked up by name.
Definition at line 236 of file res_phoneprov.c.
References ao2_find, phone_profile::name, and OBJ_POINTER.
Referenced by set_config().
00237 { 00238 struct phone_profile tmp = { 00239 .name = name, 00240 }; 00241 00242 return ao2_find(profiles, &tmp, OBJ_POINTER); 00243 }
| static struct user* find_user | ( | const char * | macaddress | ) | [static, read] |
Return a user looked up by name.
Definition at line 782 of file res_phoneprov.c.
References ao2_find, user::macaddress, and OBJ_POINTER.
00783 { 00784 struct user tmp = { 00785 .macaddress = macaddress, 00786 }; 00787 00788 return ao2_find(users, &tmp, OBJ_POINTER); 00789 }
| 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 1233 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.
01234 { 01235 #define FORMAT "%-40.40s %-30.30s\n" 01236 struct ao2_iterator i; 01237 struct http_route *route; 01238 01239 switch(cmd) { 01240 case CLI_INIT: 01241 e->command = "phoneprov show routes"; 01242 e->usage = 01243 "Usage: phoneprov show routes\n" 01244 " Lists all registered phoneprov http routes.\n"; 01245 return NULL; 01246 case CLI_GENERATE: 01247 return NULL; 01248 } 01249 01250 /* This currently iterates over routes twice, but it is the only place I've needed 01251 * to really separate static an dynamic routes, so I've just left it this way. */ 01252 ast_cli(a->fd, "Static routes\n\n"); 01253 ast_cli(a->fd, FORMAT, "Relative URI", "Physical location"); 01254 i = ao2_iterator_init(http_routes, 0); 01255 while ((route = ao2_iterator_next(&i))) { 01256 if (!route->user) 01257 ast_cli(a->fd, FORMAT, route->uri, route->file->template); 01258 route = unref_route(route); 01259 } 01260 ao2_iterator_destroy(&i); 01261 01262 ast_cli(a->fd, "\nDynamic routes\n\n"); 01263 ast_cli(a->fd, FORMAT, "Relative URI", "Template"); 01264 01265 i = ao2_iterator_init(http_routes, 0); 01266 while ((route = ao2_iterator_next(&i))) { 01267 if (route->user) 01268 ast_cli(a->fd, FORMAT, route->uri, route->file->template); 01269 route = unref_route(route); 01270 } 01271 ao2_iterator_destroy(&i); 01272 01273 return CLI_SUCCESS; 01274 }
| static int load_file | ( | const char * | filename, | |
| char ** | ret | |||
| ) | [static] |
Read a TEXT file into a string and return the length.
Definition at line 313 of file res_phoneprov.c.
References ast_malloc, f, free, and len().
Referenced by phoneprov_callback(), and pp_each_extension_helper().
00314 { 00315 int len = 0; 00316 FILE *f; 00317 00318 if (!(f = fopen(filename, "r"))) { 00319 *ret = NULL; 00320 return -1; 00321 } 00322 00323 fseek(f, 0, SEEK_END); 00324 len = ftell(f); 00325 fseek(f, 0, SEEK_SET); 00326 if (!(*ret = ast_malloc(len + 1))) 00327 return -2; 00328 00329 if (len != fread(*ret, sizeof(char), len, f)) { 00330 free(*ret); 00331 *ret = NULL; 00332 return -3; 00333 } 00334 00335 fclose(f); 00336 00337 (*ret)[len] = '\0'; 00338 00339 return len; 00340 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1289 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().
01290 { 01291 profiles = ao2_container_alloc(MAX_PROFILE_BUCKETS, profile_hash_fn, profile_cmp_fn); 01292 01293 http_routes = ao2_container_alloc(MAX_ROUTE_BUCKETS, routes_hash_fn, routes_cmp_fn); 01294 01295 users = ao2_container_alloc(MAX_USER_BUCKETS, users_hash_fn, users_cmp_fn); 01296 01297 AST_LIST_HEAD_INIT_NOLOCK(&global_variables); 01298 ast_mutex_init(&globals_lock); 01299 01300 ast_custom_function_register(&pp_each_user_function); 01301 ast_custom_function_register(&pp_each_extension_function); 01302 ast_cli_register_multiple(pp_cli, ARRAY_LEN(pp_cli)); 01303 01304 set_config(); 01305 ast_http_uri_link(&phoneprovuri); 01306 01307 return 0; 01308 }
| static int lookup_iface | ( | const char * | iface, | |
| struct in_addr * | address | |||
| ) | [static] |
Definition at line 198 of file res_phoneprov.c.
References ast_copy_string(), ast_log(), errno, LOG_ERROR, and LOG_WARNING.
Referenced by set_config().
00199 { 00200 int mysock, res = 0; 00201 struct ifreq ifr; 00202 struct sockaddr_in *sin; 00203 00204 memset(&ifr, 0, sizeof(ifr)); 00205 ast_copy_string(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); 00206 00207 mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 00208 if (mysock < 0) { 00209 ast_log(LOG_ERROR, "Failed to create socket: %s\n", strerror(errno)); 00210 return -1; 00211 } 00212 00213 res = ioctl(mysock, SIOCGIFADDR, &ifr); 00214 00215 close(mysock); 00216 00217 if (res < 0) { 00218 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno)); 00219 memcpy(address, &__ourip, sizeof(__ourip)); 00220 return -1; 00221 } else { 00222 sin = (struct sockaddr_in *)&ifr.ifr_addr; 00223 memcpy(address, &sin->sin_addr, sizeof(*address)); 00224 return 0; 00225 } 00226 }
| 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 403 of file res_phoneprov.c.
References ao2_find, ast_config_AST_DATA_DIR, ast_debug, 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(), buf, errno, user::extensions, ast_tcptls_session_instance::f, 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.
00404 { 00405 struct http_route *route; 00406 struct http_route search_route = { 00407 .uri = uri, 00408 }; 00409 struct ast_str *result; 00410 char path[PATH_MAX]; 00411 char *file = NULL; 00412 int len; 00413 int fd; 00414 char buf[256]; 00415 struct ast_str *http_header; 00416 00417 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) { 00418 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 00419 return -1; 00420 } 00421 00422 if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) { 00423 goto out404; 00424 } 00425 00426 snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template); 00427 00428 if (!route->user) { /* Static file */ 00429 00430 fd = open(path, O_RDONLY); 00431 if (fd < 0) { 00432 goto out500; 00433 } 00434 00435 len = lseek(fd, 0, SEEK_END); 00436 lseek(fd, 0, SEEK_SET); 00437 if (len < 0) { 00438 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len); 00439 close(fd); 00440 goto out500; 00441 } 00442 00443 http_header = ast_str_create(80); 00444 ast_str_set(&http_header, 0, "Content-type: %s\r\n", 00445 route->file->mime_type); 00446 00447 while ((len = read(fd, buf, sizeof(buf))) > 0) { 00448 if (fwrite(buf, 1, len, ser->f) != len) { 00449 if (errno != EPIPE) { 00450 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00451 } else { 00452 ast_debug(3, "Requester closed the connection while downloading '%s'\n", path); 00453 } 00454 break; 00455 } 00456 } 00457 00458 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0); 00459 close(fd); 00460 route = unref_route(route); 00461 return 0; 00462 } else { /* Dynamic file */ 00463 struct ast_str *tmp; 00464 00465 len = load_file(path, &file); 00466 if (len < 0) { 00467 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len); 00468 if (file) { 00469 ast_free(file); 00470 } 00471 00472 goto out500; 00473 } 00474 00475 if (!file) { 00476 goto out500; 00477 } 00478 00479 if (!(tmp = ast_str_create(len))) { 00480 if (file) { 00481 ast_free(file); 00482 } 00483 00484 goto out500; 00485 } 00486 00487 /* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to 00488 * the IP address we are listening on that the phone contacted for this config file */ 00489 if (ast_strlen_zero(global_server)) { 00490 union { 00491 struct sockaddr sa; 00492 struct sockaddr_in sa_in; 00493 } name; 00494 socklen_t namelen = sizeof(name.sa); 00495 int res; 00496 00497 if ((res = getsockname(ser->fd, &name.sa, &namelen))) { 00498 ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n"); 00499 } else { 00500 struct ast_var_t *var; 00501 struct extension *exten_iter; 00502 00503 if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) { 00504 AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) { 00505 AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries); 00506 } 00507 } 00508 } 00509 } 00510 00511 ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file); 00512 00513 if (file) { 00514 ast_free(file); 00515 } 00516 00517 ast_str_set(&http_header, 0, "Content-type: %s\r\n", 00518 route->file->mime_type); 00519 00520 if (!(result = ast_str_create(512))) { 00521 ast_log(LOG_ERROR, "Could not create result string!\n"); 00522 if (tmp) { 00523 ast_free(tmp); 00524 } 00525 goto out500; 00526 } 00527 ast_str_append(&result, 0, "%s", ast_str_buffer(tmp)); 00528 00529 ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0); 00530 if (tmp) { 00531 ast_free(tmp); 00532 } 00533 00534 route = unref_route(route); 00535 00536 return 0; 00537 } 00538 00539 out404: 00540 ast_http_error(ser, 404, "Not Found", "Nothing to see here. Move along."); 00541 return -1; 00542 00543 out500: 00544 route = unref_route(route); 00545 ast_http_error(ser, 500, "Internal Error", "An internal error has occured."); 00546 return -1; 00547 }
| 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 1155 of file res_phoneprov.c.
References 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().
01156 { 01157 struct user *user; 01158 struct extension *exten; 01159 char path[PATH_MAX]; 01160 char *file; 01161 int filelen; 01162 struct ast_str *str; 01163 AST_DECLARE_APP_ARGS(args, 01164 AST_APP_ARG(mac); 01165 AST_APP_ARG(template); 01166 ); 01167 01168 AST_STANDARD_APP_ARGS(args, data); 01169 01170 if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) { 01171 ast_log(LOG_WARNING, "PP_EACH_EXTENSION requries both a macaddress and template filename.\n"); 01172 return 0; 01173 } 01174 01175 if (!(user = find_user(args.mac))) { 01176 ast_log(LOG_WARNING, "Could not find user with mac = '%s'\n", args.mac); 01177 return 0; 01178 } 01179 01180 snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, args.template); 01181 filelen = load_file(path, &file); 01182 if (filelen < 0) { 01183 ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, filelen); 01184 if (file) { 01185 ast_free(file); 01186 } 01187 return 0; 01188 } 01189 01190 if (!file) { 01191 return 0; 01192 } 01193 01194 if (!(str = ast_str_create(filelen))) { 01195 return 0; 01196 } 01197 01198 AST_LIST_TRAVERSE(&user->extensions, exten, entry) { 01199 ast_str_substitute_variables_varshead(&str, 0, exten->headp, file); 01200 if (buf) { 01201 size_t slen = len; 01202 ast_build_string(&buf, &slen, "%s", ast_str_buffer(str)); 01203 } else { 01204 ast_str_append(bufstr, len, "%s", ast_str_buffer(str)); 01205 } 01206 } 01207 01208 ast_free(file); 01209 ast_free(str); 01210 01211 user = unref_user(user); 01212 01213 return 0; 01214 }
| static int pp_each_extension_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 1216 of file res_phoneprov.c.
References pp_each_extension_helper().
01217 { 01218 return pp_each_extension_helper(chan, cmd, data, buf, NULL, len); 01219 }
| 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 1221 of file res_phoneprov.c.
References pp_each_extension_helper().
01222 { 01223 return pp_each_extension_helper(chan, cmd, data, NULL, buf, len); 01224 }
| 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 1098 of file res_phoneprov.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, 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().
01099 { 01100 char *tmp; 01101 struct ao2_iterator i; 01102 struct user *user; 01103 struct ast_str *str; 01104 AST_DECLARE_APP_ARGS(args, 01105 AST_APP_ARG(string); 01106 AST_APP_ARG(exclude_mac); 01107 ); 01108 AST_STANDARD_APP_ARGS(args, data); 01109 01110 if (!(str = ast_str_create(16))) { 01111 return -1; 01112 } 01113 01114 /* Fix data by turning %{ into ${ */ 01115 while ((tmp = strstr(args.string, "%{"))) 01116 *tmp = '$'; 01117 01118 i = ao2_iterator_init(users, 0); 01119 while ((user = ao2_iterator_next(&i))) { 01120 if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->macaddress, args.exclude_mac)) { 01121 continue; 01122 } 01123 ast_str_substitute_variables_varshead(&str, len, AST_LIST_FIRST(&user->extensions)->headp, args.string); 01124 if (buf) { 01125 size_t slen = len; 01126 ast_build_string(&buf, &slen, "%s", ast_str_buffer(str)); 01127 } else { 01128 ast_str_append(bufstr, len, "%s", ast_str_buffer(str)); 01129 } 01130 user = unref_user(user); 01131 } 01132 ao2_iterator_destroy(&i); 01133 01134 ast_free(str); 01135 return 0; 01136 }
| static int pp_each_user_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 1138 of file res_phoneprov.c.
References pp_each_user_helper().
01139 { 01140 return pp_each_user_helper(chan, data, buf, NULL, len); 01141 }
| 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 1143 of file res_phoneprov.c.
References pp_each_user_helper().
01144 { 01145 return pp_each_user_helper(chan, data, NULL, buf, len); 01146 }
| static int profile_cmp_fn | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 252 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and phone_profile::name.
Referenced by load_module().
00253 { 00254 const struct phone_profile *profile1 = obj, *profile2 = arg; 00255 00256 return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0; 00257 }
| static void profile_destructor | ( | void * | obj | ) | [static] |
Definition at line 265 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, ast_var_t::entries, phone_profile::headp, phone_profile::static_files, and var.
Referenced by build_profile().
00266 { 00267 struct phone_profile *profile = obj; 00268 struct phoneprov_file *file; 00269 struct ast_var_t *var; 00270 00271 while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry))) 00272 delete_file(file); 00273 00274 while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry))) 00275 delete_file(file); 00276 00277 while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries))) 00278 ast_var_delete(var); 00279 00280 ast_free(profile->headp); 00281 ast_string_field_free_memory(profile); 00282 }
| static int profile_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 245 of file res_phoneprov.c.
References ast_str_case_hash(), and phone_profile::name.
Referenced by load_module().
00246 { 00247 const struct phone_profile *profile = obj; 00248 00249 return ast_str_case_hash(profile->name); 00250 }
| static int reload | ( | void | ) | [static] |
Definition at line 1337 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(), ast_var_t::entries, global_variables, set_config(), and var.
01338 { 01339 struct ast_var_t *var; 01340 01341 delete_routes(); 01342 delete_users(); 01343 delete_profiles(); 01344 01345 ast_mutex_lock(&globals_lock); 01346 while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) { 01347 ast_var_delete(var); 01348 } 01349 ast_mutex_unlock(&globals_lock); 01350 01351 set_config(); 01352 01353 return 0; 01354 }
| static void route_destructor | ( | void * | obj | ) | [static] |
Definition at line 305 of file res_phoneprov.c.
References ast_string_field_free_memory.
Referenced by build_route().
00306 { 00307 struct http_route *route = obj; 00308 00309 ast_string_field_free_memory(route); 00310 }
| static int routes_cmp_fn | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 298 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and http_route::uri.
Referenced by load_module().
00299 { 00300 const struct http_route *route1 = obj, *route2 = arg; 00301 00302 return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0; 00303 }
| static int routes_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 291 of file res_phoneprov.c.
References ast_str_case_hash(), and http_route::uri.
Referenced by load_module().
00292 { 00293 const struct http_route *route = obj; 00294 00295 return ast_str_case_hash(route->uri); 00296 }
| static int set_config | ( | void | ) | [static] |
Definition at line 922 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(), ast_var_t::entries, 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.
00923 { 00924 struct ast_config *cfg, *phoneprov_cfg; 00925 char *cat; 00926 struct ast_variable *v; 00927 struct ast_flags config_flags = { 0 }; 00928 struct ast_var_t *var; 00929 00930 /* Try to grab the port from sip.conf. If we don't get it here, we'll set it 00931 * to whatever is set in phoneprov.conf or default to 5060 */ 00932 if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { 00933 ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport)); 00934 ast_config_destroy(cfg); 00935 } 00936 00937 if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 00938 ast_log(LOG_WARNING, "Unable to load users.conf\n"); 00939 return 0; 00940 } 00941 00942 /* Go ahead and load global variables from users.conf so we can append to profiles */ 00943 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { 00944 if (!strcasecmp(v->name, "vmexten")) { 00945 if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) { 00946 ast_mutex_lock(&globals_lock); 00947 AST_LIST_INSERT_TAIL(&global_variables, var, entries); 00948 ast_mutex_unlock(&globals_lock); 00949 } 00950 } 00951 if (!strcasecmp(v->name, "localextenlength")) { 00952 if ((var = ast_var_assign("EXTENSION_LENGTH", v->value))) 00953 ast_mutex_lock(&globals_lock); 00954 AST_LIST_INSERT_TAIL(&global_variables, var, entries); 00955 ast_mutex_unlock(&globals_lock); 00956 } 00957 } 00958 00959 if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) { 00960 ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n"); 00961 ast_config_destroy(cfg); 00962 return -1; 00963 } 00964 00965 cat = NULL; 00966 while ((cat = ast_category_browse(phoneprov_cfg, cat))) { 00967 if (!strcasecmp(cat, "general")) { 00968 for (v = ast_variable_browse(phoneprov_cfg, cat); v; v = v->next) { 00969 if (!strcasecmp(v->name, "serveraddr")) 00970 ast_copy_string(global_server, v->value, sizeof(global_server)); 00971 else if (!strcasecmp(v->name, "serveriface")) { 00972 struct in_addr addr; 00973 lookup_iface(v->value, &addr); 00974 ast_copy_string(global_server, ast_inet_ntoa(addr), sizeof(global_server)); 00975 } else if (!strcasecmp(v->name, "serverport")) 00976 ast_copy_string(global_serverport, v->value, sizeof(global_serverport)); 00977 else if (!strcasecmp(v->name, "default_profile")) 00978 ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile)); 00979 } 00980 } else 00981 build_profile(cat, ast_variable_browse(phoneprov_cfg, cat)); 00982 } 00983 00984 ast_config_destroy(phoneprov_cfg); 00985 00986 cat = NULL; 00987 while ((cat = ast_category_browse(cfg, cat))) { 00988 const char *tmp, *mac; 00989 struct user *user; 00990 struct phone_profile *profile; 00991 struct extension *exten; 00992 00993 if (!strcasecmp(cat, "general")) { 00994 continue; 00995 } 00996 00997 if (!strcasecmp(cat, "authentication")) 00998 continue; 00999 01000 if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp))) 01001 continue; 01002 01003 if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) { 01004 ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat); 01005 continue; 01006 } 01007 01008 tmp = S_OR(ast_variable_retrieve(cfg, cat, "profile"), global_default_profile); 01009 if (ast_strlen_zero(tmp)) { 01010 ast_log(LOG_WARNING, "No profile for user [%s] with mac '%s' - skipping\n", cat, mac); 01011 continue; 01012 } 01013 01014 if (!(user = find_user(mac))) { 01015 if (!(profile = find_profile(tmp))) { 01016 ast_log(LOG_WARNING, "Could not look up profile '%s' - skipping.\n", tmp); 01017 continue; 01018 } 01019 01020 if (!(user = build_user(mac, profile))) { 01021 ast_log(LOG_WARNING, "Could not create user for '%s' - skipping\n", user->macaddress); 01022 continue; 01023 } 01024 01025 if (!(exten = build_extension(cfg, cat))) { 01026 ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress); 01027 user = unref_user(user); 01028 continue; 01029 } 01030 01031 if (add_user_extension(user, exten)) { 01032 ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress); 01033 user = unref_user(user); 01034 exten = delete_extension(exten); 01035 continue; 01036 } 01037 01038 if (build_user_routes(user)) { 01039 ast_log(LOG_WARNING, "Could not create http routes for %s - skipping\n", user->macaddress); 01040 user = unref_user(user); 01041 continue; 01042 } 01043 01044 ao2_link(users, user); 01045 user = unref_user(user); 01046 } else { 01047 if (!(exten = build_extension(cfg, cat))) { 01048 ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress); 01049 user = unref_user(user); 01050 continue; 01051 } 01052 01053 if (add_user_extension(user, exten)) { 01054 ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress); 01055 user = unref_user(user); 01056 exten = delete_extension(exten); 01057 continue; 01058 } 01059 01060 user = unref_user(user); 01061 } 01062 } 01063 01064 ast_config_destroy(cfg); 01065 01066 return 0; 01067 }
| 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 346 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().
00347 { 00348 time_t utc_time; 00349 int dstenable; 00350 time_t dststart; 00351 time_t dstend; 00352 struct ast_tm tm_info; 00353 int tzoffset; 00354 char buffer[21]; 00355 struct ast_var_t *var; 00356 struct timeval when; 00357 00358 time(&utc_time); 00359 ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone); 00360 snprintf(buffer, sizeof(buffer), "%d", tzoffset); 00361 var = ast_var_assign("TZOFFSET", buffer); 00362 if (var) 00363 AST_LIST_INSERT_TAIL(headp, var, entries); 00364 00365 if (!dstenable) 00366 return; 00367 00368 if ((var = ast_var_assign("DST_ENABLE", "1"))) 00369 AST_LIST_INSERT_TAIL(headp, var, entries); 00370 00371 when.tv_sec = dststart; 00372 ast_localtime(&when, &tm_info, zone); 00373 00374 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1); 00375 if ((var = ast_var_assign("DST_START_MONTH", buffer))) 00376 AST_LIST_INSERT_TAIL(headp, var, entries); 00377 00378 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday); 00379 if ((var = ast_var_assign("DST_START_MDAY", buffer))) 00380 AST_LIST_INSERT_TAIL(headp, var, entries); 00381 00382 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour); 00383 if ((var = ast_var_assign("DST_START_HOUR", buffer))) 00384 AST_LIST_INSERT_TAIL(headp, var, entries); 00385 00386 when.tv_sec = dstend; 00387 ast_localtime(&when, &tm_info, zone); 00388 00389 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1); 00390 if ((var = ast_var_assign("DST_END_MONTH", buffer))) 00391 AST_LIST_INSERT_TAIL(headp, var, entries); 00392 00393 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday); 00394 if ((var = ast_var_assign("DST_END_MDAY", buffer))) 00395 AST_LIST_INSERT_TAIL(headp, var, entries); 00396 00397 snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour); 00398 if ((var = ast_var_assign("DST_END_HOUR", buffer))) 00399 AST_LIST_INSERT_TAIL(headp, var, entries); 00400 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1310 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(), ast_var_t::entries, global_variables, and var.
01311 { 01312 struct ast_var_t *var; 01313 01314 ast_http_uri_unlink(&phoneprovuri); 01315 ast_custom_function_unregister(&pp_each_user_function); 01316 ast_custom_function_unregister(&pp_each_extension_function); 01317 ast_cli_unregister_multiple(pp_cli, ARRAY_LEN(pp_cli)); 01318 01319 delete_routes(); 01320 delete_users(); 01321 delete_profiles(); 01322 ao2_ref(profiles, -1); 01323 ao2_ref(http_routes, -1); 01324 ao2_ref(users, -1); 01325 01326 ast_mutex_lock(&globals_lock); 01327 while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) { 01328 ast_var_delete(var); 01329 } 01330 ast_mutex_unlock(&globals_lock); 01331 01332 ast_mutex_destroy(&globals_lock); 01333 01334 return 0; 01335 }
| static struct phone_profile* unref_profile | ( | struct phone_profile * | prof | ) | [static, read] |
Definition at line 228 of file res_phoneprov.c.
References ao2_ref.
Referenced by build_profile(), build_user(), delete_profiles(), and user_destructor().
00229 { 00230 ao2_ref(prof, -1); 00231 00232 return NULL; 00233 }
| static struct http_route* unref_route | ( | struct http_route * | route | ) | [static, read] |
Definition at line 284 of file res_phoneprov.c.
References ao2_ref.
Referenced by build_route(), delete_routes(), handle_show_routes(), and phoneprov_callback().
00285 { 00286 ao2_ref(route, -1); 00287 00288 return NULL; 00289 }
Definition at line 774 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().
00775 { 00776 ao2_ref(user, -1); 00777 00778 return NULL; 00779 }
| static void user_destructor | ( | void * | obj | ) | [static] |
Free all memory associated with a user.
Definition at line 806 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().
00807 { 00808 struct user *user = obj; 00809 struct extension *exten; 00810 00811 while ((exten = AST_LIST_REMOVE_HEAD(&user->extensions, entry))) { 00812 exten = delete_extension(exten); 00813 } 00814 00815 if (user->profile) { 00816 user->profile = unref_profile(user->profile); 00817 } 00818 00819 ast_string_field_free_memory(user); 00820 }
| static int users_cmp_fn | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 798 of file res_phoneprov.c.
References CMP_MATCH, CMP_STOP, and user::macaddress.
Referenced by load_module().
00799 { 00800 const struct user *user1 = obj, *user2 = arg; 00801 00802 return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0; 00803 }
| static int users_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 791 of file res_phoneprov.c.
References ast_str_case_hash(), and user::macaddress.
Referenced by load_module().
00792 { 00793 const struct user *user = obj; 00794 00795 return ast_str_case_hash(user->macaddress); 00796 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1360 of file res_phoneprov.c.
struct in_addr __ourip = { .s_addr = 0x00000000, } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1360 of file res_phoneprov.c.
char global_default_profile[80] = "" [static] |
Default profile to use if one isn't specified
Definition at line 191 of file res_phoneprov.c.
char global_server[80] = "" [static] |
Server to substitute into templates
Definition at line 189 of file res_phoneprov.c.
char global_serverport[6] = "" [static] |
Server port to substitute into templates
Definition at line 190 of file res_phoneprov.c.
struct varshead global_variables [static] |
List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH.
Definition at line 194 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 195 of file res_phoneprov.c.
struct ao2_container* http_routes [static] |
Definition at line 186 of file res_phoneprov.c.
struct ast_http_uri phoneprovuri [static] |
Definition at line 1280 of file res_phoneprov.c.
struct ast_cli_entry pp_cli[] [static] |
Initial value:
{
AST_CLI_DEFINE(handle_show_routes, "Show registered phoneprov http routes"),
}
Definition at line 1276 of file res_phoneprov.c.
struct ast_custom_function pp_each_extension_function [static] |
Initial value:
{
.name = "PP_EACH_EXTENSION",
.read = pp_each_extension_read,
.read2 = pp_each_extension_read2,
}
Definition at line 1226 of file res_phoneprov.c.
struct ast_custom_function pp_each_user_function [static] |
Initial value:
{
.name = "PP_EACH_USER",
.read = pp_each_user_read,
.read2 = pp_each_user_read2,
}
Definition at line 1148 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 185 of file res_phoneprov.c.
struct ao2_container* users [static] |
Definition at line 187 of file res_phoneprov.c.
1.5.6