Thu Apr 28 2011 17:16:19

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
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "HTTP Phone Provisioning" , .key = ASTERISK_GPL_KEY , .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
struct {
   char *   ext
   char *   mtype
mimetypes []
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 []
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.

Referenced by load_module().

#define VAR_BUF_SIZE   4096

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.

                  {
   PP_MACADDRESS,
   PP_USERNAME,
   PP_FULLNAME,
   PP_SECRET,
   PP_LABEL,
   PP_CALLERID,
   PP_TIMEZONE,
   PP_LINENUMBER,
   PP_LINEKEYS,
   PP_VAR_LIST_LENGTH,  /* This entry must always be the last in the list */
};

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

{
   struct ast_var_t *var;

   /* Append profile variables here, and substitute variables on profile
    * setvars, so that we can use user specific variables in them */
   AST_LIST_TRAVERSE(user->profile->headp, var, entries) {
      char expand_buf[VAR_BUF_SIZE] = {0,};
      struct ast_var_t *var2;

      pbx_substitute_variables_varshead(exten->headp, var->value, expand_buf, sizeof(expand_buf));
      if ((var2 = ast_var_assign(var->name, expand_buf)))
         AST_LIST_INSERT_TAIL(exten->headp, var2, entries);
   }

   if (AST_LIST_EMPTY(&user->extensions)) {
      AST_LIST_INSERT_HEAD(&user->extensions, exten, entry);
   } else {
      struct extension *exten_iter;

      AST_LIST_TRAVERSE_SAFE_BEGIN(&user->extensions, exten_iter, entry) {
         if (exten->index < exten_iter->index) {
            AST_LIST_INSERT_BEFORE_CURRENT(exten, entry);
         } else if (exten->index == exten_iter->index) {
            ast_log(LOG_WARNING, "Duplicate linenumber=%d for %s\n", exten->index, user->macaddress);
            return -1;
         } else if (!AST_LIST_NEXT(exten_iter, entry)) {
            AST_LIST_INSERT_TAIL(&user->extensions, exten, entry);
         }
      }
      AST_LIST_TRAVERSE_SAFE_END;
   }

   return 0;
}
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().

{
   struct extension *exten;
   struct ast_var_t *var;
   const char *tmp;
   int i;

   if (!(exten = ast_calloc(1, sizeof(*exten)))) {
      return NULL;
   }

   if (ast_string_field_init(exten, 32)) {
      ast_free(exten);
      exten = NULL;
      return NULL;
   }

   ast_string_field_set(exten, name, name);

   if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) {
      ast_free(exten);
      exten = NULL;
      return NULL;
   }

   for (i = 0; i < PP_VAR_LIST_LENGTH; i++) {
      tmp = ast_variable_retrieve(cfg, name, pp_variable_list[i].user_var);

      /* If we didn't get a USERNAME variable, set it to the user->name */
      if (i == PP_USERNAME && !tmp) {
         if ((var = ast_var_assign(pp_variable_list[PP_USERNAME].template_var, exten->name))) {
            AST_LIST_INSERT_TAIL(exten->headp, var, entries);
         }
         continue;
      } else if (i == PP_TIMEZONE) {
         /* perfectly ok if tmp is NULL, will set variables based on server's time zone */
         set_timezone_variables(exten->headp, tmp);
      } else if (i == PP_LINENUMBER) {
         if (!tmp) {
            tmp = "1";
         }
         exten->index = atoi(tmp);
      } else if (i == PP_LINEKEYS) {
         if (!tmp) {
            tmp = "1";
         }
      }

      if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) {
         AST_LIST_INSERT_TAIL(exten->headp, var, entries);
      }
   }

   if (!ast_strlen_zero(global_server)) {
      if ((var = ast_var_assign("SERVER", global_server)))
         AST_LIST_INSERT_TAIL(exten->headp, var, entries);
   }

   if (!ast_strlen_zero(global_serverport)) {
      if ((var = ast_var_assign("SERVER_PORT", global_serverport)))
         AST_LIST_INSERT_TAIL(exten->headp, var, entries);
   }

   return exten;
}
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:
namethe name of the profile
vast_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_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, 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().

