Fri Nov 12 12:08:40 2010

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 * ftype2mtype (const char *ftype)
 Return mime type based on extension.
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 struct ast_strphoneprov_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
 Callback that is executed everytime an http request is received by this module.
static int pp_each_extension_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 A dialplan function that can be used to output a template for each extension attached to a user.
static int pp_each_user_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 A dialplan function that can be used to print a string for each phoneprov user.
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_GLOBAL_SYMBOLS , .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 = "0901e4e500243c855563a2d78b0c03e4" , .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
struct {
   char *   ext
   char *   mtype
mimetypes []
 Extensions whose mime types we think we know.
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 73 of file res_phoneprov.c.

00073                   {
00074    PP_MACADDRESS,
00075    PP_USERNAME,
00076    PP_FULLNAME,
00077    PP_SECRET,
00078    PP_LABEL,
00079    PP_CALLERID,
00080    PP_TIMEZONE,
00081    PP_LINENUMBER,
00082    PP_LINEKEYS,
00083    PP_VAR_LIST_LENGTH,  /* This entry must always be the last in the list */
00084 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1321 of file res_phoneprov.c.

static void __unreg_module ( void   )  [static]

Definition at line 1321 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 860 of file res_phoneprov.c.

References 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_var_assign(), ast_var_t::entries, user::extensions, extension::headp, phone_profile::headp, extension::index, LOG_WARNING, user::macaddress, ast_var_t::name, pbx_substitute_variables_varshead(), user::profile, ast_var_t::value, var, and VAR_BUF_SIZE.

Referenced by set_config().

00861 {
00862    struct ast_var_t *var;
00863 
00864    /* Append profile variables here, and substitute variables on profile
00865     * setvars, so that we can use user specific variables in them */
00866    AST_LIST_TRAVERSE(user->profile->headp, var, entries) {
00867       char expand_buf[VAR_BUF_SIZE] = {0,};
00868       struct ast_var_t *var2;
00869 
00870       pbx_substitute_variables_varshead(exten->headp, var->value, expand_buf, sizeof(expand_buf));
00871       if ((var2 = ast_var_assign(var->name, expand_buf)))
00872          AST_LIST_INSERT_TAIL(exten->headp, var2, entries);
00873    }
00874 
00875    if (AST_LIST_EMPTY(&user->extensions)) {
00876       AST_LIST_INSERT_HEAD(&user->extensions, exten, entry);
00877    } else {
00878       struct extension *exten_iter;
00879 
00880       AST_LIST_TRAVERSE_SAFE_BEGIN(&user->extensions, exten_iter, entry) {
00881          if (exten->index < exten_iter->index) {
00882             AST_LIST_INSERT_BEFORE_CURRENT(exten, entry);
00883          } else if (exten->index == exten_iter->index) {
00884             ast_log(LOG_WARNING, "Duplicate linenumber=%d for %s\n", exten->index, user->macaddress);
00885             return -1;
00886          } else if (!AST_LIST_NEXT(exten_iter, entry)) {
00887             AST_LIST_INSERT_TAIL(&user->extensions, exten, entry);
00888          }
00889       }
00890       AST_LIST_TRAVERSE_SAFE_END;
00891    }
00892 
00893    return 0;
00894 }

static struct extension* build_extension ( struct ast_config cfg,
const char *  name 
) [static, read]

Definition at line 709 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().

00710 {
00711    struct extension *exten;
00712    struct ast_var_t *var;
00713    const char *tmp;
00714    int i;
00715 
00716    if (!(exten = ast_calloc(1, sizeof(*exten)))) {
00717       return NULL;
00718    }
00719 
00720    if (ast_string_field_init(exten, 32)) {
00721       ast_free(exten);
00722       exten = NULL;
00723       return NULL;
00724    }
00725 
00726    ast_string_field_set(exten, name, name);
00727 
00728    if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) {
00729       ast_free(exten);
00730       exten = NULL;
00731       return NULL;
00732    }
00733 
00734    for (i = 0; i < PP_VAR_LIST_LENGTH; i++) {
00735       tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var);
00736 
00737       /* If we didn't get a USERNAME variable, set it to the user->name */
00738       if (i == PP_USERNAME && !tmp) {
00739          if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) {
00740             AST_LIST_INSERT_TAIL(exten->headp, var, entries);
00741          }
00742          continue;
00743       } else if (i == PP_TIMEZONE) {
00744          /* perfectly ok if tmp is NULL, will set variables based on server's time zone */
00745          set_timezone_variables(exten->headp, tmp);
00746       } else if (i == PP_LINENUMBER) {
00747          if (!tmp) {
00748             tmp = "1";
00749          }
00750          exten->index = atoi(tmp);
00751       } else if (i == PP_LINEKEYS) {
00752          if (!tmp) {
00753             tmp = "1";
00754          }
00755       }
00756 
00757       if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) {
00758          AST_LIST_INSERT_TAIL(exten->headp, var, entries);
00759       }
00760    }
00761 
00762    if (!ast_strlen_zero(global_server)) {
00763       if ((var = ast_var_assign("SERVER", global_server)))
00764          AST_LIST_INSERT_TAIL(exten->headp, var, entries);
00765    }
00766 
00767    if (!ast_strlen_zero(global_serverport)) {
00768       if ((var = ast_var_assign("SERVER_PORT", global_serverport)))
00769          AST_LIST_INSERT_TAIL(exten->headp, var, entries);
00770    }
00771 
00772    return exten;
00773 }

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 583 of file res_phoneprov.c.

