app_voicemail: Cleanup ODBC connection handling

The primary focus of this patch is adding a missing call to
ast_odbc_release_obj(), but is also a general cleanup of the ODBC
related code in app_voicemail.

ASTERISK-27093 #close

Change-Id: I8e285142eaeb3146b4287a928276b70db76c902b
This commit is contained in:
Sean Bright 2017-06-29 14:58:35 -04:00
parent b62a3f0a67
commit 950b39a4f5
1 changed files with 379 additions and 390 deletions

View File

@ -3779,12 +3779,12 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
SQLHSTMT stmt;
res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
return NULL;
}
res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return NULL;
@ -3826,14 +3826,14 @@ static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
* \brief Retrieves a file from an ODBC data store.
* \param dir the path to the file to be retrieved.
* \param msgnum the message number, such as within a mailbox folder.
*
*
* This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end.
* The purpose is to get the message from the database store to the local file system, so that the message may be played, or the information file may be read.
*
* The file is looked up by invoking a SQL on the odbc_table (default 'voicemessages') using the dir and msgnum input parameters.
* The output is the message information file with the name msgnum and the extension .txt
* and the message file with the extension of its format, in the directory with base file name of the msgnum.
*
*
* \return 0 on success, -1 on error.
*/
static int retrieve_file(char *dir, int msgnum)
@ -3846,7 +3846,7 @@ static int retrieve_file(char *dir, int msgnum)
SQLSMALLINT colcount = 0;
SQLHSTMT stmt;
char sql[PATH_MAX];
char fmt[80]="";
char fmt[80] = "";
char *c;
char coltitle[256];
SQLSMALLINT collen;
@ -3862,144 +3862,139 @@ static int retrieve_file(char *dir, int msgnum)
char msgnums[80];
char *argv[] = { dir, msgnums };
struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
struct odbc_obj *obj;
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
ast_copy_string(fmt, vmfmts, sizeof(fmt));
c = strchr(fmt, '|');
if (c)
*c = '\0';
if (!strcasecmp(fmt, "wav49"))
strcpy(fmt, "WAV");
snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
if (msgnum > -1)
make_file(fn, sizeof(fn), dir, msgnum);
else
ast_copy_string(fn, dir, sizeof(fn));
/* Create the information file */
snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
if (!(f = fopen(full_fn, "w+"))) {
ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
goto yuck;
}
snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLFetch(stmt);
if (res == SQL_NO_DATA) {
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
if (fd < 0) {
ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLNumResultCols(stmt, &colcount);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (f)
fprintf(f, "[message]\n");
for (x = 0; x < colcount; x++) {
rowdata[0] = '\0';
colsize = 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(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (!strcasecmp(coltitle, "recording")) {
off_t offset;
res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
fdlen = colsize2;
if (fd > -1) {
char tmp[1]="";
lseek(fd, fdlen - 1, SEEK_SET);
if (write(fd, tmp, 1) != 1) {
close(fd);
fd = -1;
continue;
}
/* Read out in small chunks */
for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
} else {
res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
munmap(fdm, CHUNKSIZE);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
unlink(full_fn);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
}
}
if (truncate(full_fn, fdlen) < 0) {
ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
}
}
} else {
res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res == SQL_NULL_DATA) && (!strcasecmp(coltitle, "msg_id"))) {
char msg_id[MSG_ID_LEN];
generate_msg_id(msg_id);
snprintf(rowdata, sizeof(rowdata), "%s", msg_id);
odbc_update_msg_id(dir, msgnum, msg_id);
} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
fprintf(f, "%s=%s\n", coltitle, rowdata);
}
}
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
} else
obj = ast_odbc_request_obj(odbc_database, 0);
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
yuck:
return -1;
}
ast_copy_string(fmt, vmfmts, sizeof(fmt));
c = strchr(fmt, '|');
if (c)
*c = '\0';
if (!strcasecmp(fmt, "wav49"))
strcpy(fmt, "WAV");
snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
if (msgnum > -1)
make_file(fn, sizeof(fn), dir, msgnum);
else
ast_copy_string(fn, dir, sizeof(fn));
/* Create the information file */
snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
if (!(f = fopen(full_fn, "w+"))) {
ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
goto bail;
}
snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto bail;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
if (res != SQL_NO_DATA) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
}
goto bail_with_handle;
}
fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
if (fd < 0) {
ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
goto bail_with_handle;
}
res = SQLNumResultCols(stmt, &colcount);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
fprintf(f, "[message]\n");
for (x = 0; x < colcount; x++) {
rowdata[0] = '\0';
colsize = 0;
collen = sizeof(coltitle);
res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
&datatype, &colsize, &decimaldigits, &nullable);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
if (!strcasecmp(coltitle, "recording")) {
off_t offset;
res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
fdlen = colsize2;
if (fd > -1) {
char tmp[1] = "";
lseek(fd, fdlen - 1, SEEK_SET);
if (write(fd, tmp, 1) != 1) {
close(fd);
fd = -1;
continue;
}
/* Read out in small chunks */
for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
goto bail_with_handle;
}
res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
munmap(fdm, CHUNKSIZE);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
unlink(full_fn);
goto bail_with_handle;
}
}
if (truncate(full_fn, fdlen) < 0) {
ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
}
}
} else {
res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (res == SQL_NULL_DATA && !strcasecmp(coltitle, "msg_id")) {
char msg_id[MSG_ID_LEN];
generate_msg_id(msg_id);
snprintf(rowdata, sizeof(rowdata), "%s", msg_id);
odbc_update_msg_id(dir, msgnum, msg_id);
} else if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
goto bail_with_handle;
}
if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir")) {
fprintf(f, "%s=%s\n", coltitle, rowdata);
}
}
}
bail_with_handle:
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
bail:
if (f)
fclose(f);
if (fd > -1)
close(fd);
ast_odbc_release_obj(obj);
return x - 1;
}
/*!
* \brief Determines the highest message number in use for a given user and mailbox folder.
* \param vmu
* \param vmu
* \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause.
*
* This method is used when mailboxes are stored in an ODBC back end.
@ -4010,58 +4005,61 @@ yuck:
*/
static int last_message_index(struct ast_vm_user *vmu, char *dir)
{
int x = 0;
int x = -1;
int res;
SQLHSTMT stmt;
char sql[PATH_MAX];
char rowdata[20];
char *argv[] = { dir };
struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
struct odbc_obj *obj;
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
if (res == SQL_NO_DATA) {
ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
} else {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
}
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (sscanf(rowdata, "%30d", &x) != 1)
ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
return x;
} else
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
yuck:
return x - 1;
return -1;
}
snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto bail;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
if (res == SQL_NO_DATA) {
ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
} else {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
}
goto bail_with_handle;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
if (sscanf(rowdata, "%30d", &x) != 1) {
ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
}
bail_with_handle:
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
bail:
ast_odbc_release_obj(obj);
return x;
}
/*!
* \brief Determines if the specified message exists.
* \param dir the folder the mailbox folder to look for messages.
* \param dir the folder the mailbox folder to look for messages.
* \param msgnum the message index to query for.
*
* This method is used when mailboxes are stored in an ODBC back end.
@ -4078,39 +4076,43 @@ static int message_exists(char *dir, int msgnum)
char msgnums[20];
char *argv[] = { dir, msgnums };
struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
struct odbc_obj *obj;
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (sscanf(rowdata, "%30d", &x) != 1)
ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
} else
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
yuck:
return 0;
}
snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto bail;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
if (sscanf(rowdata, "%30d", &x) != 1) {
ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
}
bail_with_handle:
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
bail:
ast_odbc_release_obj(obj);
return x;
}
@ -4125,48 +4127,50 @@ yuck:
*/
static int count_messages(struct ast_vm_user *vmu, char *dir)
{
int x = 0;
int x = -1;
int res;
SQLHSTMT stmt;
char sql[PATH_MAX];
char rowdata[20];
char *argv[] = { dir };
struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
struct odbc_obj *obj;
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
goto yuck;
}
if (sscanf(rowdata, "%30d", &x) != 1)
ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
return x;
} else
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
yuck:
return x - 1;
obj = ast_odbc_request_obj(odbc_database, 0);
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return -1;
}
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto bail;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
if (sscanf(rowdata, "%30d", &x) != 1) {
ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
}
bail_with_handle:
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
bail:
ast_odbc_release_obj(obj);
return x;
}
/*!
@ -4176,7 +4180,7 @@ yuck:
*
* This method is used when mailboxes are stored in an ODBC back end.
* The specified message is directly deleted from the database 'voicemessages' table.
*
*
* \return the value greater than zero on success to indicate the number of messages, less than zero on error.
*/
static void delete_file(const char *sdir, int smsg)
@ -4188,21 +4192,25 @@ static void delete_file(const char *sdir, int smsg)
struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
struct odbc_obj *obj;
obj = ast_odbc_request_obj(odbc_database, 0);
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return;
}
argv[0] = ast_strdupa(sdir);
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt)
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
else
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
} else
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return;
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
} else {
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
ast_odbc_release_obj(obj);
return;
}
/*!
@ -4230,19 +4238,22 @@ static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailbox
generate_msg_id(msg_id);
delete_file(ddir, dmsg);
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt)
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
else
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
} else
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return;
return;
}
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt)
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
else
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
return;
}
struct insert_data {
@ -4271,9 +4282,8 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
SQLHSTMT stmt;
res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return NULL;
}
@ -4293,7 +4303,7 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
}
res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return NULL;
@ -4310,7 +4320,7 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
* \param msgnum the message index for the message to be stored.
*
* This method is used when mailboxes are stored in an ODBC back end.
* The message sound file and information file is looked up on the file system.
* The message sound file and information file is looked up on the file system.
* A SQL query is invoked to store the message into the (MySQL) database.
*
* \return the zero on success -1 on error.
@ -4335,7 +4345,9 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail
struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
delete_file(dir, msgnum);
if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
obj = ast_odbc_request_obj(odbc_database, 0);
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return -1;
}
@ -4398,25 +4410,25 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail
ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
res = -1;
break;
}
}
idata.data = fdm;
idata.datalen = idata.indlen = fdlen;
if (!ast_strlen_zero(idata.category))
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
if (!ast_strlen_zero(idata.category))
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
else
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
} else {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
res = -1;
}
} while (0);
if (obj) {
ast_odbc_release_obj(obj);
}
ast_odbc_release_obj(obj);
if (valid_config(cfg))
ast_config_destroy(cfg);
if (fdm != MAP_FAILED)
@ -4450,20 +4462,23 @@ static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxco
struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
delete_file(ddir, dmsg);
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt)
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
else
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
} else
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return;
return;
}
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt)
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
else
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
ast_odbc_release_obj(obj);
return;
}
/*!
@ -5663,18 +5678,49 @@ static void free_zone(struct vm_zone *z)
}
#ifdef ODBC_STORAGE
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
static int count_messages_in_folder(struct odbc_obj *odbc, const char *context, const char *mailbox, const char *folder, int *messages)
{
int x = -1;
int res;
SQLHSTMT stmt = NULL;
char sql[PATH_MAX];
char rowdata[20];
char tmp[PATH_MAX] = "";
struct odbc_obj *obj = NULL;
char *context;
SQLHSTMT stmt = NULL;
struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
if (!messages) {
return 0;
}
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
if (!(stmt = ast_odbc_prepare_and_execute(odbc, generic_prepare, &gps))) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
return 1;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return 1;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (!SQL_SUCCEEDED(res)) {
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return 1;
}
*messages = atoi(rowdata);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return 0;
}
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
{
char tmp[PATH_MAX] = "";
struct odbc_obj *obj;
char *context;
if (newmsgs)
*newmsgs = 0;
if (oldmsgs)
@ -5715,87 +5761,28 @@ static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *
} else
context = "default";
if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
do {
if (newmsgs) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
break;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
break;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
break;
}
*newmsgs = atoi(rowdata);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
}
if (oldmsgs) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
break;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
break;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
break;
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
*oldmsgs = atoi(rowdata);
}
if (urgentmsgs) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
break;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
break;
}
res = SQLGetData(stmt, 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);
break;
}
*urgentmsgs = atoi(rowdata);
}
x = 0;
} while (0);
} else {
obj = ast_odbc_request_obj(odbc_database, 0);
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return -1;
}
if (stmt) {
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
if (count_messages_in_folder(obj, context, tmp, "INBOX", newmsgs)
|| count_messages_in_folder(obj, context, tmp, "Old", oldmsgs)
|| count_messages_in_folder(obj, context, tmp, "Urgent", urgentmsgs)) {
ast_log(AST_LOG_WARNING, "Failed to obtain message count for mailbox %s@%s\n",
tmp, context);
}
if (obj) {
ast_odbc_release_obj(obj);
}
return x;
ast_odbc_release_obj(obj);
return 0;
}
/*!
* \brief Gets the number of messages that exist in a mailbox folder.
* \param mailbox_id
* \param folder
*
*
* This method is used when ODBC backend is used.
* \return The number of messages in this mailbox folder (zero or more).
*/
@ -5822,37 +5809,39 @@ static int messagecount(const char *mailbox_id, const char *folder)
}
obj = ast_odbc_request_obj(odbc_database, 0);
if (obj) {
if (!strcmp(folder, "INBOX")) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
} else {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
}
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto yuck;
}
res = SQLFetch(stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
goto yuck;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
goto yuck;
}
nummsgs = atoi(rowdata);
SQLFreeHandle (SQL_HANDLE_STMT, stmt);
} else
if (!obj) {
ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
return 0;
}
yuck:
if (obj)
ast_odbc_release_obj(obj);
if (!strcmp(folder, "INBOX")) {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
} else {
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
}
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
goto bail;
}
res = SQLFetch(stmt);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
if (!SQL_SUCCEEDED(res)) {
ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
goto bail_with_handle;
}
nummsgs = atoi(rowdata);
bail_with_handle:
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
bail:
ast_odbc_release_obj(obj);
return nummsgs;
}