{
   struct phone_profile *profile;
   struct ast_var_t *var;

   if (!(profile = ao2_alloc(sizeof(*profile), profile_destructor))) {
      return;
   }

   if (ast_string_field_init(profile, 32)) {
      profile = unref_profile(profile);
      return;
   }

   if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) {
      profile = unref_profile(profile);
      return;
   }

   AST_LIST_HEAD_INIT_NOLOCK(&profile->static_files);
   AST_LIST_HEAD_INIT_NOLOCK(&profile->dynamic_files);

   ast_string_field_set(profile, name, name);
   for (; v; v = v->next) {
      if (!strcasecmp(v->name, "mime_type")) {
         ast_string_field_set(profile, default_mime_type, v->value);
      } else if (!strcasecmp(v->name, "setvar")) {
         struct ast_var_t *variable;
         char *value_copy = ast_strdupa(v->value);

         AST_DECLARE_APP_ARGS(args,
            AST_APP_ARG(varname);
            AST_APP_ARG(varval);
         );

         AST_NONSTANDARD_APP_ARGS(args, value_copy, '=');
         do {
            if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
               break;
            args.varname = ast_strip(args.varname);
            args.varval = ast_strip(args.varval);
            if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
               break;
            if ((variable = ast_var_assign(args.varname, args.varval)))
               AST_LIST_INSERT_TAIL(profile->headp, variable, entries);
         } while (0);
      } else if (!strcasecmp(v->name, "staticdir")) {
         ast_string_field_set(profile, staticdir, v->value);
      } else {
         struct phoneprov_file *pp_file;
         char *file_extension;
         char *value_copy = ast_strdupa(v->value);

         AST_DECLARE_APP_ARGS(args,
            AST_APP_ARG(filename);
            AST_APP_ARG(mimetype);
         );

         if (!(pp_file = ast_calloc(1, sizeof(*pp_file)))) {
            profile = unref_profile(profile);
            return;
         }
         if (ast_string_field_init(pp_file, 32)) {
            ast_free(pp_file);
            profile = unref_profile(profile);
            return;
         }

         if ((file_extension = strrchr(pp_file->format, '.')))
            file_extension++;

         AST_STANDARD_APP_ARGS(args, value_copy);

         /* Mime type order of preference
          * 1) Specific mime-type defined for file in profile
          * 2) Mime determined by extension
          * 3) Default mime type specified in profile
          * 4) text/plain
          */
         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"))));

         if (!strcasecmp(v->name, "static_file")) {
            ast_string_field_set(pp_file, format, args.filename);
            ast_string_field_build(pp_file, template, "%s%s", profile->staticdir, args.filename);
            AST_LIST_INSERT_TAIL(&profile->static_files, pp_file, entry);
            /* Add a route for the static files, as their filenames won't change per-user */
            build_route(pp_file, NULL, NULL);
         } else {
            ast_string_field_set(pp_file, format, v->name);
            ast_string_field_set(pp_file, template, args.filename);
            AST_LIST_INSERT_TAIL(&profile->dynamic_files, pp_file, entry);
         }
      }
   }

   /* Append the global variables to the variables list for this profile.
    * This is for convenience later, when we need to provide a single
    * variable list for use in substitution. */
   ast_mutex_lock(&globals_lock);
   AST_LIST_TRAVERSE(&global_variables, var, entries) {
      struct ast_var_t *new_var;
      if ((new_var = ast_var_assign(var->name, var->value))) {
         AST_LIST_INSERT_TAIL(profile->headp, new_var, entries);
      }
   }
   ast_mutex_unlock(&globals_lock);

   ao2_link(profiles, profile);

   profile = unref_profile(profile);
}
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_fileFile to link to the route
userUser to link to the route (NULL means static route)
uriURI 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(), user, and http_route::user.

Referenced by build_profile(), and build_user_routes().