References ao2_alloc, ao2_link, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, ast_free, 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_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, ftype2mtype(), 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().

00584 {
00585    struct phone_profile *profile;
00586    struct ast_var_t *var;
00587 
00588    if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) {
00589       return;
00590    }
00591 
00592    if (ast_string_field_init(profile, 32)) {
00593       profile = unref_profile(profile);
00594       return;
00595    }
00596 
00597    if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) {
00598       profile = unref_profile(profile);
00599       return;
00600    }
00601 
00602    AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files);
00603    AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files);
00604 
00605    ast_string_field_set(profile, name, name);
00606    for (; v; v = v->next) {
00607       if (!strcasecmp(v->name, "mime_type")) {
00608          ast_string_field_set(profile, default_mime_type, v->value);
00609       } else if (!strcasecmp(v->name, "setvar")) {
00610          struct ast_var_t *variable;
00611          char *value_copy = ast_strdupa(v->value);
00612 
00613          AST_DECLARE_APP_ARGS(args,
00614             AST_APP_ARG(varname);
00615             AST_APP_ARG(varval);
00616          );
00617 
00618          AST_NONSTANDARD_APP_ARGS(args, value_copy, '=');
00619          do {
00620             if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
00621                break;
00622             args.varname = ast_strip(args.varname);
00623             args.varval = ast_strip(args.varval);
00624             if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
00625                break;
00626             if ((variable = ast_var_assign(args.varname, args.varval)))
00627                AST_LIST_INSERT_TAIL(profile->headp, variable, entries);
00628          } while (0);
00629       } else if (!strcasecmp(v->name, "staticdir")) {
00630          ast_string_field_set(profile, staticdir, v->value);
00631       } else {
00632          struct phoneprov_file *pp_file;
00633          char *file_extension;
00634          char *value_copy = ast_strdupa(v->value);
00635 
00636          AST_DECLARE_APP_ARGS(args,
00637             AST_APP_ARG(filename);
00638             AST_APP_ARG(mimetype);
00639          );
00640 
00641          if (!(pp_file = ast_calloc(1, sizeof(*pp_file)))) {
00642             profile = unref_profile(profile);
00643             return;
00644          }
00645          if (ast_string_field_init(pp_file, 32)) {
00646             ast_free(pp_file);
00647             profile = unref_profile(profile);
00648             return;
00649          }
00650 
00651          if ((file_extension = strrchr(pp_file->format, '.')))
00652             file_extension++;
00653 
00654          AST_STANDARD_APP_ARGS(args, value_copy);
00655 
00656          /* Mime type order of preference
00657           * 1) Specific mime-type defined for file in profile
00658           * 2) Mime determined by extension
00659           * 3) Default mime type specified in profile
00660           * 4) text/plain
00661           */
00662          ast_string_field_set(pp_file, mime_type, S_OR(args.mimetype, (S_OR(S_OR(ftype2mtype(file_extension), profile->default_mime_type), "text/plain"))));
00663 
00664          if (!strcasecmp(v->name, "static_file")) {
00665             ast_string_field_set(pp_file, format, args.filename);
00666             ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename);
00667             AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry);
00668             /* Add a route for the static files, as their filenames won't change per-user */
00669             build_route(pp_file, NULL, NULL);
00670          } else {
00671             ast_string_field_set(pp_file, format, v->name);
00672             ast_string_field_set(pp_file, template, args.filename);
00673             AST_LIST_INSERT_TAIL(&profile->dynamic_files, pp_file, entry);
00674          }
00675       }
00676    }
00677 
00678    /* Append the global variables to the variables list for this profile.
00679     * This is for convenience later, when we need to provide a single
00680     * variable list for use in substitution. */
00681    ast_mutex_lock(&globals_lock);
00682    AST_LIST_TRAVERSE(&global_variables, var, entries) {
00683       struct ast_var_t *new_var;
00684       if ((new_var = ast_var_assign(var->name, var->value))) {
00685          AST_LIST_INSERT_TAIL(profile->headp, new_var, entries);
00686       }
00687    }
00688    ast_mutex_unlock(&globals_lock);
00689 
00690    ao2_link(profiles, profile);
00691 
00692    profile = unref_profile(profile);
00693 }

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 556 of file res_phoneprov.c.

References ao2_alloc, ao2_link, ast_log(), ast_string_field_init, ast_string_field_set, http_route::file, phoneprov_file::format, LOG_ERROR, route_destructor(), S_OR, unref_route(), and http_route::user.

Referenced by build_profile(), and build_user_routes().

