Wed Oct 28 13:33:31 2009

Asterisk developer's documentation


res_phoneprov.c File Reference

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"

Include dependency graph for res_phoneprov.c:

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 extensionbuild_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 userbuild_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 extensiondelete_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_profilefind_profile (const char *name)
 Return a phone profile looked up by name.
static struct userfind_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_profileunref_profile (struct phone_profile *prof)
static struct http_routeunref_route (struct http_route *route)
static struct userunref_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_infoast_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_containerhttp_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_containerprofiles
static struct ao2_containerusers


Detailed Description

Phone provisioning application for the asterisk internal http server.

Author:
Matthew Brooks <mbrooks@digium.com>

Terry Wilson <twilson@digium.com>

Definition in file res_phoneprov.c.


Define Documentation

#define FORMAT   "%-40.40s %-30.30s\n"

#define MAX_PROFILE_BUCKETS   17

Definition at line 61 of file res_phoneprov.c.

Referenced by load_module().

#define MAX_ROUTE_BUCKETS   563

Definition at line 62 of file res_phoneprov.c.

Referenced by load_module().

#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.


Enumeration Type Documentation

Enumerator:
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 };


Function Documentation

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.

static int add_user_extension ( struct user user,
struct extension exten 
) [static]

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.

Parameters:
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.

Parameters:
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 }

static struct extension* delete_extension ( struct extension exten  )  [static, read]

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]

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).

Parameters:
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]

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 }

static struct user* unref_user ( struct user user  )  [static, read]

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 }


Variable Documentation

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]

for use in lookup_iface

Definition at line 100 of file res_phoneprov.c.

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().

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.

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.

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.

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.


Generated on Wed Oct 28 13:33:32 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6