{
   struct http_route *route;

   if (!(route = ao2_alloc(sizeof(*route), route_destructor))) {
      return;
   }

   if (ast_string_field_init(route, 32)) {
      ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", pp_file->format);
      route = unref_route(route);
      return;
   }

   ast_string_field_set(route, uri, S_OR(uri, pp_file->format));
   route->user = user;
   route->file = pp_file;

   ao2_link(http_routes, route);

   route = unref_route(route);
}
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(), user, and user_destructor().

Referenced by set_config().

{
   struct user *user;

   if (!(user = ao2_alloc(sizeof(*user), user_destructor))) {
      profile = unref_profile(profile);
      return NULL;
   }

   if (ast_string_field_init(user, 32)) {
      profile = unref_profile(profile);
      user = unref_user(user);
      return NULL;
   }

   ast_string_field_set(user, macaddress, mac);
   user->profile = profile; /* already ref counted by find_profile */

   return user;
}
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().

{
   struct phoneprov_file *pp_file;

   AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) {
      char expand_buf[VAR_BUF_SIZE] = { 0, };

      pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, pp_file->format, expand_buf, sizeof(expand_buf));
      build_route(pp_file, user, expand_buf);
   }

   return 0;
}
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().

{
   struct ast_var_t *var;
   while ((var = AST_LIST_REMOVE_HEAD(exten->headp, entries))) {
      ast_var_delete(var);
   }
   ast_free(exten->headp);
   ast_string_field_free_memory(exten);

   ast_free(exten);

   return NULL;
}
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().

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

{
   struct ao2_iterator i;
   struct phone_profile *profile;

   i = ao2_iterator_init(profiles, 0);
   while ((profile = ao2_iterator_next(&i))) {
      ao2_unlink(profiles, profile);
      profile = unref_profile(profile);
   }
   ao2_iterator_destroy(&i);
}
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().

{
   struct ao2_iterator i;
   struct http_route *route;

   i = ao2_iterator_init(http_routes, 0);
   while ((route = ao2_iterator_next(&i))) {
      ao2_unlink(http_routes, route);
      route = unref_route(route);
   }
   ao2_iterator_destroy(&i);
}
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, unref_user(), and user.

Referenced by reload(), and unload_module().

{
   struct ao2_iterator i;
   struct user *user;

   i = ao2_iterator_init(users, 0);
   while ((user = ao2_iterator_next(&i))) {
      ao2_unlink(users, user);
      user = unref_user(user);
   }
   ao2_iterator_destroy(&i);
}
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, name, phone_profile::name, and OBJ_POINTER.

Referenced by set_config().

{
   struct phone_profile tmp = {
      .name = name,
   };

   return ao2_find(profiles, &tmp, OBJ_POINTER);
}
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().

{
   struct user tmp = {
      .macaddress = macaddress,
   };

   return ao2_find(users, &tmp, OBJ_POINTER);
}
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().

{
   int x;

   if (ast_strlen_zero(ftype))
      return NULL;

   for (x = 0;x < ARRAY_LEN(mimetypes);x++) {
      if (!strcasecmp(ftype, mimetypes[x].ext))
         return mimetypes[x].mtype;
   }

   return NULL;
}
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.