00557 {
00558    struct http_route *route;
00559 
00560    if (!(route = ao2_alloc(sizeof(*route), route_destructor))) {
00561       return;
00562    }
00563 
00564    if (ast_string_field_init(route, 32)) {
00565       ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", pp_file->format);
00566       route = unref_route(route);
00567       return;
00568    }
00569 
00570    ast_string_field_set(route, uri, S_OR(uri, pp_file->format));
00571    route->user = user;
00572    route->file = pp_file;
00573 
00574    ao2_link(http_routes, route);
00575 
00576    route = unref_route(route);
00577 }

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 838 of file res_phoneprov.c.

References ao2_alloc, ast_string_field_init, ast_string_field_set, user::macaddress, user::profile, unref_profile(), unref_user(), and user_destructor().

Referenced by set_config().

00839 {
00840    struct user *user;
00841 
00842    if (!(user = ao2_alloc(sizeof(*user), user_destructor))) {
00843       profile = unref_profile(profile);
00844       return NULL;
00845    }
00846 
00847    if (ast_string_field_init(user, 32)) {
00848       profile = unref_profile(profile);
00849       user = unref_user(user);
00850       return NULL;
00851    }
00852 
00853    ast_string_field_set(user, macaddress, mac);
00854    user->profile = profile; /* already ref counted by find_profile */
00855 
00856    return user;
00857 }

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 897 of file res_phoneprov.c.

References AST_LIST_FIRST, AST_LIST_TRAVERSE, build_route(), phone_profile::dynamic_files, user::extensions, phoneprov_file::format, pbx_substitute_variables_varshead(), user::profile, and VAR_BUF_SIZE.

Referenced by set_config().

00898 {
00899    struct phoneprov_file *pp_file;
00900 
00901    AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) {
00902       char expand_buf[VAR_BUF_SIZE] = { 0, };
00903 
00904       pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, pp_file->format, expand_buf, sizeof(expand_buf));
00905       build_route(pp_file, user, expand_buf);
00906    }
00907 
00908    return 0;
00909 }

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

Definition at line 695 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().

00696 {
00697    struct ast_var_t *var;
00698    while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) {
00699       ast_var_delete(var);
00700    }
00701    ast_free(exten->headp);
00702    ast_string_field_free_memory(exten);
00703 
00704    ast_free(exten);
00705 
00706    return NULL;
00707 }

static void delete_file ( struct phoneprov_file file  )  [static]

Definition at line 257 of file res_phoneprov.c.

References ast_string_field_free_memory, and free.

Referenced by profile_destructor().

00258 {
00259    ast_string_field_free_memory(file);
00260    free(file);
00261 }

static void delete_profiles ( void   )  [static]

Delete all phone profiles, freeing their memory.

Definition at line 1074 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().

01075 {
01076    struct ao2_iterator i;
01077    struct phone_profile *profile;
01078 
01079    i = ao2_iterator_init(profiles, 0);
01080    while ((profile = ao2_iterator_next(&i))) {
01081       ao2_unlink(profiles, profile);
01082       profile = unref_profile(profile);
01083    }
01084    ao2_iterator_destroy(&i);
01085 }

static void delete_routes ( void   )  [static]

Delete all http routes, freeing their memory.

Definition at line 1060 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().

01061 {
01062    struct ao2_iterator i;
01063    struct http_route *route;
01064 
01065    i = ao2_iterator_init(http_routes, 0);
01066    while ((route = ao2_iterator_next(&i))) {
01067       ao2_unlink(http_routes, route);
01068       route = unref_route(route);
01069    }
01070    ao2_iterator_destroy(&i);
01071 }

static void delete_users ( void   )  [static]

Delete all users.

Definition at line 824 of file res_phoneprov.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_unlink, and unref_user().

Referenced by reload(), and unload_module().

00825 {
00826    struct ao2_iterator i;
00827    struct user *user;
00828 
00829    i = ao2_iterator_init(users, 0);
00830    while ((user = ao2_iterator_next(&i))) {
00831       ao2_unlink(users, user);
00832       user = unref_user(user);
00833    }
00834    ao2_iterator_destroy(&i);
00835 }

static struct phone_profile* find_profile ( const char *  name  )  [static, read]

Return a phone profile looked up by name.

Definition at line 234 of file res_phoneprov.c.

References ao2_find, phone_profile::name, and OBJ_POINTER.

Referenced by set_config().

00235 {
00236    struct phone_profile tmp = {
00237       .name = name,
00238    };
00239 
00240    return ao2_find(profiles, &tmp, OBJ_POINTER);
00241 }

static struct user* find_user ( const char *  macaddress  )  [static, read]

Return a user looked up by name.

Definition at line 783 of file res_phoneprov.c.

References ao2_find, user::macaddress, and OBJ_POINTER.

Referenced by pp_each_extension_exec(), and set_config().

00784 {
00785    struct user tmp = {
00786       .macaddress = macaddress,
00787    };
00788 
00789    return ao2_find(users, &tmp, OBJ_POINTER);
00790 }

static char* ftype2mtype ( const char *  ftype  )  [static]

Return mime type based on extension.

