[asterisk-commits] tilghman: branch group/ast_storage r48122 - in
/team/group/ast_storage: inclu...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Wed Nov 29 18:29:35 MST 2006
Author: tilghman
Date: Wed Nov 29 19:29:34 2006
New Revision: 48122
URL: http://svn.digium.com/view/asterisk?view=rev&rev=48122
Log:
Lots of revisions on storage types
Added:
team/group/ast_storage/res/res_storage_odbc.c (with props)
Modified:
team/group/ast_storage/include/asterisk/storage.h
team/group/ast_storage/main/storage.c
team/group/ast_storage/res/res_storage_file.c
Modified: team/group/ast_storage/include/asterisk/storage.h
URL: http://svn.digium.com/view/asterisk/team/group/ast_storage/include/asterisk/storage.h?view=diff&rev=48122&r1=48121&r2=48122
==============================================================================
--- team/group/ast_storage/include/asterisk/storage.h (original)
+++ team/group/ast_storage/include/asterisk/storage.h Wed Nov 29 19:29:34 2006
@@ -31,34 +31,77 @@
extern "C" {
#endif
-struct ast_storage {
+struct ast_storage_be {
const char *name;
- int type;
- int (*get)(int blah);
- int (*put)(int blah);
- int (*delete)(int blah);
- int (*count)(int blah);
- int (*parseoptions)(const char *var, const char *value);
- AST_LIST_ENTRY(ast_storage) list;
+ struct ast_storage *(*new)(const char *uri);
+ int (*free)(struct ast_storage *st);
+ int (*get)(struct ast_storage *st, const char *objectname, char *localfile, size_t localfilesize);
+ int (*put)(struct ast_storage *st, const char *objectname, const char *localfile);
+ int (*delete)(struct ast_storage *st, const char *objectname);
+ int (*count)(struct ast_storage *st, const char *objectpath);
+ int (*parseoptions)(struct ast_storage *st, const char *var, const char *value);
+ AST_LIST_ENTRY(ast_storage_be) list;
struct ast_module *module;
};
-#define AST_STORAGE_FILE (1 << 0)
-#define AST_STORAGE_ODBC (1 << 1)
-#define AST_STORAGE_IMAP (1 << 2)
+/* Most specific backends will have longer structures */
+struct ast_storage {
+ struct ast_storage_be *be;
+};
-int __ast_register_storage(const struct ast_storage *e, struct ast_module *mod);
+int __ast_register_storage(const struct ast_storage_be *e, struct ast_module *mod);
#define ast_register_storage(e) __ast_register_storage(e, ast_module_info->self)
int ast_unregister_storage(const char *name);
int ast_storage_engine_init(void);
-int se_get(struct ast_storage *e);
-int se_put(struct ast_storage *e);
-int se_delete(struct ast_storage *e);
-int se_count(struct ast_storage *e);
-int se_parseoptions(struct ast_storage *e, const char *var, const char *value);
+/*! \brief Retrieves an instance of a storage method
+ * \param storage_type Name of the backend
+ * \param root Backend specific parameter. Generally is a hostname or path.
+ * \param auth Backend specific parameter. Generally is the user in an authentication scheme.
+ * \param passwd Backend specific parameter. Generally is the password in an authentication scheme.
+ * \param flags Backend specific parameter
+ */
+struct ast_storage *ast_storage_request(const char *storage_type, const char *uri);
+
+/*! \brief Releases a storage instance created with ast_storage_request
+ */
+int ast_storage_release(struct ast_storage *st);
+
+/*! \brief Retrieves a file from the storage medium
+ * \param st Storage instance
+ * \param objectname Logical name of the file
+ * \param localfile Buffer in which to place the name of the resulting temporary file.
+ * \param localfilesize Length of the above buffer
+ */
+int ast_storage_get(struct ast_storage *st, const char *objectname, char *localfile, size_t localfilesize);
+
+/*! \brief Stores a file into the storage medium
+ * \param st Storage instance
+ * \param objectname Logical name of the file
+ * \param localfile Location of the file to store
+ */
+int ast_storage_put(struct ast_storage *st, const char *objectname, const char *localfile);
+
+/*! \brief Removes a file from the storage medium
+ * \param st Storage instance
+ * \param objectname Logical name of the file
+ */
+int ast_storage_delete(struct ast_storage *st, const char *objectname);
+
+/*! \brief Retrieves a count of objects at a particular path
+ * \param st Storage instance
+ * \param objectname Logical name of the file
+ */
+int ast_storage_count(struct ast_storage *st, const char *objectname);
+
+/*! \brief Specify a backend specific parameter
+ * \param st Storage instance
+ * \param var Parameter name
+ * \param value Parameter value
+ */
+int ast_storage_parseoptions(struct ast_storage *st, const char *var, const char *value);
#if defined(__cplusplus) || defined(c_plusplus)
}
Modified: team/group/ast_storage/main/storage.c
URL: http://svn.digium.com/view/asterisk/team/group/ast_storage/main/storage.c?view=diff&rev=48122&r1=48121&r2=48122
==============================================================================
--- team/group/ast_storage/main/storage.c (original)
+++ team/group/ast_storage/main/storage.c Wed Nov 29 19:29:34 2006
@@ -33,11 +33,11 @@
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
-static AST_LIST_HEAD_STATIC(storage_engines, ast_storage);
+static AST_LIST_HEAD_STATIC(storage_engines, ast_storage_be);
-int __ast_register_storage(const struct ast_storage *e, struct ast_module *mod)
+int __ast_register_storage(const struct ast_storage_be *e, struct ast_module *mod)
{
- struct ast_storage *tmp;
+ struct ast_storage_be *tmp;
if (AST_LIST_LOCK(&storage_engines)) {
ast_log(LOG_WARNING, "Unable to lock storage engine list\n");
@@ -69,7 +69,7 @@
int ast_unregister_storage(const char *name)
{
- struct ast_storage *tmp;
+ struct ast_storage_be *tmp;
int res = -1;
if (AST_LIST_LOCK(&storage_engines)) {
@@ -95,29 +95,50 @@
return res;
}
-int ast_se_get(struct ast_storage *e) {
- return e->get(0);
+struct ast_storage *ast_storage_request(const char *storage_type, const char *uri)
+{
+ struct ast_storage_be *e;
+
+ AST_LIST_TRAVERSE(&storage_engines, e, list) {
+ if (!strcasecmp(e->name, storage_type))
+ return e->new(uri);
+ }
+ return NULL;
}
-int ast_se_put(struct ast_storage *e) {
- return e->put(0);
+int ast_storage_release(struct ast_storage *st)
+{
+ return st && st->be->free ? st->be->free(st) : -1;
}
-int ast_se_delete(struct ast_storage *e) {
- return e->delete(0);
+int ast_storage_get(struct ast_storage *st, const char *objectname, char *localfile, size_t localfilesize)
+{
+ return st->be->get ? st->be->get(st, objectname, localfile, localfilesize) : -1;
}
-int ast_se_count(struct ast_storage *e) {
- return e->count(0);
+int ast_storage_put(struct ast_storage *st, const char *objectname, const char *localfile)
+{
+ return st->be->put ? st->be->put(st, objectname, localfile) : -1;
}
-int ast_se_parseoptions(struct ast_storage *e, const char *var, const char *value) {
- return e->parseoptions(var, value);
+int ast_storage_delete(struct ast_storage *st, const char *objectname)
+{
+ return st->be->delete ? st->be->delete(st, objectname) : -1;
+}
+
+int ast_storage_count(struct ast_storage *st, const char *objectpath)
+{
+ return st->be->count ? st->be->count(st, objectpath) : -1;
+}
+
+int ast_storage_parseoptions(struct ast_storage *st, const char *var, const char *value)
+{
+ return st->be->parseoptions ? st->be->parseoptions(st, var, value) : -1;
}
static int show_storage_engines(int fd, int argc, char *argv[])
{
- struct ast_storage *e;
+ struct ast_storage_be *e;
int count_se = 0;
if (argc != 4)
@@ -153,3 +174,4 @@
ast_cli_register_multiple(cli_storage, sizeof(cli_storage) / sizeof(struct ast_cli_entry));
return 0;
}
+
Modified: team/group/ast_storage/res/res_storage_file.c
URL: http://svn.digium.com/view/asterisk/team/group/ast_storage/res/res_storage_file.c?view=diff&rev=48122&r1=48121&r2=48122
==============================================================================
--- team/group/ast_storage/res/res_storage_file.c (original)
+++ team/group/ast_storage/res/res_storage_file.c Wed Nov 29 19:29:34 2006
@@ -29,30 +29,146 @@
#include "asterisk/storage.h"
#include "asterisk/module.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
-static int se_get_file(int blah) {
+struct ast_storage_file {
+ const struct ast_storage_be *be;
+ char rootpath[128];
+};
+
+static const struct ast_storage_be file_se;
+
+static struct ast_storage *se_new_file(const char *uri)
+{
+ struct ast_storage_file *fst = malloc(sizeof(struct ast_storage_file));
+ ast_copy_string(fst->rootpath, uri + 6, sizeof(fst->rootpath));
+ fst->be = &file_se;
+ return ((struct ast_storage *)fst);
+}
+
+static int se_free_file(struct ast_storage *st)
+{
+ free(st);
return 0;
}
-static int se_put_file(int blah) {
+static int se_get_file(struct ast_storage *st, const char *objectname, char *localfile, size_t localfilesize)
+{
+ struct ast_storage_file *fst = (struct ast_storage_file *)st;
+ char dirname[256], *dirnameptr;
+ DIR *dir;
+ struct dirent *dirent;
+ int res = -1;
+
+ snprintf(localfile, localfilesize, "%s/%s", fst->rootpath, objectname);
+
+ /* Ensure the file exists. */
+ /* NOTE: while this is similar to a function already in main/file.c,
+ * this has to remain coded here, because the version in file.c will
+ * eventually depend upon this one. */
+ ast_copy_string(dirname, localfile, sizeof(dirname));
+ dirnameptr = strrchr(dirname, '/');
+ if (dirnameptr)
+ *dirnameptr++ = '\0';
+ else
+ return -1;
+ dir = opendir(dirname);
+ while ((dirent = readdir(dir))) {
+ if (!strcmp(dirent->d_name, dirnameptr)) {
+ res = 0;
+ break;
+ }
+ }
+ closedir(dir);
+
+ return res;
+}
+
+static int se_put_file(struct ast_storage *st, const char *objectname, const char *localfile)
+{
+ struct ast_storage_file *fst = (struct ast_storage_file *)st;
+ int ifd;
+ int ofd;
+ int res = 0;
+ int len;
+ char dest[256];
+ char buf[4096];
+
+ snprintf(dest, sizeof(dest), "%s/%s", fst->rootpath, objectname);
+
+ if ((ifd = open(localfile, O_RDONLY)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", localfile);
+ return -1;
+ }
+ if ((ofd = open(dest, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", dest);
+ close(ifd);
+ return -1;
+ }
+ do {
+ len = read(ifd, buf, sizeof(buf));
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Read failed on %s: %s\n", localfile, strerror(errno));
+ close(ifd);
+ close(ofd);
+ unlink(dest);
+ }
+ if (len) {
+ res = write(ofd, buf, len);
+ if (errno == ENOMEM || errno == ENOSPC || res != len) {
+ ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", dest, res, len, strerror(errno));
+ close(ifd);
+ close(ofd);
+ unlink(dest);
+ }
+ }
+ } while (len);
+ close(ifd);
+ close(ofd);
+ return res;
+}
+
+static int se_delete_file(struct ast_storage *st, const char *objectname)
+{
+ struct ast_storage_file *fst = (struct ast_storage_file *)st;
+ char dest[256];
+ snprintf(dest, sizeof(dest), "%s/%s", fst->rootpath, objectname);
+ return unlink(dest);
+}
+
+static int se_count_file(struct ast_storage *st, const char *objectpath)
+{
+ struct ast_storage_file *fst = (struct ast_storage_file *)st;
+ char dest[256];
+ DIR *dir;
+ struct dirent *dirent;
+ int count = 0;
+ snprintf(dest, sizeof(dest), "%s/%s", fst->rootpath, objectpath);
+ dir = opendir(dest);
+ while ((dirent = readdir(dir))) {
+ /* Probably not exactly correct */
+ if (strncmp(dirent->d_name, ".", 1) != 0)
+ count++;
+ }
+ closedir(dir);
+
return 0;
}
-static int se_delete_file(int blah) {
+static int se_parseoptions_file(struct ast_storage *st, const char *var, const char *value)
+{
return 0;
}
-static int se_count_file(int blah) {
- return 0;
-}
-
-static int se_parseoptions_file(const char *var, const char *value) {
- return 0;
-}
-
-static const struct ast_storage file_se = {
+static const struct ast_storage_be file_se = {
.name = "file",
- .type = AST_STORAGE_FILE,
+ .new = se_new_file,
+ .free = se_free_file,
.get = se_get_file,
.put = se_put_file,
.delete = se_delete_file,
@@ -62,12 +178,12 @@
static int load_module(void)
{
- return ast_register_storage(&file_se);
+ return ast_register_storage(&file_se);
}
static int unload_module(void)
{
- return ast_unregister_storage(file_se.name);
+ return ast_unregister_storage(file_se.name);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Files based storage engine");
Added: team/group/ast_storage/res/res_storage_odbc.c
URL: http://svn.digium.com/view/asterisk/team/group/ast_storage/res/res_storage_odbc.c?view=auto&rev=48122
==============================================================================
--- team/group/ast_storage/res/res_storage_odbc.c (added)
+++ team/group/ast_storage/res/res_storage_odbc.c Wed Nov 29 19:29:34 2006
@@ -1,0 +1,522 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Tilghman Lesher
+ *
+ * Tilghman Lesher <res_storage_odbc__v001 at the-tilghman.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ODBC based storage engine
+ * \author Tilghman Lesher <res_storage_odbc__v001 at the-tilghman.com>
+ * \ingroup res
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/storage.h"
+#include "asterisk/module.h"
+#include "asterisk/res_odbc.h"
+#include "asterisk/app.h"
+#include "asterisk/config.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Number of bytes to transfer when moving a large field */
+#define CHUNKSIZE 65536
+
+struct ast_storage_odbc {
+ const struct ast_storage_be *be;
+ char odbc_class[128];
+ char tablename[128];
+ char pathname[128];
+ struct odbc_obj *conn;
+ SQLHSTMT sth;
+};
+
+static const struct ast_storage_be odbc_se;
+
+static void copy_file(const char *from, const char *to)
+{
+ int ifd;
+ int ofd;
+ int res = 0;
+ int len;
+ char buf[4096];
+
+ if ((ifd = open(from, O_RDONLY)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", from);
+ return;
+ }
+ if ((ofd = open(to, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) {
+ ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", to);
+ close(ifd);
+ return;
+ }
+ do {
+ len = read(ifd, buf, sizeof(buf));
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Read failed on %s: %s\n", from, strerror(errno));
+ close(ifd);
+ close(ofd);
+ unlink(to);
+ }
+ if (len) {
+ res = write(ofd, buf, len);
+ if (errno == ENOMEM || errno == ENOSPC || res != len) {
+ ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", to, res, len, strerror(errno));
+ close(ifd);
+ close(ofd);
+ unlink(to);
+ }
+ }
+ } while (len);
+ close(ifd);
+ close(ofd);
+ return;
+}
+
+static struct ast_storage *se_new_odbc(const char *uri)
+{
+ char tmp[256];
+ struct ast_storage_odbc *ost = ast_calloc(1, sizeof(struct ast_storage_odbc));
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(class);
+ AST_APP_ARG(tablename);
+ AST_APP_ARG(pathname);
+ );
+
+ /* odbc:// */
+ ast_copy_string(tmp, uri + 7, sizeof(tmp));
+ AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
+
+ ost->be = &odbc_se;
+ ast_copy_string(ost->odbc_class, args.class, sizeof(ost->odbc_class));
+ ast_copy_string(ost->tablename, args.tablename, sizeof(ost->tablename));
+ ast_copy_string(ost->pathname, args.pathname, sizeof(ost->pathname));
+ ost->conn = ast_odbc_request_obj(ost->odbc_class, 0);
+
+ if (!ost->conn) {
+ free(ost);
+ return NULL;
+ }
+
+ return ((struct ast_storage *)ost);
+}
+
+static int se_free_odbc(struct ast_storage *st)
+{
+ struct ast_storage_odbc *ost = (struct ast_storage_odbc *)st;
+ if (ost->sth)
+ SQLFreeHandle(SQL_HANDLE_STMT, ost->sth);
+ ast_odbc_release_obj(ost->conn);
+ free(ost);
+ return 0;
+}
+
+static void get_path_file(struct ast_storage_odbc *ost, const char *objectname, char *pathname, size_t pathnamesize, char *filename, size_t filenamesize)
+{
+ char tmp[256], *filename2;
+
+ ast_copy_string(tmp, objectname, sizeof(tmp));
+ if ((filename2 = strrchr(tmp, '/'))) {
+ if (filename2 == tmp) {
+ ast_copy_string(pathname, "/", pathnamesize);
+ *filename2++ = '\0';
+ } else {
+ *filename2++ = '\0';
+
+ /* Absolute or relative path? */
+ if (tmp[0] == '/')
+ ast_copy_string(pathname, tmp, sizeof(pathname));
+ else
+ snprintf(pathname, sizeof(pathname), "%s/%s", ost->pathname, tmp);
+ }
+ } else {
+ ast_copy_string(pathname, ost->pathname, sizeof(pathname));
+ filename2 = tmp;
+ }
+ ast_copy_string(filename, filename2, filenamesize);
+}
+
+static int se_get_odbc(struct ast_storage *st, const char *objectname, char *localfile, size_t localfilesize)
+{
+ struct ast_storage_odbc *ost = (struct ast_storage_odbc *)st;
+ int res = -1, tempfd, x, gotten = 0;
+ char sql[128];
+ char pathname[256], filename[256], reallocalfile[256];
+ char fileformat[10], rowdata[256], coltitle[128];
+ SQLHSTMT stmt;
+ SQLSMALLINT colcount, collen, datatype;
+ FILE *txt;
+
+ ast_copy_string(localfile, "/var/tmp/XXXXXX", localfilesize);
+ tempfd = mkstemp(localfile);
+ if (tempfd == -1)
+ return -1;
+
+ snprintf(reallocalfile, sizeof(reallocalfile), "%s.txt", localfile);
+ txt = fopen(reallocalfile, "w");
+ if (!txt) {
+ close(tempfd);
+ unlink(localfile);
+ return -1;
+ }
+
+ fprintf(txt, "[info]\n");
+
+ get_path_file(ost, objectname, pathname, sizeof(pathname), filename, sizeof(filename));
+
+ snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE pathname=? AND filename=?", ost->tablename);
+
+ res = SQLAllocHandle(SQL_HANDLE_STMT, ost->conn->con, &stmt);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+ fclose(txt);
+ close(tempfd);
+ unlink(localfile);
+ return -1;
+ }
+
+ res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
+ goto endget;
+ }
+
+ SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(pathname), 0, (void *)pathname, 0, NULL);
+ SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(filename), 0, (void *)filename, 0, NULL);
+
+ res = ast_odbc_smart_execute(ost->conn, stmt);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n", sql);
+ goto endget;
+ }
+
+ while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n", sql);
+ goto endget;
+ }
+
+ res = SQLNumResultCols(stmt, &colcount);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n", sql);
+ goto endget;
+ }
+
+ fileformat[0] = '\0';
+ for (x = 0; x < colcount; x++) {
+ int fd = -1;
+ SQLUINTEGER colsize;
+ SQLSMALLINT decimaldigits, nullable;
+ rowdata[0] = '\0';
+ collen = sizeof(coltitle);
+ res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
+ &datatype, &colsize, &decimaldigits, &nullable);
+
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n", sql);
+ goto endget;
+ }
+
+ if (!strcasecmp(coltitle, "recording")) {
+ int fdlen;
+ off_t chunk_offset;
+ void *fdm = NULL;
+ SQLINTEGER colsize2;
+
+ if (!ast_strlen_zero(fileformat)) {
+ /* We have a file format, just go ahead and create the destination */
+ snprintf(reallocalfile, sizeof(reallocalfile), "%s.%s", localfile, fileformat);
+ fd = open(reallocalfile, O_CREAT | O_WRONLY | O_EXCL);
+ if (fd == -1) {
+ ast_log(LOG_ERROR, "Unable to write recording: %s (%d)\n", strerror(errno), errno);
+ goto endget;
+ }
+ } else {
+ fd = tempfd;
+ truncate(localfile, 0);
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize2);
+ fdlen = colsize2;
+ if (fd > -1) {
+ char tmp[1]="";
+ lseek(fd, fdlen - 1, SEEK_SET);
+ if (write(fd, tmp, 1) != 1) {
+ if (fd != tempfd)
+ close(fd);
+ fd = -1;
+ continue;
+ }
+ }
+
+ /* Grab data in 64k chunks */
+ for (chunk_offset = 0; chunk_offset < fdlen; chunk_offset += CHUNKSIZE) {
+ /* Add one to the CHUNKSIZE, because ODBC always adds a terminating NULL */
+ if ((fdm = mmap(NULL, CHUNKSIZE + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, chunk_offset)) == (void *)-1) {
+ ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
+ goto endget;
+ } else {
+ res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE + 1, NULL);
+ munmap(fdm, 0);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+ unlink(reallocalfile);
+ goto endget;
+ }
+ }
+ }
+ /* Ensure the file is exactly the right length */
+ truncate(reallocalfile, fdlen);
+ } else {
+ res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+ goto endget;
+ }
+ if (!strcasecmp(coltitle, "fileformat")) {
+ /* Is there a recording waiting for us? */
+ if (lseek(tempfd, 0, SEEK_CUR) > 0) {
+ snprintf(reallocalfile, sizeof(reallocalfile), "%s.%s", localfile, rowdata);
+ copy_file(localfile, reallocalfile);
+ lseek(tempfd, 0, SEEK_SET);
+ truncate(localfile, 0);
+ } else
+ ast_copy_string(fileformat, rowdata, sizeof(fileformat));
+ } else if (strcasecmp(coltitle, "filename") && strcasecmp(coltitle, "pathname") && !ast_strlen_zero(rowdata) && !gotten)
+ fprintf(txt, "%s=%s\n", coltitle, rowdata);
+ }
+ if (fd > -1 && fd != tempfd)
+ close(fd);
+ }
+ gotten = 1;
+ }
+ res = 0;
+endget:
+ SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+ fclose(txt);
+ close(tempfd);
+ /* This is just the temp marker */
+ unlink(localfile);
+
+ return res ? -1 : 0;
+}
+
+static int se_put_odbc(struct ast_storage *st, const char *objectname, const char *localfile)
+{
+ struct ast_storage_odbc *ost = (struct ast_storage_odbc *)st;
+ int res = -1, x;
+ struct ast_config *cfg;
+ struct ast_variable *cfgvar, *var;
+ char sql[768], sqlfields[256] = ") VALUES (?,?,?,?";
+ char needlong[10] = "";
+ char pathname[256], *localfile2, reallocalfile[256];
+ char *fileformat;
+ SQLHSTMT stmt = NULL;
+ DIR *dir;
+ struct dirent *dirent;
+
+ snprintf(reallocalfile, sizeof(reallocalfile), "%s.txt", localfile);
+ cfg = ast_config_load(reallocalfile);
+ cfgvar = ast_variable_browse(cfg, "info");
+
+ snprintf(sql, sizeof(sql), "INSERT INTO %s (pathname,filename,recording,fileformat", ost->tablename);
+
+ for (var = cfgvar; var; var = var->next) {
+ strncat(sql, var->name, sizeof(sql) - 1);
+ strncat(sql, ",", sizeof(sql) - 1);
+ strncat(sqlfields, ",?", sizeof(sqlfields) - 1);
+ }
+ strncat(sql, sqlfields, sizeof(sql) - 1);
+ strncat(sql, ")", sizeof(sql) - 1);
+
+ if ((strlen(sqlfields) == sizeof(sqlfields) - 1) || (strlen(sql) == sizeof(sql) - 1)) {
+ ast_log(LOG_ERROR, "Data overflow. Increase SQL buffer size in se_put_odbc() (%d/%d)\n", strlen(sqlfields), strlen(sql));
+ ast_config_destroy(cfg);
+ return -1;
+ }
+
+ SQLGetInfo(ost->conn->con, SQL_NEED_LONG_DATA_LEN, (SQLPOINTER)&needlong, sizeof(needlong), NULL);
+
+ ast_copy_string(pathname, localfile, sizeof(pathname));
+ if ((localfile2 = strrchr(pathname, '/')))
+ *localfile2++ = '\0';
+ else {
+ ast_log(LOG_ERROR, "Specified file is not absolute path: %s\n", localfile);
+ ast_config_destroy(cfg);
+ return -1;
+ }
+
+ dir = opendir(pathname);
+ if (!dir) {
+ ast_log(LOG_ERROR, "Could not read directory %s: %s (%d)\n", pathname, strerror(errno), errno);
+ ast_config_destroy(cfg);
+ return -1;
+ }
+
+ while ((dirent = readdir(dir))) {
+ int fd = -1;
+ SQLINTEGER filesize;
+ off_t offset;
+
+ if (strcmp(dirent->d_name, localfile2) != 0)
+ continue;
+
+ if (!(fileformat = strrchr(dirent->d_name, '.')))
+ continue;
+ fileformat++;
+
+ snprintf(reallocalfile, sizeof(reallocalfile), "%s.%s", pathname, dirent->d_name);
+ fd = open(reallocalfile, O_RDONLY);
+
+ if (fd == -1) {
+ ast_log(LOG_WARNING, "Could not open file %s: %s (%d)\n", reallocalfile, strerror(errno), errno);
+ continue;
+ }
+
+ res = SQLAllocHandle(SQL_HANDLE_STMT, ost->conn->con, &stmt);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+ ast_config_destroy(cfg);
+ return -1;
+ }
+
+ res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
+ goto endput;
+ }
+
+ filesize = (SQLINTEGER)lseek(fd, 0, SEEK_END);
+
+ SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(pathname), 0, (void *)pathname, 0, NULL);
+ SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(localfile2), 0, (void *)localfile2, 0, NULL);
+ if (needlong[0] == 'Y') {
+ SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER)3, 0, &filesize);
+ } else
+ SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER)3, 0, NULL);
+ SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(fileformat), 0, (void *)fileformat, 0, NULL);
+ for (var = cfgvar, x = 5; var; var = var->next, x++) {
+ SQLBindParameter(stmt, x, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(var->value), 0, (void *)var->value, 0, NULL);
+ }
+
+ res = SQLExecute(stmt);
+
+ if (res == SQL_NEED_DATA) {
+ for (offset = 0; offset < filesize; offset += CHUNKSIZE) {
+ void *fdm = mmap(NULL, CHUNKSIZE + 1, PROT_READ, MAP_SHARED, fd, offset);
+ if (fdm == (void *)-1) {
+ ast_log(LOG_ERROR, "Unable to mmap file %s: %s (%d)\n", reallocalfile, strerror(errno), errno);
+ goto endput;
+ }
+ SQLPutData(stmt, fdm, CHUNKSIZE);
+ munmap(fdm, 0);
+ }
+ } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n", sql);
+ goto endput;
+ }
+
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ stmt = NULL;
+ }
+ res = 0;
+endput:
+ if (stmt)
+ SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+ ast_config_destroy(cfg);
+ return res ? -1 : 0;
+}
+
+static int se_delete_odbc(struct ast_storage *st, const char *objectname)
+{
+ char pathname[256], filename[256], sql[256];
+ struct ast_storage_odbc *ost = (struct ast_storage_odbc *)st;
+ int res;
+ SQLHSTMT sth;
+
+ get_path_file(ost, objectname, pathname, sizeof(pathname), filename, sizeof(filename));
+
+ snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE pathname=? AND filename=?", ost->tablename);
+
+ res = SQLAllocHandle(SQL_HANDLE_STMT, ost->conn->con, &sth);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+ return -1;
+ }
+
+ res = SQLPrepare(sth, (unsigned char *)sql, SQL_NTS);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
+ goto enddel;
+ }
+
+ SQLBindParameter(sth, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(pathname), 0, (void *)pathname, 0, NULL);
+ SQLBindParameter(sth, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(filename), 0, (void *)filename, 0, NULL);
+
+ res = ast_odbc_smart_execute(ost->conn, sth);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n", sql);
+ goto enddel;
+ }
+ res = 0;
+enddel:
+ SQLFreeHandle(SQL_HANDLE_STMT, sth);
+
+ return res ? -1 : 0;
+}
+
+static int se_count_odbc(struct ast_storage *st, const char *objectpath)
+{
+ return -1;
+}
+
+static int se_parseoptions_odbc(struct ast_storage *st, const char *var, const char *value)
+{
+ return 0;
+}
+
+static const struct ast_storage_be odbc_se = {
+ .name = "odbc",
+ .new = se_new_odbc,
+ .free = se_free_odbc,
+ .get = se_get_odbc,
+ .put = se_put_odbc,
+ .delete = se_delete_odbc,
+ .count = se_count_odbc,
+ .parseoptions = se_parseoptions_odbc,
+};
+
+static int load_module(void)
+{
+ return ast_register_storage(&odbc_se);
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_storage(odbc_se.name);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ODBC based storage engine");
Propchange: team/group/ast_storage/res/res_storage_odbc.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/group/ast_storage/res/res_storage_odbc.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/group/ast_storage/res/res_storage_odbc.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list