{
#define FORMAT "%-40.40s  %-30.30s\n"
   struct ao2_iterator i;
   struct http_route *route;

   switch(cmd) {
   case CLI_INIT:
      e->command = "phoneprov show routes";
      e->usage =
         "Usage: phoneprov show routes\n"
         "       Lists all registered phoneprov http routes.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   /* This currently iterates over routes twice, but it is the only place I've needed
    * to really separate static an dynamic routes, so I've just left it this way. */
   ast_cli(a->fd, "Static routes\n\n");
   ast_cli(a->fd, FORMAT, "Relative URI", "Physical location");
   i = ao2_iterator_init(http_routes, 0);
   while ((route = ao2_iterator_next(&i))) {
      if (!route->user)
         ast_cli(a->fd, FORMAT, route->uri, route->file->template);
      route = unref_route(route);
   }
   ao2_iterator_destroy(&i);

   ast_cli(a->fd, "\nDynamic routes\n\n");
   ast_cli(a->fd, FORMAT, "Relative URI", "Template");

   i = ao2_iterator_init(http_routes, 0);
   while ((route = ao2_iterator_next(&i))) {
      if (route->user)
         ast_cli(a->fd, FORMAT, route->uri, route->file->template);
      route = unref_route(route);
   }
   ao2_iterator_destroy(&i);

   return CLI_SUCCESS;
}
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().

{
   int len = 0;
   FILE *f;

   if (!(f = fopen(filename, "r"))) {
      *ret = NULL;
      return -1;
   }

   fseek(f, 0, SEEK_END);
   len = ftell(f);
   fseek(f, 0, SEEK_SET);
   if (!(*ret = ast_malloc(len + 1)))
      return -2;

   if (len != fread(*ret, sizeof(char), len, f)) {
      free(*ret);
      *ret = NULL;
      return -3;
   }

   fclose(f);

   (*ret)[len] = '\0';

   return len;
}
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().

{
   int mysock, res = 0;
   struct ifreq ifr;
   struct sockaddr_in *sin;

   memset(&ifr, 0, sizeof(ifr));
   ast_copy_string(ifr.ifr_name, iface, sizeof(ifr.ifr_name));

   mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
   if (mysock < 0) {
      ast_log(LOG_ERROR, "Failed to create socket: %s\n", strerror(errno));
      return -1;
   }

   res = ioctl(mysock, SIOCGIFADDR, &ifr);

   close(mysock);

   if (res < 0) {
      ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
      memcpy(address, &__ourip, sizeof(__ourip));
      return -1;
   } else {
      sin = (struct sockaddr_in *)&ifr.ifr_addr;
      memcpy(address, &sin->sin_addr, sizeof(*address));
      return 0;
   }
}
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.

{
   struct http_route *route;
   struct http_route search_route = {
      .uri = uri,
   };
   struct ast_str *result = ast_str_create(512);
   char path[PATH_MAX];
   char *file = NULL;
   int len;
   int fd;
   char buf[256];
   struct timeval now = ast_tvnow();
   struct ast_tm tm;

   if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
      goto out404;
   }

   snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->file->template);

   if (!route->user) { /* Static file */

      fd = open(path, O_RDONLY);
      if (fd < 0) {
         goto out500;
      }

      len = lseek(fd, 0, SEEK_END);
      lseek(fd, 0, SEEK_SET);
      if (len < 0) {
         ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
         close(fd);
         goto out500;
      }

      ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT"));
      fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
         "Server: Asterisk/%s\r\n"
         "Date: %s\r\n"
         "Connection: close\r\n"
         "Cache-Control: no-cache, no-store\r\n"
         "Content-Length: %d\r\n"
         "Content-Type: %s\r\n\r\n",
         ast_get_version(), buf, len, route->file->mime_type);

      while ((len = read(fd, buf, sizeof(buf))) > 0) {
         if (fwrite(buf, 1, len, ser->f) != len) {
            if (errno != EPIPE) {
               ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
            } else {
               ast_debug(3, "Requester closed the connection while downloading '%s'\n", path);
            }
            break;
         }
      }

      close(fd);
      route = unref_route(route);
      return NULL;
   } else { /* Dynamic file */
      int bufsize;
      char *tmp;

      len = load_file(path, &file);
      if (len < 0) {
         ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, len);
         if (file) {
            ast_free(file);
         }

         goto out500;
      }

      if (!file) {
         goto out500;
      }

      /* XXX This is a hack -- maybe sum length of all variables in route->user->headp and add that? */
      bufsize = len + VAR_BUF_SIZE;

      /* malloc() instead of alloca() here, just in case the file is bigger than
       * we have enough stack space for. */
      if (!(tmp = ast_calloc(1, bufsize))) {
         if (file) {
            ast_free(file);
         }

         goto out500;
      }

      /* Unless we are overridden by serveriface or serveraddr, we set the SERVER variable to
       * the IP address we are listening on that the phone contacted for this config file */
      if (ast_strlen_zero(global_server)) {
         union {
            struct sockaddr sa;
            struct sockaddr_in sa_in;
         } name;
         socklen_t namelen = sizeof(name.sa);
         int res;

         if ((res = getsockname(ser->fd, &name.sa, &namelen))) {
            ast_log(LOG_WARNING, "Could not get server IP, breakage likely.\n");
         } else {
            struct ast_var_t *var;
            struct extension *exten_iter;

            if ((var = ast_var_assign("SERVER", ast_inet_ntoa(name.sa_in.sin_addr)))) {
               AST_LIST_TRAVERSE(&route->user->extensions, exten_iter, entry) {
                  AST_LIST_INSERT_TAIL(exten_iter->headp, var, entries);
               }
            }
         }
      }

      pbx_substitute_variables_varshead(AST_LIST_FIRST(&route->user->extensions)->headp, file, tmp, bufsize);

      if (file) {
         ast_free(file);
      }

      ast_str_append(&result, 0,
         "Content-Type: %s\r\n"
         "Content-length: %d\r\n"
         "\r\n"
         "%s", route->file->mime_type, (int) strlen(tmp), tmp);

      if (tmp) {
         ast_free(tmp);
      }

      route = unref_route(route);

      return result;
   }