Definition at line 180 of file res_phoneprov.c.

References ARRAY_LEN, ast_strlen_zero(), ext, mimetypes, and mtype.

Referenced by build_profile().

00181 {
00182    int x;
00183 
00184    if (ast_strlen_zero(ftype))
00185       return NULL;
00186 
00187    for (x = 0;x < ARRAY_LEN(mimetypes);x++) {
00188       if (!strcasecmp(ftype, mimetypes[x].ext))
00189          return mimetypes[x].mtype;
00190    }
00191 
00192    return NULL;
00193 }

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

01194 {
01195 #define FORMAT "%-40.40s  %-30.30s\n"
01196    struct ao2_iterator i;
01197    struct http_route *route;
01198 
01199    switch(cmd) {
01200    case CLI_INIT:
01201       e->command = "phoneprov show routes";
01202       e->usage =
01203          "Usage: phoneprov show routes\n"
01204          "       Lists all registered phoneprov http routes.\n";
01205       return NULL;
01206    case CLI_GENERATE:
01207       return NULL;
01208    }
01209 
01210    /* This currently iterates over routes twice, but it is the only place I've needed
01211     * to really separate static an dynamic routes, so I've just left it this way. */
01212    ast_cli(a->fd, "Static routes\n\n");
01213    ast_cli(a->fd, FORMAT, "Relative URI", "Physical location");
01214    i = ao2_iterator_init(http_routes, 0);
01215    while ((route = ao2_iterator_next(&i))) {
01216       if (!route->user)
01217          ast_cli(a->fd, FORMAT, route->uri, route->file->template);
01218       route = unref_route(route);
01219    }
01220    ao2_iterator_destroy(&i);
01221 
01222    ast_cli(a->fd, "\nDynamic routes\n\n");
01223    ast_cli(a->fd, FORMAT, "Relative URI", "Template");
01224 
01225    i = ao2_iterator_init(http_routes, 0);
01226    while ((route = ao2_iterator_next(&i))) {
01227       if (route->user)
01228          ast_cli(a->fd, FORMAT, route->uri, route->file->template);
01229       route = unref_route(route);
01230    }
01231    ao2_iterator_destroy(&i);
01232 
01233    return CLI_SUCCESS;
01234 }

static int load_file ( const char *  filename,
char **  ret 
) [static]

Read a TEXT file into a string and return the length.

Definition at line 311 of file res_phoneprov.c.

References ast_malloc, f, free, and len().

Referenced by phoneprov_callback(), and pp_each_extension_exec().

00312 {
00313    int len = 0;
00314    FILE *f;
00315 
00316    if (!(f = fopen(filename, "r"))) {
00317       *ret = NULL;
00318       return -1;
00319    }
00320 
00321    fseek(f, 0, SEEK_END);
00322    len = ftell(f);
00323    fseek(f, 0, SEEK_SET);
00324    if (!(*ret = ast_malloc(len + 1)))
00325       return -2;
00326 
00327    if (len != fread(*ret, sizeof(char), len, f)) {
00328       free(*ret);
00329       *ret = NULL;
00330       return -3;
00331    }
00332 
00333    fclose(f);
00334 
00335    (*ret)[len] = '\0';
00336 
00337    return len;
00338 }

static int load_module ( void   )  [static]
static int lookup_iface ( const char *  iface,
struct in_addr *  address 
) [static]

Definition at line 196 of file res_phoneprov.c.

References ast_copy_string(), ast_log(), errno, LOG_ERROR, and LOG_WARNING.

Referenced by set_config().

