static void qualify_and_schedule_all(void) { struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; struct ao2_container *contacts; if (!var) { return; } aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); if (aors) { ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); ao2_ref(aors, -1); } contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); ao2_ref(contacts, -1); } ast_variables_destroy(var); }
static int json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables) { struct ast_variable *current = NULL; struct ast_json_iter *it_json_var; for (it_json_var = ast_json_object_iter(json_variables); it_json_var; it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) { struct ast_variable *new_var; new_var = ast_variable_new(ast_json_object_iter_key(it_json_var), ast_json_string_get(ast_json_object_iter_value(it_json_var)), ""); if (!new_var) { ast_variables_destroy(*variables); *variables = NULL; return 1; } if (!current) { *variables = new_var; current = *variables; } else { current->next = new_var; current = new_var; } } return 0; }
int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables) { struct ast_json_iter *it_json_var; *variables = NULL; for (it_json_var = ast_json_object_iter(json_variables); it_json_var; it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) { struct ast_variable *new_var; const char *key = ast_json_object_iter_key(it_json_var); if (ast_strlen_zero(key)) { continue; } new_var = ast_variable_new(key, ast_json_string_get(ast_json_object_iter_value(it_json_var)), ""); if (!new_var) { ast_variables_destroy(*variables); *variables = NULL; return -1; } ast_variable_list_append(variables, new_var); } return 0; }
static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf) { struct ast_variable *objset; struct ast_variable *i; objset = ast_sorcery_objectset_create2(ast_sip_get_sorcery(), aor, AST_HANDLER_ONLY_STRING); if (!objset) { return -1; } ast_str_append(buf, 0, "ObjectType: %s\r\n", ast_sorcery_object_get_type(aor)); ast_str_append(buf, 0, "ObjectName: %s\r\n", ast_sorcery_object_get_id(aor)); for (i = objset; i; i = i->next) { char *camel = ast_to_camel_case(i->name); if (strcmp(camel, "Contact") == 0) { ast_free(camel); camel = NULL; } ast_str_append(buf, 0, "%s: %s\r\n", S_OR(camel, "Contacts"), i->value); ast_free(camel); } ast_variables_destroy(objset); return 0; }
static void return_sorcery_object(struct ast_sorcery *sorcery, void *sorcery_obj, struct ast_ari_response *response) { RAII_VAR(struct ast_json *, return_set, NULL, ast_json_unref); struct ast_variable *change_set; struct ast_variable *it_change_set; return_set = ast_json_array_create(); if (!return_set) { ast_ari_response_alloc_failed(response); return; } /* Note that we can't use the sorcery JSON change set directly, * as it will hand us back an Object (with fields), and we need * a more generic representation of whatever the API call asked * for, i.e., a list of tuples. */ change_set = ast_sorcery_objectset_create(sorcery, sorcery_obj); if (!change_set) { ast_ari_response_alloc_failed(response); return; } for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) { struct ast_json *tuple; tuple = ast_json_pack("{s: s, s: s}", "attribute", it_change_set->name, "value", it_change_set->value); if (!tuple) { ast_variables_destroy(change_set); ast_ari_response_alloc_failed(response); return; } if (ast_json_array_append(return_set, tuple)) { ast_json_unref(tuple); ast_variables_destroy(change_set); ast_ari_response_alloc_failed(response); return; } } ast_variables_destroy(change_set); ast_ari_response_ok(response, ast_json_ref(return_set)); }
/*! * \internal * \brief Destroy the notify AMI data releasing any resources. */ static void notify_ami_data_destroy(void *obj) { struct notify_data *data = obj; struct ast_variable *info = data->info; ao2_cleanup(data->endpoint); ast_variables_destroy(info); }
/*! * \internal * \brief Destroy the notify AMI URI data releasing any resources. */ static void notify_ami_uri_data_destroy(void *obj) { struct notify_uri_data *data = obj; struct ast_variable *info = data->info; ast_free(data->uri); ast_variables_destroy(info); }
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables) { struct ast_json_iter *it_json_var; *variables = NULL; for (it_json_var = ast_json_object_iter(json_variables); it_json_var; it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) { struct ast_variable *new_var; const char *key = ast_json_object_iter_key(it_json_var); const char *value; struct ast_json *json_value; if (ast_strlen_zero(key)) { continue; } json_value = ast_json_object_iter_value(it_json_var); if (ast_json_typeof(json_value) != AST_JSON_STRING) { /* Error: Only strings allowed */ ast_variables_destroy(*variables); *variables = NULL; return AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE; } value = ast_json_string_get(json_value); /* Should never be NULL. Otherwise, how could it be a string type? */ ast_assert(value != NULL); if (!value) { /* To be safe. */ continue; } new_var = ast_variable_new(key, value, ""); if (!new_var) { /* Error: OOM */ ast_variables_destroy(*variables); *variables = NULL; return AST_JSON_TO_AST_VARS_CODE_OOM; } ast_variable_list_append(variables, new_var); } return AST_JSON_TO_AST_VARS_CODE_SUCCESS; }
static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { const struct ast_channel_tech *tech = NULL; struct ast_variable *channel_types, *next; static unsigned long long_ret; struct ast_channel *chan; u_long i; if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) return NULL; channel_types = ast_channeltype_list(); for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++) ; if (next != NULL) tech = ast_get_channel_tech(next->name); ast_variables_destroy(channel_types); if (next == NULL || tech == NULL) return NULL; switch (vp->magic) { case ASTCHANTYPEINDEX: long_ret = name[*length - 1]; return (u_char *)&long_ret; case ASTCHANTYPENAME: *var_len = strlen(tech->type); return (u_char *)tech->type; case ASTCHANTYPEDESC: *var_len = strlen(tech->description); return (u_char *)tech->description; case ASTCHANTYPEDEVSTATE: long_ret = tech->devicestate ? 1 : 2; return (u_char *)&long_ret; case ASTCHANTYPEINDICATIONS: long_ret = tech->indicate ? 1 : 2; return (u_char *)&long_ret; case ASTCHANTYPETRANSFER: long_ret = tech->transfer ? 1 : 2; return (u_char *)&long_ret; case ASTCHANTYPECHANNELS: long_ret = 0; for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) { if (chan->tech == tech) long_ret++; ast_channel_unlock(chan); } return (u_char *)&long_ret; default: break; } return NULL; }
/*! \brief Internal helper function which returns a filtered objectset. * * The following are filtered out of the objectset: * \li The id field. This is returned to the caller in an out parameter. * \li Fields that are not registered with sorcery. * * \param objectset Objectset to filter. * \param[out] id The ID of the sorcery object, as found in the objectset. * \param sorcery The sorcery instance that is requesting an objectset. * \param type The object type * * \return The filtered objectset */ static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variable *objectset, struct ast_variable **id, const struct ast_sorcery *sorcery, const char *type) { struct ast_variable *previous = NULL, *field = objectset; struct ast_sorcery_object_type *object_type; object_type = ast_sorcery_get_object_type(sorcery, type); if (!object_type) { ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type); /* Continue since we still want to filter out the id */ } while (field) { int remove_field = 0; int delete_field = 0; if (!strcmp(field->name, UUID_FIELD)) { *id = field; remove_field = 1; } else if (object_type && !ast_sorcery_is_object_field_registered(object_type, field->name)) { ast_debug(1, "Filtering out realtime field '%s' from retrieval\n", field->name); remove_field = 1; delete_field = 1; } if (remove_field) { struct ast_variable *removed; if (previous) { previous->next = field->next; } else { objectset = field->next; } removed = field; field = field->next; removed->next = NULL; if (delete_field) { ast_variables_destroy(removed); } } else { previous = field; field = field->next; } } ao2_cleanup(object_type); return objectset; }
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags) { struct ast_sip_cli_context *context = arg; struct ast_variable *i; int max_name_width = 13; int max_value_width = 14; int width; char *separator; struct ast_variable *objset; if (!context->output_buffer) { return -1; } objset = ast_sorcery_objectset_create(ast_sip_get_sorcery(),obj); if (!objset) { return -1; } for (i = objset; i; i = i->next) { if (i->name) { width = strlen(i->name); max_name_width = width > max_name_width ? width : max_name_width; } if (i->value) { width = strlen(i->value); max_value_width = width > max_value_width ? width : max_value_width; } } separator = ast_alloca(max_name_width + max_value_width + 8); memset(separator, '=', max_name_width + max_value_width + 3); separator[max_name_width + max_value_width + 3] = 0; ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, "ParameterName", "ParameterValue"); ast_str_append(&context->output_buffer, 0, " %s\n", separator); objset = ast_variable_list_sort(objset); for (i = objset; i; i = i->next) { ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, i->name, i->value); } ast_variables_destroy(objset); return 0; }
static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object) { const char *family = data; RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy); struct ast_variable *id = ast_variable_new(UUID_FIELD, ast_sorcery_object_get_id(object), ""); if (!fields || !id) { ast_variables_destroy(id); return -1; } /* Place the identifier at the front for sanity sake */ id->next = fields; fields = id; return (ast_store_realtime_fields(family, fields) <= 0) ? -1 : 0; }
static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; struct ast_variable *channel_types, *next; if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL; if (vp->magic != ASTCHANTYPECOUNT) return NULL; for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next) long_ret++; ast_variables_destroy(channel_types); return (u_char *)&long_ret; }
/*! \brief Helper function which converts a json object to a sorcery object set */ static struct ast_variable *sorcery_json_to_objectset(struct ast_json *json) { struct ast_json_iter *field; struct ast_variable *objset = NULL; for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) { struct ast_json *value = ast_json_object_iter_value(field); struct ast_variable *variable = ast_variable_new(ast_json_object_iter_key(field), ast_json_string_get(value), ""); if (!variable) { ast_variables_destroy(objset); return NULL; } variable->next = objset; objset = variable; } return objset; }
/*! \brief Internal helper function which returns a filtered objectset. * * The following are filtered out of the objectset: * \li Fields that are not registered with sorcery. * * \param objectset Objectset to filter. * \param sorcery The sorcery instance that is requesting an objectset. * \param type The object type * * \return The filtered objectset */ static struct ast_variable *sorcery_astdb_filter_objectset(struct ast_variable *objectset, const struct ast_sorcery *sorcery, const char *type) { struct ast_variable *previous = NULL, *field = objectset; struct ast_sorcery_object_type *object_type; object_type = ast_sorcery_get_object_type(sorcery, type); if (!object_type) { ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type); return objectset; } while (field) { struct ast_variable *removed; if (ast_sorcery_is_object_field_registered(object_type, field->name)) { previous = field; field = field->next; continue; } ast_debug(1, "Filtering out astdb field '%s' from retrieval\n", field->name); if (previous) { previous->next = field->next; } else { objectset = field->next; } removed = field; field = field->next; removed->next = NULL; ast_variables_destroy(removed); } ao2_cleanup(object_type); return objectset; }
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields) { const char *family = data; RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy); RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy); struct ast_category *row = NULL; if (!fields) { char field[strlen(UUID_FIELD) + 6], value[2]; /* If no fields have been specified we want all rows, so trick realtime into doing it */ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); snprintf(value, sizeof(value), "%%"); if (!(all = ast_variable_new(field, value, ""))) { return; } fields = all; } if (!(rows = ast_load_realtime_multientry_fields(family, fields))) { return; } while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) { struct ast_variable *objectset = ast_category_detach_variables(row); RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy); RAII_VAR(void *, object, NULL, ao2_cleanup); objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type); if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) { ao2_link(objects, object); } ast_variables_destroy(objectset); } }
static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; struct ast_variable *channel_types, *next; if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL; switch (vp->magic) { case ASTCHANTYPECOUNT: long_ret = 0; for (channel_types = next = ast_channeltype_list(); next; next = next->next) { long_ret++; } ast_variables_destroy(channel_types); return (u_char *)&long_ret; default: break; } return NULL; }
/*! * \internal * \brief Completes SIPNotify AMI command in URI mode. */ static void manager_notify_uri(struct mansession *s, const struct message *m, const char *uri) { struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL); switch (push_notify_uri(uri, vars, notify_ami_uri_data_create)) { case INVALID_ENDPOINT: /* Shouldn't be possible. */ ast_assert(0); break; case ALLOC_ERROR: ast_variables_destroy(vars); astman_send_error(s, m, "Unable to allocate NOTIFY task data"); break; case TASK_PUSH_ERROR: /* Don't need to destroy vars since it is handled by cleanup in push_notify_uri */ astman_send_error(s, m, "Unable to push Notify task"); break; case SUCCESS: astman_send_ack(s, m, "NOTIFY sent"); break; } }
static char *cli_realtime_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { #define CRL_HEADER_FORMAT "%30s %-30s\n" struct ast_variable *var = NULL, *orig_var = NULL; switch (cmd) { case CLI_INIT: e->command = "realtime load"; e->usage = "Usage: realtime load <family> <colmatch> <value>\n" " Prints out a list of variables using the RealTime driver.\n" " You must supply a family name, a column to match on, and a value to match to.\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc < 5) return CLI_SHOWUSAGE; var = ast_load_realtime_all(a->argv[2], a->argv[3], a->argv[4], SENTINEL); if (var) { ast_cli(a->fd, CRL_HEADER_FORMAT, "Column Name", "Column Value"); ast_cli(a->fd, CRL_HEADER_FORMAT, "--------------------", "--------------------"); orig_var = var; while (var) { ast_cli(a->fd, CRL_HEADER_FORMAT, var->name, var->value); var = var->next; } } else { ast_cli(a->fd, "No rows found matching search criteria.\n"); } ast_variables_destroy(orig_var); return CLI_SUCCESS; }
/*! * \internal * \brief Find an endpoint associated with the given contact. */ static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact) { struct ao2_container *endpoints; struct ast_sip_endpoint *endpoint; struct ast_variable *var; char *aor = ast_alloca(strlen(contact->aor) + 3); sprintf(aor, "%%%s%%", contact->aor); var = ast_variable_new("aors LIKE", aor, ""); endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var); ast_variables_destroy(var); /* * Because aors are a string list, we have to use a pattern match but since a simple * pattern match could return an endpoint that has an aor of "aaabccc" when searching * for "abc", we still have to iterate over them to find an exact aor match. */ endpoint = ao2_callback(endpoints, 0, on_endpoint, (char *)contact->aor); ao2_ref(endpoints, -1); return endpoint; }
static void *ast_httpd_helper_thread(void *data) { char buf[4096]; char cookie[4096]; char timebuf[256]; struct ast_http_server_instance *ser = data; struct ast_variable *var, *prev=NULL, *vars=NULL; char *uri, *c, *title=NULL; char *vname, *vval; int status = 200, contentlength = 0; time_t t; if (fgets(buf, sizeof(buf), ser->f)) { /* Skip method */ uri = buf; while(*uri && (*uri > 32)) uri++; if (*uri) { *uri = '\0'; uri++; } /* Skip white space */ while (*uri && (*uri < 33)) uri++; if (*uri) { c = uri; while (*c && (*c > 32)) c++; if (*c) { *c = '\0'; } } while (fgets(cookie, sizeof(cookie), ser->f)) { /* Trim trailing characters */ while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) { cookie[strlen(cookie) - 1] = '\0'; } if (ast_strlen_zero(cookie)) break; if (!strncasecmp(cookie, "Cookie: ", 8)) { vname = cookie + 8; vval = strchr(vname, '='); if (vval) { /* Ditch the = and the quotes */ *vval = '\0'; vval++; if (*vval) vval++; if (strlen(vval)) vval[strlen(vval) - 1] = '\0'; var = ast_variable_new(vname, vval); if (var) { if (prev) prev->next = var; else vars = var; prev = var; } } } } if (*uri) { if (!strcasecmp(buf, "get")) c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars); else c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ } else c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); /* If they aren't mopped up already, clean up the cookies */ if (vars) ast_variables_destroy(vars); if (!c) c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); if (c) { time(&t); strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK"); ast_cli(ser->fd, "Server: Asterisk\r\n"); ast_cli(ser->fd, "Date: %s\r\n", timebuf); ast_cli(ser->fd, "Connection: close\r\n"); if (contentlength) { char *tmp; tmp = strstr(c, "\r\n\r\n"); if (tmp) { ast_cli(ser->fd, "Content-length: %d\r\n", contentlength); write(ser->fd, c, (tmp + 4 - c)); write(ser->fd, tmp + 4, contentlength); } } else ast_cli(ser->fd, "%s", c); free(c); } if (title) free(title); } fclose(ser->f); free(ser); return NULL; }
static int http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) { struct ast_variable *var, *cookies; unsigned long ident = 0; FILE *f; int content_len = 0; struct ast_str *post_dir; GMimeMessage *message; int message_count = 0; char * boundary_marker = NULL; if (method != AST_HTTP_POST) { ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); return -1; } if (!astman_is_authed(ast_http_manid_from_vars(headers))) { ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave."); return -1; } if (!urih) { ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request"); return -1; } cookies = ast_http_get_cookies(headers); for (var = cookies; var; var = var->next) { if (!strcasecmp(var->name, "mansession_id")) { sscanf(var->value, "%30lx", &ident); break; } } if (cookies) { ast_variables_destroy(cookies); } if (ident == 0) { ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); return -1; } if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) { ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); return -1; } if (!(f = tmpfile())) { ast_log(LOG_ERROR, "Could not create temp file.\n"); ast_http_error(ser, 500, "Internal server error", "Could not create temp file."); return -1; } for (var = headers; var; var = var->next) { fprintf(f, "%s: %s\r\n", var->name, var->value); if (!strcasecmp(var->name, "Content-Length")) { if ((sscanf(var->value, "%30u", &content_len)) != 1) { ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n"); fclose(f); ast_http_error(ser, 500, "Internal server error", "Invalid Content-Length in POST request!"); return -1; } ast_debug(1, "Got a Content-Length of %d\n", content_len); } else if (!strcasecmp(var->name, "Content-Type")) { boundary_marker = strstr(var->value, "boundary="); if (boundary_marker) { boundary_marker += strlen("boundary="); } } } fprintf(f, "\r\n"); if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { if (option_debug) { ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n"); } fclose(f); return -1; } if (fseek(f, SEEK_SET, 0)) { ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n"); fclose(f); ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning."); return -1; } post_dir = urih->data; message = parse_message(f); /* Takes ownership and will close f */ if (!message) { ast_log(LOG_ERROR, "Error parsing MIME data\n"); ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); return -1; } if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) { ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n"); g_object_unref(message); ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); return -1; } g_object_unref(message); ast_http_error(ser, 200, "OK", "File successfully uploaded."); return 0; }
void ast_ari_asterisk_update_object(struct ast_variable *headers, struct ast_ari_asterisk_update_object_args *args, struct ast_ari_response *response) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref); RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup); RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup); struct ast_json *fields; struct ast_variable *update_set = NULL; int created = 0; sorcery = ast_sorcery_retrieve_by_module_name(args->config_class); if (!sorcery) { ast_ari_response_error( response, 404, "Not Found", "configClass '%s' not found", args->config_class); return; } object_type = ast_sorcery_get_object_type(sorcery, args->object_type); if (!object_type) { ast_ari_response_error( response, 404, "Not Found", "objectType '%s' not found", args->object_type); return; } sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args->object_type, args->id); if (!sorcery_obj) { ast_debug(5, "Sorcery object '%s' does not exist; creating it\n", args->id); sorcery_obj = ast_sorcery_alloc(sorcery, args->object_type, args->id); if (!sorcery_obj) { ast_ari_response_alloc_failed(response); return; } created = 1; } else { void *copy; copy = ast_sorcery_copy(sorcery, sorcery_obj); if (!copy) { ast_ari_response_alloc_failed(response); return; } ao2_ref(sorcery_obj, -1); sorcery_obj = copy; } fields = ast_json_object_get(args->fields, "fields"); if (!fields && !created) { /* Whoops. We need data. */ ast_ari_response_error( response, 400, "Bad request", "Fields must be provided to update object '%s'", args->id); return; } else if (fields) { size_t i; for (i = 0; i < ast_json_array_size(fields); i++) { struct ast_variable *new_var; struct ast_json *json_value = ast_json_array_get(fields, i); if (!json_value) { continue; } new_var = ast_variable_new( ast_json_string_get(ast_json_object_get(json_value, "attribute")), ast_json_string_get(ast_json_object_get(json_value, "value")), ""); if (!new_var) { ast_variables_destroy(update_set); ast_ari_response_alloc_failed(response); return; } ast_variable_list_append(&update_set, new_var); } } /* APPLY! Note that a NULL update_set is fine (and necessary), as it * will force validation on a newly created object. */ if (ast_sorcery_objectset_apply(sorcery, sorcery_obj, update_set)) { ast_variables_destroy(update_set); ast_ari_response_error( response, 400, "Bad request", "%s of object '%s' failed field value validation", created ? "Creation" : "Update", args->id); return; } ast_variables_destroy(update_set); if (created) { if (ast_sorcery_create(sorcery, sorcery_obj)) { ast_ari_response_error( response, 403, "Forbidden", "Cannot create sorcery objects of type '%s'", args->object_type); return; } } else { if (ast_sorcery_update(sorcery, sorcery_obj)) { ast_ari_response_error( response, 403, "Forbidden", "Cannot update sorcery objects of type '%s'", args->object_type); return; } } return_sorcery_object(sorcery, sorcery_obj, response); }
static void *ast_httpd_helper_thread(void *data) { char buf[4096]; char cookie[4096]; char timebuf[256]; struct ast_http_server_instance *ser = data; struct ast_variable *vars = NULL; char *uri, *c, *title=NULL; int status = 200, contentlength = 0; time_t t; unsigned int static_content = 0; if (fgets(buf, sizeof(buf), ser->f)) { /* Skip method */ uri = buf; while(*uri && (*uri > 32)) uri++; if (*uri) { *uri = '\0'; uri++; } /* Skip white space */ while (*uri && (*uri < 33)) uri++; if (*uri) { c = uri; while (*c && (*c > 32)) c++; if (*c) { *c = '\0'; } } while (fgets(cookie, sizeof(cookie), ser->f)) { /* Trim trailing characters */ while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) { cookie[strlen(cookie) - 1] = '\0'; } if (ast_strlen_zero(cookie)) break; if (!strncasecmp(cookie, "Cookie: ", 8)) { vars = parse_cookies(cookie); } } if (*uri) { if (!strcasecmp(buf, "get")) c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content); else c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\ } else c = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); /* If they aren't mopped up already, clean up the cookies */ if (vars) ast_variables_destroy(vars); if (!c) c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error"); if (c) { time(&t); strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t)); ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK"); ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION); ast_cli(ser->fd, "Date: %s\r\n", timebuf); ast_cli(ser->fd, "Connection: close\r\n"); if (!static_content) ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n"); /* We set the no-cache headers only for dynamic content. * If you want to make sure the static file you requested is not from cache, * append a random variable to your GET request. Ex: 'something.html?r=109987734' */ if (contentlength) { char *tmp; tmp = strstr(c, "\r\n\r\n"); if (tmp) { ast_cli(ser->fd, "Content-length: %d\r\n", contentlength); if (write(ser->fd, c, (tmp + 4 - c)) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } if (write(ser->fd, tmp + 4, contentlength) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } else ast_cli(ser->fd, "%s", c); free(c); } if (title) free(title); } fclose(ser->f); free(ser); ast_atomic_fetchadd_int(&session_count, -1); return NULL; }
static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies, unsigned int *static_content) { char *c; char *turi; char *params; char *var; char *val; struct ast_http_uri *urih=NULL; int len; struct ast_variable *vars=NULL, *v, *prev = NULL; params = strchr(uri, '?'); if (params) { *params = '\0'; params++; while ((var = strsep(¶ms, "&"))) { val = strchr(var, '='); if (val) { *val = '\0'; val++; ast_uri_decode(val); } else val = ""; ast_uri_decode(var); if ((v = ast_variable_new(var, val))) { if (vars) prev->next = v; else vars = v; prev = v; } } } if (prev) prev->next = *cookies; else vars = *cookies; *cookies = NULL; ast_uri_decode(uri); if (!strncasecmp(uri, prefix, prefix_len)) { uri += prefix_len; if (!*uri || (*uri == '/')) { if (*uri == '/') uri++; ast_rwlock_rdlock(&uris_lock); urih = uris; while(urih) { len = strlen(urih->uri); if (!strncasecmp(urih->uri, uri, len)) { if (!uri[len] || uri[len] == '/') { turi = uri + len; if (*turi == '/') turi++; if (!*turi || urih->has_subtree) { uri = turi; break; } } } urih = urih->next; } if (!urih) ast_rwlock_unlock(&uris_lock); } } if (urih) { if (urih->static_content) *static_content = 1; c = urih->callback(sin, uri, vars, status, title, contentlength); ast_rwlock_unlock(&uris_lock); } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) { /* Special case: If no prefix, and no URI, send to /static/index.html */ c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "Redirecting to /static/index.html."); *status = 302; *title = strdup("Moved Temporarily"); } else { c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server."); *status = 404; *title = strdup("Not Found"); } ast_variables_destroy(vars); return c; }