out404:
   *status = 404;
   *title = strdup("Not Found");
   *contentlength = 0;
   return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");

out500:
   route = unref_route(route);
   *status = 500;
   *title = strdup("Internal Server Error");
   *contentlength = 0;
   return ast_http_error(500, "Internal Error", NULL, "An internal error has occured.");
}
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(), user, and VAR_BUF_SIZE.

{
   struct user *user;
   struct extension *exten;
   char path[PATH_MAX];
   char *file;
   int filelen;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(mac);
      AST_APP_ARG(template);
   );

   AST_STANDARD_APP_ARGS(args, data);

   if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) {
      ast_log(LOG_WARNING, "PP_EACH_EXTENSION requries both a macaddress and template filename.\n");
      return 0;
   }

   if (!(user = find_user(args.mac))) {
      ast_log(LOG_WARNING, "Could not find user with mac = '%s'\n", args.mac);
      return 0;
   }

   snprintf(path, sizeof(path), "%s/phoneprov/%s", ast_config_AST_DATA_DIR, args.template);
   filelen = load_file(path, &file);
   if (filelen < 0) {
      ast_log(LOG_WARNING, "Could not load file: %s (%d)\n", path, filelen);
      if (file) {
         ast_free(file);
      }
      return 0;
   }

   if (!file) {
      return 0;
   }

   AST_LIST_TRAVERSE(&user->extensions, exten, entry) {
      char expand_buf[VAR_BUF_SIZE] = {0,};
      pbx_substitute_variables_varshead(exten->headp, file, expand_buf, sizeof(expand_buf));
      ast_build_string(&buf, &len, "%s", expand_buf);
   }

   ast_free(file);

   user = unref_user(user);

   return 0;
}
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(), user, and VAR_BUF_SIZE.

{
   char *tmp, expand_buf[VAR_BUF_SIZE] = {0,};
   struct ao2_iterator i;
   struct user *user;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(string);
      AST_APP_ARG(exclude_mac);
   );
   AST_STANDARD_APP_ARGS(args, data);

   /* Fix data by turning %{ into ${ */
   while ((tmp = strstr(args.string, "%{")))
      *tmp = '$';

   i = ao2_iterator_init(users, 0);
   while ((user = ao2_iterator_next(&i))) {
      if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->macaddress, args.exclude_mac)) {
         continue;
      }
      pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, args.string, expand_buf, sizeof(expand_buf));
      ast_build_string(&buf, &len, "%s", expand_buf);
      user = unref_user(user);
   }
   ao2_iterator_destroy(&i);

   return 0;
}
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().