00197 {
00198    int mysock, res = 0;
00199    struct ifreq ifr;
00200    struct sockaddr_in *sin;
00201 
00202    memset(&ifr, 0, sizeof(ifr));
00203    ast_copy_string(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
00204 
00205    mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
00206    if (mysock < 0) {
00207       ast_log(LOG_ERROR, "Failed to create socket: %s\n", strerror(errno));
00208       return -1;
00209    }
00210 
00211    res = ioctl(mysock, SIOCGIFADDR, &ifr);
00212 
00213    close(mysock);
00214 
00215    if (res < 0) {
00216       ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
00217       memcpy(address, &__ourip, sizeof(__ourip));
00218       return -1;
00219    } else {
00220       sin = (struct sockaddr_in *)&ifr.ifr_addr;
00221       memcpy(address, &sin->sin_addr, sizeof(*address));
00222       return 0;
00223    }
00224 }

static struct ast_str* 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 vars,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Callback that is executed everytime an http request is received by this module.

Definition at line 401 of file res_phoneprov.c.

References ao2_find, ast_calloc, ast_config_AST_DATA_DIR, ast_debug, ast_free, ast_get_version(), ast_http_error(), ast_inet_ntoa(), AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_localtime(), ast_log(), ast_str_append(), ast_str_create(), ast_strftime(), ast_strlen_zero(), ast_tvnow(), ast_var_assign(), buf, errno, user::extensions, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, http_route::file, fwrite, extension::headp, len(), load_file(), LOG_WARNING, phoneprov_file::mime_type, name, OBJ_POINTER, pbx_substitute_variables_varshead(), strdup, phoneprov_file::template, unref_route(), http_route::uri, http_route::user, var, and VAR_BUF_SIZE.

00402 {
00403    struct http_route *route;
00404    struct http_route search_route = {
00405       .uri = uri,
00406    };
00407    struct ast_str *result = ast_str_create(512);
00408    char path[PATH_MAX];
00409    char *file = NULL;
00410    int len;
00411    int fd;
00412    char buf[256];
00413    struct timeval now = ast_tvnow();
00414    struct ast_tm tm;
00415 
00416    if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
00417       goto out404;
00418    }
00419 
00420    snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template);
00421 
00422    if (!route->user) { /* Static file */
00423 
00424       fd = open(path, O_RDONLY);
00425       if (fd < 0) {
00426          goto out500;
00427       }
00428 
00429       len = lseek(fd, 0, SEEK_END);
00430       lseek(fd, 0, SEEK_SET);
00431       if (len < 0) {
00432          ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
00433          close(fd);
00434          goto out500;
00435       }
00436 
00437       ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT"));
00438       fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
00439          "Server: Asterisk/%s\r\n"
00440          "Date: %s\r\n"
00441          "Connection: close\r\n"
00442          "Cache-Control: no-cache, no-store\r\n"
00443          "Content-Length: %d\r\n"
00444          "Content-Type: %s\r\n\r\n",
00445          ast_get_version(), buf, len, 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       close(fd);
00459       route = unref_route(route);
00460       return NULL;
00461    } else { /* Dynamic file */
00462       int bufsize;
00463       char *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       /* XXX This is a hack -- maybe sum length of all variables in route->user->headp and add that? */
00480       bufsize = len + VAR_BUF_SIZE;
00481 
00482       /* malloc() instead of alloca() here, just in case the file is bigger than
00483        * we have enough stack space for. */
00484       if (!(tmp = ast_calloc(1, bufsize))) {
00485          if (file) {
00486             ast_free(file);
00487          }
00488 
00489          goto out500;
00490       }
00491 
00492       /* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to
00493        * the IP address we are listening on that the phone contacted for this config file */
00494       if (ast_strlen_zero(global_server)) {
00495          union {
00496             struct sockaddr sa;
00497             struct sockaddr_in sa_in;
00498          } name;
00499          socklen_t namelen = sizeof(name.sa);
00500          int res;
00501 
00502          if ((res = getsockname(ser->fd, &name.sa, &namelen))) {
00503             ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n");
00504          } else {
00505             struct ast_var_t *var;
00506             struct extension *exten_iter;
00507 
00508             if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) {
00509                AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) {
00510                   AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries);
00511                }
00512             }
00513          }
00514       }
00515 
00516       pbx_substitute_variables_varshead(AST_LIST_FIRST(&route->user->extensions)->headp, file, tmp, bufsize);
00517 
00518       if (file) {
00519          ast_free(file);
00520       }
00521 
00522       ast_str_append(&result, 0,
00523          "Content-Type: %s\r\n"
00524          "Content-length: %d\r\n"
00525          "\r\n"
00526          "%s", route->file->mime_type, (int) strlen(tmp), tmp);
00527 
00528       if (tmp) {
00529          ast_free(tmp);
00530       }
00531 
00532       route = unref_route(route);
00533 
00534       return result;
00535    }
00536 
00537 out404:
00538    *status = 404;
00539    *title = strdup("Not Found");
00540    *contentlength = 0;
00541    return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
00542 
00543 out500:
00544    route = unref_route(route);
00545    *status = 500;
00546    *title = strdup("Internal Server Error");
00547    *contentlength = 0;
00548    return ast_http_error(500, "Internal Error", NULL, "An internal error has occured.");
00549 }

static int pp_each_extension_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

A dialplan function that can be used to output a template for each extension attached to a user.

Definition at line 1131 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_strlen_zero(), exten, user::extensions, find_user(), extension::headp, load_file(), LOG_WARNING, pbx_substitute_variables_varshead(), unref_user(), and VAR_BUF_SIZE.

01132 {
01133    struct user *user;
01134    struct extension *exten;
01135    char path[PATH_MAX];
01136    char *file;
01137    int filelen;
01138    AST_DECLARE_APP_ARGS(args,
01139       AST_APP_ARG(mac);
01140       AST_APP_ARG(template);
01141    );
01142 
01143    AST_STANDARD_APP_ARGS(args, data);
01144 
01145    if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) {
01146       ast_log(LOG_WARNING, "PP_EACH_EXTENSION requries both a macaddress and template filename.\n");
01147       return 0;
01148    }
01149 
01150    if (!(user = find_user(args.mac))) {
01151       ast_log(LOG_WARNING, "Could not find user with mac = '%s'\n", args.mac);
01152       return 0;
01153    }
01154 
01155    snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, args.template);
01156    filelen = load_file(path, &file);
01157    if (filelen < 0) {
01158       ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, filelen);
01159       if (file) {
01160          ast_free(file);
01161       }
01162       return 0;
01163    }
01164 
01165    if (!file) {
01166       return 0;
01167    }
01168 
01169    AST_LIST_TRAVERSE(&user->extensions, exten, entry) {
01170       char expand_buf[VAR_BUF_SIZE] = {0,};
01171       pbx_substitute_variables_varshead(exten->headp, file, expand_buf, sizeof(expand_buf));
01172       ast_build_string(&buf, &len, "%s", expand_buf);
01173    }
01174 
01175    ast_free(file);
01176 
01177    user = unref_user(user);
01178 
01179    return 0;
01180 }

static int pp_each_user_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

A dialplan function that can be used to print a string for each phoneprov user.

Definition at line 1088 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_LIST_FIRST, AST_STANDARD_APP_ARGS, ast_strlen_zero(), user::extensions, user::macaddress, pbx_substitute_variables_varshead(), unref_user(), and VAR_BUF_SIZE.

01089 {
01090    char *tmp, expand_buf[VAR_BUF_SIZE] = {0,};
01091    struct ao2_iterator i;
01092    struct user *user;
01093    AST_DECLARE_APP_ARGS(args,
01094       AST_APP_ARG(string);
01095       AST_APP_ARG(exclude_mac);
01096    );
01097    AST_STANDARD_APP_ARGS(args, data);
01098 
01099    /* Fix data by turning %{ into ${ */
01100    while ((tmp = strstr(args.string, "%{")))
01101       *tmp = '$';
01102 
01103    i = ao2_iterator_init(users, 0);
01104    while ((user = ao2_iterator_next(&i))) {
01105       if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->macaddress, args.exclude_mac)) {
01106          continue;
01107       }
01108       pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, args.string, expand_buf, sizeof(expand_buf));
01109       ast_build_string(&buf, &len, "%s", expand_buf);
01110       user = unref_user(user);
01111    }
01112    ao2_iterator_destroy(&i);
01113 
01114    return 0;
01115 }

static int profile_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 250 of file res_phoneprov.c.

References CMP_MATCH, CMP_STOP, and phone_profile::name.

Referenced by load_module().

00251 {
00252    const struct phone_profile *profile1 = obj, *profile2 = arg;
00253 
00254    return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0;
00255 }

static void profile_destructor ( void *  obj  )  [static]

Definition at line 263 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().

00264 {
00265    struct phone_profile *profile = obj;
00266    struct phoneprov_file *file;
00267    struct ast_var_t *var;
00268 
00269    while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry)))
00270       delete_file(file);
00271 
00272    while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry)))
00273       delete_file(file);
00274 
00275    while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries)))
00276       ast_var_delete(var);
00277 
00278    ast_free(profile->headp);
00279    ast_string_field_free_memory(profile);
00280 }

static int profile_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 243 of file res_phoneprov.c.

References ast_str_case_hash(), and phone_profile::name.

Referenced by load_module().

00244 {
00245    const struct phone_profile *profile = obj;
00246 
00247    return ast_str_case_hash(profile->name);
00248 }

static int reload ( void   )  [static]

Definition at line 1298 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.

01299 {
01300    struct ast_var_t *var;
01301 
01302    delete_routes();
01303    delete_users();
01304    delete_profiles();
01305 
01306    ast_mutex_lock(&globals_lock);
01307    while ((var = AST_LIST_REMOVE_HEAD(&global_variables, entries))) {
01308       ast_var_delete(var);
01309    }
01310    ast_mutex_unlock(&globals_lock);
01311 
01312    set_config();
01313 
01314    return 0;
01315 }

static void route_destructor ( void *  obj  )  [static]

Definition at line 303 of file res_phoneprov.c.

References ast_string_field_free_memory.

Referenced by build_route().

00304 {
00305    struct http_route *route = obj;
00306 
00307    ast_string_field_free_memory(route);
00308 }

static int routes_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 296 of file res_phoneprov.c.

References CMP_MATCH, CMP_STOP, and http_route::uri.

Referenced by load_module().

00297 {
00298    const struct http_route *route1 = obj, *route2 = arg;
00299 
00300    return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
00301 }

static int routes_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 289 of file res_phoneprov.c.

References ast_str_case_hash(), and http_route::uri.

Referenced by load_module().

00290 {
00291    const struct http_route *route = obj;
00292 
00293    return ast_str_case_hash(route->uri);
00294 }

static int set_config ( void   )  [static]

Definition at line 912 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.

Referenced by load_module(), and reload().