{
   const struct phone_profile *profile1 = obj, *profile2 = arg;

   return !strcasecmp(profile1->name, profile2->name) ? CMP_MATCH | CMP_STOP : 0;
}
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().

{
   struct phone_profile *profile = obj;
   struct phoneprov_file *file;
   struct ast_var_t *var;

   while ((file = AST_LIST_REMOVE_HEAD(&profile->static_files, entry)))
      delete_file(file);

   while ((file = AST_LIST_REMOVE_HEAD(&profile->dynamic_files, entry)))
      delete_file(file);

   while ((var = AST_LIST_REMOVE_HEAD(profile->headp, entries)))
      ast_var_delete(var);

   ast_free(profile->headp);
   ast_string_field_free_memory(profile);
}
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().

{
   const struct phone_profile *profile = obj;

   return ast_str_case_hash(profile->name);
}
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().

{
   struct http_route *route = obj;

   ast_string_field_free_memory(route);
}
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().

{
   const struct http_route *route1 = obj, *route2 = arg;

   return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
}
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().

{
   const struct http_route *route = obj;

   return ast_str_case_hash(route->uri);
}
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(), user, ast_variable::value, and var.

Referenced by load_module(), and reload().

{
   struct ast_config *cfg, *phoneprov_cfg;
   char *cat;
   struct ast_variable *v;
   struct ast_flags config_flags = { 0 };
   struct ast_var_t *var;

   /* Try to grab the port from sip.conf.  If we don't get it here, we'll set it
    * to whatever is set in phoneprov.conf or default to 5060 */
   if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
      ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport));
      ast_config_destroy(cfg);
   }

   if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING, "Unable to load users.conf\n");
      return 0;
   }

   /* Go ahead and load global variables from users.conf so we can append to profiles */
   for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
      if (!strcasecmp(v->name, "vmexten")) {
         if ((var = ast_var_assign("VOICEMAIL_EXTEN", v->value))) {
            ast_mutex_lock(&globals_lock);
            AST_LIST_INSERT_TAIL(&global_variables, var, entries);
            ast_mutex_unlock(&globals_lock);
         }
      }
      if (!strcasecmp(v->name, "localextenlength")) {
         if ((var = ast_var_assign("EXTENSION_LENGTH", v->value)))
            ast_mutex_lock(&globals_lock);
            AST_LIST_INSERT_TAIL(&global_variables, var, entries);
            ast_mutex_unlock(&globals_lock);
      }
   }

   if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
      ast_config_destroy(cfg);
      return -1;
   }

   cat = NULL;
   while ((cat = ast_category_browse(phoneprov_cfg, cat))) {
      if (!strcasecmp(cat, "general")) {
         for (v = ast_variable_browse(phoneprov_cfg, cat); v; v = v->next) {
            if (!strcasecmp(v->name, "serveraddr"))
               ast_copy_string(global_server, v->value, sizeof(global_server));
            else if (!strcasecmp(v->name, "serveriface")) {
               struct in_addr addr;
               lookup_iface(v->value, &addr);
               ast_copy_string(global_server, ast_inet_ntoa(addr), sizeof(global_server));
            } else if (!strcasecmp(v->name, "serverport"))
               ast_copy_string(global_serverport, v->value, sizeof(global_serverport));
            else if (!strcasecmp(v->name, "default_profile"))
               ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile));
         }
      } else
         build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
   }

   ast_config_destroy(phoneprov_cfg);

   cat = NULL;
   while ((cat = ast_category_browse(cfg, cat))) {
      const char *tmp, *mac;
      struct user *user;
      struct phone_profile *profile;
      struct extension *exten;

      if (!strcasecmp(cat, "general")) {
         continue;
      }

      if (!strcasecmp(cat, "authentication"))
         continue;

      if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp)))
         continue;

      if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) {
         ast_log(LOG_WARNING, "autoprov set for %s, but no mac address - skipping.\n", cat);
         continue;
      }

      tmp = S_OR(ast_variable_retrieve(cfg, cat, "profile"), global_default_profile);
      if (ast_strlen_zero(tmp)) {
         ast_log(LOG_WARNING, "No profile for user [%s] with mac '%s' - skipping\n", cat, mac);
         continue;
      }

      if (!(user = find_user(mac))) {
         if (!(profile = find_profile(tmp))) {
            ast_log(LOG_WARNING, "Could not look up profile '%s' - skipping.\n", tmp);
            continue;
         }

         if (!(user = build_user(mac, profile))) {
            ast_log(LOG_WARNING, "Could not create user for '%s' - skipping\n", user->macaddress);
            continue;
         }

         if (!(exten = build_extension(cfg, cat))) {
            ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
            user = unref_user(user);
            continue;
         }

         if (add_user_extension(user, exten)) {
            ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
            user = unref_user(user);
            exten = delete_extension(exten);
            continue;
         }

         if (build_user_routes(user)) {
            ast_log(LOG_WARNING, "Could not create http routes for %s - skipping\n", user->macaddress);
            user = unref_user(user);
            continue;
         }

         ao2_link(users, user);
         user = unref_user(user);
      } else {
         if (!(exten = build_extension(cfg, cat))) {
            ast_log(LOG_WARNING, "Could not create extension for %s - skipping\n", user->macaddress);
            user = unref_user(user);
            continue;
         }

         if (add_user_extension(user, exten)) {
            ast_log(LOG_WARNING, "Could not add extension '%s' to user '%s'\n", exten->name, user->macaddress);
            user = unref_user(user);
            exten = delete_extension(exten);
            continue;
         }

         user = unref_user(user);
      }
   }

   ast_config_destroy(cfg);

   return 0;
}
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:
headppointer to list of user variables
zoneA 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().