00913 {
00914    struct ast_config *cfg, *phoneprov_cfg;
00915    char *cat;
00916    struct ast_variable *v;
00917    struct ast_flags config_flags = { 0 };
00918    struct ast_var_t *var;
00919 
00920    /* Try to grab the port from sip.conf.  If we don't get it here, we'll set it
00921     * to whatever is set in phoneprov.conf or default to 5060 */
00922    if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
00923       ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport));
00924       ast_config_destroy(cfg);
00925    }
00926 
00927    if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00928       ast_log(LOG_WARNING, "Unable to load users.conf\n");
00929       return 0;
00930    }
00931 
00932    /* Go ahead and load global variables from users.conf so we can append to profiles */
00933    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00934       if (!strcasecmp(v->name, "vmexten")) {
00935          if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) {
00936             ast_mutex_lock(&globals_lock);
00937             AST_LIST_INSERT_TAIL(&global_variables, var, entries);
00938             ast_mutex_unlock(&globals_lock);
00939          }
00940       }
00941       if (!strcasecmp(v->name, "localextenlength")) {
00942          if ((var = ast_var_assign("EXTENSION_LENGTH", v->value)))
00943             ast_mutex_lock(&globals_lock);
00944             AST_LIST_INSERT_TAIL(&global_variables, var, entries);
00945             ast_mutex_unlock(&globals_lock);
00946       }
00947    }
00948 
00949    if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
00950       ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
00951       ast_config_destroy(cfg);
00952       return -1;
00953    }
00954 
00955    cat = NULL;
00956    while ((cat = ast_category_browse(phoneprov_cfg, cat))) {
00957       if (!strcasecmp(cat, "general")) {
00958          for (v = ast_variable_browse(phoneprov_cfg, cat); v; v = v->next) {
00959             if (!strcasecmp(v->name, "serveraddr"))
00960                ast_copy_string(global_server, v->value, sizeof(global_server));
00961             else if (!strcasecmp(v->name, "serveriface")) {
00962                struct in_addr addr;
00963                lookup_iface(v->value, &addr);
00964                ast_copy_string(global_server, ast_inet_ntoa(addr), sizeof(global_server));
00965             } else if (!strcasecmp(v->name, "serverport"))
00966                ast_copy_string(global_serverport, v->value, sizeof(global_serverport));
00967             else if (!strcasecmp(v->name, "default_profile"))
00968                ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile));
00969          }
00970       } else
00971          build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
00972    }
00973 
00974    ast_config_destroy(phoneprov_cfg);
00975 
00976    cat = NULL;
00977    while ((cat = ast_category_browse(cfg, cat))) {
00978       const char *tmp, *mac;
00979       struct user *user;
00980       struct phone_profile *profile;
00981       struct extension *exten;
00982 
00983       if (!strcasecmp(cat, "general")) {
00984          continue;
00985       }
00986 
00987       if (!strcasecmp(cat, "authentication"))
00988          continue;
00989 
00990       if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp)))
00991          continue;
00992 
00993       if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) {
00994          ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat);
00995          continue;
00996       }
00997 
00998       tmp = S_OR(ast_variable_retrieve(cfg, cat, "profile"), global_default_profile);
00999       if (ast_strlen_zero(tmp)) {
01000          ast_log(LOG_WARNING, "No profile for user [%s] with mac '%s' - skipping\n", cat, mac);
01001          continue;
01002       }
01003 
01004       if (!(user = find_user(mac))) {
01005          if (!(profile = find_profile(tmp))) {
01006             ast_log(LOG_WARNING, "Could not look up profile '%s' - skipping.\n", tmp);
01007             continue;
01008          }
01009 
01010          if (!(user = build_user(mac, profile))) {
01011             ast_log(LOG_WARNING, "Could not create user for '%s' - skipping\n", user->macaddress);
01012             continue;
01013          }
01014 
01015          if (!(exten = build_extension(cfg, cat))) {
01016             ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
01017             user = unref_user(user);
01018             continue;
01019          }
01020 
01021          if (add_user_extension(user, exten)) {
01022             ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
01023             user = unref_user(user);
01024             exten = delete_extension(exten);
01025             continue;
01026          }
01027 
01028          if (build_user_routes(user)) {
01029             ast_log(LOG_WARNING, "Could not create http routes for %s - skipping\n", user->macaddress);
01030             user = unref_user(user);
01031             continue;
01032          }
01033 
01034          ao2_link(users, user);
01035          user = unref_user(user);
01036       } else {
01037          if (!(exten = build_extension(cfg, cat))) {
01038             ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
01039             user = unref_user(user);
01040             continue;
01041          }
01042 
01043          if (add_user_extension(user, exten)) {
01044             ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
01045             user = unref_user(user);
01046             exten = delete_extension(exten);
01047             continue;
01048          }
01049 
01050          user = unref_user(user);
01051       }
01052    }
01053 
01054    ast_config_destroy(cfg);
01055 
01056    return 0;
01057 }

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

00345 {
00346    time_t utc_time;
00347    int dstenable;
00348    time_t dststart;
00349    time_t dstend;
00350    struct ast_tm tm_info;
00351    int tzoffset;
00352    char buffer[21];
00353    struct ast_var_t *var;
00354    struct timeval when;
00355 
00356    time(&utc_time);
00357    ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone);
00358    snprintf(buffer, sizeof(buffer), "%d", tzoffset);
00359    var = ast_var_assign("TZOFFSET", buffer);
00360    if (var)
00361       AST_LIST_INSERT_TAIL(headp, var, entries);
00362 
00363    if (!dstenable)
00364       return;
00365 
00366    if ((var = ast_var_assign("DST_ENABLE", "1")))
00367       AST_LIST_INSERT_TAIL(headp, var, entries);
00368 
00369    when.tv_sec = dststart;
00370    ast_localtime(&when, &tm_info, zone);
00371 
00372    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1);
00373    if ((var = ast_var_assign("DST_START_MONTH", buffer)))
00374       AST_LIST_INSERT_TAIL(headp, var, entries);
00375 
00376    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
00377    if ((var = ast_var_assign("DST_START_MDAY", buffer)))
00378       AST_LIST_INSERT_TAIL(headp, var, entries);
00379 
00380    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
00381    if ((var = ast_var_assign("DST_START_HOUR", buffer)))
00382       AST_LIST_INSERT_TAIL(headp, var, entries);
00383 
00384    when.tv_sec = dstend;
00385    ast_localtime(&when, &tm_info, zone);
00386 
00387    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1);
00388    if ((var = ast_var_assign("DST_END_MONTH", buffer)))
00389       AST_LIST_INSERT_TAIL(headp, var, entries);
00390 
00391    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
00392    if ((var = ast_var_assign("DST_END_MDAY", buffer)))
00393       AST_LIST_INSERT_TAIL(headp, var, entries);
00394 
00395    snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
00396    if ((var = ast_var_assign("DST_END_HOUR", buffer)))
00397       AST_LIST_INSERT_TAIL(headp, var, entries);
00398 }

static int unload_module ( void   )  [static]
static struct phone_profile* unref_profile ( struct phone_profile prof  )  [static, read]

Definition at line 226 of file res_phoneprov.c.

References ao2_ref.

Referenced by build_profile(), build_user(), delete_profiles(), and user_destructor().

00227 {
00228    ao2_ref(prof, -1);
00229 
00230    return NULL;
00231 }

static struct http_route* unref_route ( struct http_route route  )  [static, read]

Definition at line 282 of file res_phoneprov.c.

References ao2_ref.

Referenced by build_route(), delete_routes(), handle_show_routes(), and phoneprov_callback().

00283 {
00284    ao2_ref(route, -1);
00285 
00286    return NULL;
00287 }

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

Definition at line 775 of file res_phoneprov.c.

References ao2_ref.

Referenced by build_user(), delete_users(), pp_each_extension_exec(), pp_each_user_exec(), and set_config().

00776 {
00777    ao2_ref(user, -1);
00778 
00779    return NULL;
00780 }

static void user_destructor ( void *  obj  )  [static]

Free all memory associated with a user.

Definition at line 807 of file res_phoneprov.c.

References AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, delete_extension(), exten, user::extensions, user::profile, and unref_profile().

Referenced by build_user().

00808 {
00809    struct user *user = obj;
00810    struct extension *exten;
00811 
00812    while ((exten = AST_LIST_REMOVE_HEAD(&user->extensions, entry))) {
00813       exten = delete_extension(exten);
00814    }
00815 
00816    if (user->profile) {
00817       user->profile = unref_profile(user->profile);
00818    }
00819 
00820    ast_string_field_free_memory(user);
00821 }

static int users_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 799 of file res_phoneprov.c.

References CMP_MATCH, CMP_STOP, and user::macaddress.

Referenced by load_module().

00800 {
00801    const struct user *user1 = obj, *user2 = arg;
00802 
00803    return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0;
00804 }

static int users_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 792 of file res_phoneprov.c.

References ast_str_case_hash(), and user::macaddress.

Referenced by load_module().

00793 {
00794    const struct user *user = obj;
00795 
00796    return ast_str_case_hash(user->macaddress);
00797 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1321 of file res_phoneprov.c.

struct in_addr __ourip = { .s_addr = 0x00000000, } [static]

for use in lookup_iface

Definition at line 69 of file res_phoneprov.c.

Definition at line 1321 of file res_phoneprov.c.

char* ext

Definition at line 160 of file res_phoneprov.c.

char global_default_profile[80] = "" [static]

Default profile to use if one isn't specified

Definition at line 173 of file res_phoneprov.c.

char global_server[80] = "" [static]

Server to substitute into templates

Definition at line 171 of file res_phoneprov.c.

char global_serverport[6] = "" [static]

Server port to substitute into templates

Definition at line 172 of file res_phoneprov.c.

struct varshead global_variables [static]

List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH.

Definition at line 176 of file res_phoneprov.c.

Referenced by build_profile(), load_module(), reload(), set_config(), and unload_module().

Definition at line 177 of file res_phoneprov.c.

struct ao2_container* http_routes [static]

Definition at line 155 of file res_phoneprov.c.

struct { ... } mimetypes[] [static]

Extensions whose mime types we think we know.

Referenced by ftype2mtype().

char* mtype

Definition at line 161 of file res_phoneprov.c.

struct ast_http_uri phoneprovuri [static]

Definition at line 1240 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 1236 of file res_phoneprov.c.

Definition at line 1182 of file res_phoneprov.c.

Definition at line 1117 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 154 of file res_phoneprov.c.

struct ao2_container* users [static]

Definition at line 156 of file res_phoneprov.c.


Generated by  doxygen 1.6.2