{
   time_t utc_time;
   int dstenable;
   time_t dststart;
   time_t dstend;
   struct ast_tm tm_info;
   int tzoffset;
   char buffer[21];
   struct ast_var_t *var;
   struct timeval when;

   time(&utc_time);
   ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone);
   snprintf(buffer, sizeof(buffer), "%d", tzoffset);
   var = ast_var_assign("TZOFFSET", buffer);
   if (var)
      AST_LIST_INSERT_TAIL(headp, var, entries);

   if (!dstenable)
      return;

   if ((var = ast_var_assign("DST_ENABLE", "1")))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   when.tv_sec = dststart;
   ast_localtime(&when, &tm_info, zone);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1);
   if ((var = ast_var_assign("DST_START_MONTH", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
   if ((var = ast_var_assign("DST_START_MDAY", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
   if ((var = ast_var_assign("DST_START_HOUR", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   when.tv_sec = dstend;
   ast_localtime(&when, &tm_info, zone);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon + 1);
   if ((var = ast_var_assign("DST_END_MONTH", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mday);
   if ((var = ast_var_assign("DST_END_MDAY", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);

   snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_hour);
   if ((var = ast_var_assign("DST_END_HOUR", buffer)))
      AST_LIST_INSERT_TAIL(headp, var, entries);
}
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().

{
   ao2_ref(prof, -1);

   return NULL;
}
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().

{
   ao2_ref(route, -1);

   return NULL;
}
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().

{
   ao2_ref(user, -1);

   return NULL;
}
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().

{
   struct user *user = obj;
   struct extension *exten;

   while ((exten = AST_LIST_REMOVE_HEAD(&user->extensions, entry))) {
      exten = delete_extension(exten);
   }

   if (user->profile) {
      user->profile = unref_profile(user->profile);
   }

   ast_string_field_free_memory(user);
}
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().

{
   const struct user *user1 = obj, *user2 = arg;

   return !strcasecmp(user1->macaddress, user2->macaddress) ? CMP_MATCH | CMP_STOP : 0;
}
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().

{
   const struct user *user = obj;

   return ast_str_case_hash(user->macaddress);
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "HTTP Phone Provisioning" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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]

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.

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.