Skip to content
Snippets Groups Projects
app_voicemail.c 258 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	struct odbc_obj *obj;
    	obj = odbc_request_obj(odbc_database, 0);
    
    		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));
    
    		snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
    		f = fopen(full_fn, "w+");
    		snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    		else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    		fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
    
    		if (fd < 0) {
    			ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		res = SQLNumResultCols(stmt, &colcount);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {	
    			ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		if (f) 
    			fprintf(f, "[message]\n");
    		for (x=0;x<colcount;x++) {
    			rowdata[0] = '\0';
    			collen = sizeof(coltitle);
    			res = SQLDescribeCol(stmt, x + 1, 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\n", sql);
    
    				SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			if (!strcasecmp(coltitle, "recording")) {
    				res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize);
    				fdlen = colsize;
    				if (fd > -1) {
    					char tmp[1]="";
    					lseek(fd, fdlen - 1, SEEK_SET);
    					if (write(fd, tmp, 1) != 1) {
    						close(fd);
    						fd = -1;
    
    					if (fd > -1)
    						fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    				}
    				if (fdm) {
    					memset(fdm, 0, fdlen);
    					res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize);
    
    					if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    						ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
    						SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			} 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);
    					SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    					goto yuck;
    				}
    				if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
    					fprintf(f, "%s=%s\n", coltitle, rowdata);
    
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:	
    	if (f)
    		fclose(f);
    	if (fdm)
    		munmap(fdm, fdlen);
    	if (fd > -1)
    		close(fd);
    	return x - 1;
    }
    
    static int remove_file(char *dir, int msgnum)
    {
    
    	
    	if (msgnum > -1) {
    		snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
    		make_file(fn, sizeof(fn), dir, msgnum);
    	} else
    
    		ast_copy_string(fn, dir, sizeof(fn));
    
    	ast_filedelete(fn, NULL);	
    	snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
    	unlink(full_fn);
    	return 0;
    }
    
    
    static int last_message_index(struct ast_vm_user *vmu, char *dir)
    
    {
    	int x = 0;
    	int res;
    	SQLHSTMT stmt;
    	char sql[256];
    	char rowdata[20];
    	
    
    	struct odbc_obj *obj;
    	obj = odbc_request_obj(odbc_database, 0);
    
    	if (obj) {
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		res = SQLFetch(stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(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(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			ast_log(LOG_WARNING, "Failed to read message count!\n");
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:	
    	return x - 1;
    }
    
    static int message_exists(char *dir, int msgnum)
    {
    	int x = 0;
    	int res;
    	SQLHSTMT stmt;
    	char sql[256];
    	char rowdata[20];
    
    	struct odbc_obj *obj;
    	obj = odbc_request_obj(odbc_database, 0);
    
    	if (obj) {
    		snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		res = SQLFetch(stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(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(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			ast_log(LOG_WARNING, "Failed to read message count!\n");
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:	
    	return x;
    }
    
    
    static int count_messages(struct ast_vm_user *vmu, char *dir)
    
    	return last_message_index(vmu, dir) + 1;
    
    static void delete_file(char *sdir, int smsg)
    {
    	int res;
    	SQLHSTMT stmt;
    	char sql[256];
    
    	struct odbc_obj *obj;
    	obj = odbc_request_obj(odbc_database, 0);
    
    	if (obj) {
    		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:
    	return;	
    }
    
    
    static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
    
    
    	delete_file(ddir, dmsg);
    
    	if (obj) {
    		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
    		snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table); 
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
    
    		SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dmailboxuser), 0, (void *)dmailboxuser, 0, NULL);
    		SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dmailboxcontext), 0, (void *)dmailboxcontext, 0, NULL);
    		SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
    		SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:
    	return;	
    }
    
    
    static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
    
    {
    	int x = 0;
    	int res;
    	int fd = -1;
    	void *fdm=NULL;
    	size_t fdlen = -1;
    	SQLHSTMT stmt;
    	SQLINTEGER len;
    	char sql[256];
    
    	char fmt[80]="";
    	char *c;
    	char *context="", *macrocontext="", *callerid="", *origtime="", *duration="";
    
    	char *category = "";
    
    	struct ast_config *cfg=NULL;
    
    
    	delete_file(dir, msgnum);
    
    		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));
    
    		snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
    
    		cfg = ast_config_load(full_fn);
    
    		snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
    		fd = open(full_fn, O_RDWR);
    		if (fd < 0) {
    			ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
    
    			goto yuck;
    		}
    		if (cfg) {
    			context = ast_variable_retrieve(cfg, "message", "context");
    			if (!context) context = "";
    			macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
    			if (!macrocontext) macrocontext = "";
    			callerid = ast_variable_retrieve(cfg, "message", "callerid");
    			if (!callerid) callerid = "";
    			origtime = ast_variable_retrieve(cfg, "message", "origtime");
    			if (!origtime) origtime = "";
    			duration = ast_variable_retrieve(cfg, "message", "duration");
    			if (!duration) duration = "";
    
    			category = ast_variable_retrieve(cfg, "message", "category");
    			if (!category) category = "";
    
    		}
    		fdlen = lseek(fd, 0, SEEK_END);
    		lseek(fd, 0, SEEK_SET);
    
    		fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
    		if (!fdm) {
    			ast_log(LOG_WARNING, "Memory map failed!\n");
    
    			goto yuck;
    		} 
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		if (!ast_strlen_zero(category)) 
    
    			snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table); 
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		else
    
    			snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		len = fdlen; /* SQL_LEN_DATA_AT_EXEC(fdlen); */
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, fdlen, 0, (void *)fdm, fdlen, &len);
    
    		SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(context), 0, (void *)context, 0, NULL);
    		SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(macrocontext), 0, (void *)macrocontext, 0, NULL);
    		SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(callerid), 0, (void *)callerid, 0, NULL);
    		SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(origtime), 0, (void *)origtime, 0, NULL);
    		SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(duration), 0, (void *)duration, 0, NULL);
    
    		SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxuser), 0, (void *)mailboxuser, 0, NULL);
    		SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxcontext), 0, (void *)mailboxcontext, 0, NULL);
    
    		if (!ast_strlen_zero(category))
    
    			SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:	
    	if (cfg)
    
    		ast_config_destroy(cfg);
    
    	if (fdm)
    		munmap(fdm, fdlen);
    	if (fd > -1)
    		close(fd);
    	return x;
    }
    
    
    static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
    
    {
    	int res;
    	SQLHSTMT stmt;
    	char sql[256];
    
    
    	delete_file(ddir, dmsg);
    
    	if (obj) {
    		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
    		snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
    		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
    
    		snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
    
    		res = SQLPrepare(stmt, sql, SQL_NTS);
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
    		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
    
    		SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxuser), 0, (void *)mailboxuser, 0, NULL);
    		SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxcontext), 0, (void *)mailboxcontext, 0, NULL);
    		SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
    		SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
    
    		res = odbc_smart_execute(obj, stmt);
    
    		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
    			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
    			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    			goto yuck;
    		}
    		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
    
    	} else
    		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
    yuck:
    	return;	
    }
    
    #else
    
    static int count_messages(struct ast_vm_user *vmu, char *dir)
    
    	/* Find all .txt files - even if they are not in sequence from 0000 */
    
    
    	int vmcount = 0;
    	DIR *vmdir = NULL;
    	struct dirent *vment = NULL;
    
    
    	if (vm_lock_path(dir))
    
    		return ERROR_LOCK_PATH;
    
    
    	if ((vmdir = opendir(dir))) {
    		while ((vment = readdir(vmdir))) {
    			if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) 
    				vmcount++;
    		}
    		closedir(vmdir);
    
    	ast_unlock_path(dir);
    	
    	return vmcount;
    
    }
    
    static void rename_file(char *sfn, char *dfn)
    {
    
    	char stxt[256];
    	char dtxt[256];
    	ast_filerename(sfn,dfn,NULL);
    
    	snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
    	snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
    	rename(stxt, dtxt);
    }
    
    static int copy(char *infile, char *outfile)
    {
    	int ifd;
    	int ofd;
    	int res;
    	int len;
    	char buf[4096];
    
    #ifdef HARDLINK_WHEN_POSSIBLE
    	/* Hard link if possible; saves disk space & is faster */
    	if (link(infile, outfile)) {
    #endif
    		if ((ifd = open(infile, O_RDONLY)) < 0) {
    			ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
    			return -1;
    		}
    
    		if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
    
    			ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
    			close(ifd);
    			return -1;
    		}
    		do {
    			len = read(ifd, buf, sizeof(buf));
    			if (len < 0) {
    				ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
    				close(ifd);
    				close(ofd);
    				unlink(outfile);
    			}
    			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", outfile, res, len, strerror(errno));
    					close(ifd);
    					close(ofd);
    					unlink(outfile);
    				}
    			}
    		} while (len);
    		close(ifd);
    		close(ofd);
    		return 0;
    #ifdef HARDLINK_WHEN_POSSIBLE
    	} else {
    		/* Hard link succeeded */
    		return 0;
    	}
    #endif
    }
    
    static void copy_file(char *frompath, char *topath)
    {
    
    	ast_filecopy(frompath, topath, NULL);
    	snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
    	snprintf(topath2, sizeof(topath2), "%s.txt", topath);
    	copy(frompath2, topath2);
    }
    
    
    /*
     * A negative return value indicates an error.
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
     * \note Should always be called with a lock already set on dir.
    
    static int last_message_index(struct ast_vm_user *vmu, char *dir)
    
    	unsigned char map[MAXMSGLIMIT] = "";
    	DIR *msgdir;
    	struct dirent *msgdirent;
    	int msgdirint;
    
    	/* Reading the entire directory into a file map scales better than
    	 * doing a stat repeatedly on a predicted sequence.  I suspect this
    	 * is partially due to stat(2) internally doing a readdir(2) itself to
    	 * find each file. */
    	msgdir = opendir(dir);
    	while ((msgdirent = readdir(msgdir))) {
    		if (sscanf(msgdirent->d_name, "msg%d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
    			map[msgdirint] = 1;
    	}
    	closedir(msgdir);
    
    
    	for (x = 0; x < vmu->maxmsg; x++) {
    
    static int vm_delete(char *file)
    {
    	char *txt;
    	int txtsize = 0;
    
    	txtsize = (strlen(file) + 5)*sizeof(char);
    
    	/* Sprintf here would safe because we alloca'd exactly the right length,
    	 * but trying to eliminate all sprintf's anyhow
    	 */
    	snprintf(txt, txtsize, "%s.txt", file);
    	unlink(txt);
    	return ast_filedelete(file, NULL);
    }
    
    
    #endif
    
    static int inbuf(struct baseio *bio, FILE *fi)
    
    	if (bio->ateof)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    
    
    	if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
    		if (ferror(fi))
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    
    
    static int inchar(struct baseio *bio, FILE *fi)
    
    	if (bio->iocp>=bio->iolen) {
    		if (!inbuf(bio, fi))
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return EOF;
    
    static int ochar(struct baseio *bio, int c, FILE *so)
    
    	if (bio->linelength>=BASELINELEN) {
    		if (fputs(eol,so)==EOF)
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    
    
    	if (putc(((unsigned char)c),so)==EOF)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	return 1;
    }
    
    static int base_encode(char *filename, FILE *so)
    {
    	unsigned char dtable[BASEMAXINLINE];
    	int i,hiteof= 0;
    	FILE *fi;
    
    	memset(&bio, 0, sizeof(bio));
    	bio.iocp = BASEMAXINLINE;
    
    	if (!(fi = fopen(filename, "rb"))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
    		return -1;
    	}
    
    
    	for (i= 0;i<9;i++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		dtable[i]= 'A'+i;
    		dtable[i+9]= 'J'+i;
    		dtable[26+i]= 'a'+i;
    		dtable[26+i+9]= 'j'+i;
    	}
    
    	for (i= 0;i<8;i++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		dtable[i+18]= 'S'+i;
    		dtable[26+i+18]= 's'+i;
    	}
    
    	for (i= 0;i<10;i++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		dtable[52+i]= '0'+i;
    	}
    	dtable[62]= '+';
    	dtable[63]= '/';
    
    
    	while (!hiteof){
    
    Mark Spencer's avatar
    Mark Spencer committed
    		unsigned char igroup[3],ogroup[4];
    		int c,n;
    
    		igroup[0]= igroup[1]= igroup[2]= 0;
    
    
    		for (n= 0;n<3;n++) {
    			if ((c = inchar(&bio, fi)) == EOF) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				hiteof= 1;
    				break;
    			}
    
    			igroup[n]= (unsigned char)c;
    		}
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ogroup[0]= dtable[igroup[0]>>2];
    			ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
    			ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
    			ogroup[3]= dtable[igroup[2]&0x3F];
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    				ogroup[3]= '=';
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    					ogroup[2]= '=';
    			}
    
    
    			for (i= 0;i<4;i++)
    
    	if (fputs(eol,so)==EOF)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    
    	fclose(fi);
    
    	return 1;
    }
    
    
    static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
    
    	char callerid[256];
    
    	/* Prepare variables for substition in email body and subject */
    	pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
    	pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
    
    	snprintf(passdata, passdatasize, "%d", msgnum);
    
    	pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
    
    	pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
    
    	pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	pbx_builtin_setvar_helper(ast, "VM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
    
    	pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (cidname ? cidname : "an unknown caller"));
    	pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
    
    	pbx_builtin_setvar_helper(ast, "VM_DATE", date);
    
    	pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
    
    /*
     * fill in *tm for current time according to the proper timezone, if any.
     * Return tm so it can be used as a function argument.
     */
    static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
    {
    	const struct vm_zone *z = NULL;
    	time_t t = time(NULL);
    
    	/* Does this user have a timezone specified? */
    	if (!ast_strlen_zero(vmu->zonetag)) {
    		/* Find the zone in the list */
    
    		AST_LIST_LOCK(&zones);
    		AST_LIST_TRAVERSE(&zones, z, list) {
    
    			if (!strcmp(z->name, vmu->zonetag))
    				break;
    
    	}
    	ast_localtime(&t, tm, z ? z->timezone : NULL);
    	return tm;
    }
    
    /* same as mkstemp, but return a FILE * */
    static FILE *vm_mkftemp(char *template)
    {
    	FILE *p = NULL;
    	int pfd = mkstemp(template);
    	if (pfd > -1) {
    		p = fdopen(pfd, "w");
    		if (!p) {
    			close(pfd);
    			pfd = -1;
    		}
    	}
    	return p;
    }
    
    
    static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char date[256];
    
    	char host[MAXHOSTNAMELEN] = "";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char who[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char bound[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char dur[256];
    
    	char tmp[80] = "/tmp/astmail-XXXXXX";
    	char tmp2[256];
    
    	if (vmu && ast_strlen_zero(vmu->email)) {
    
    Malcolm Davenport's avatar
    Malcolm Davenport committed
    		ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s].  E-mail will not be sent.\n", vmu->mailbox);
    
    Malcolm Davenport's avatar
    Malcolm Davenport committed
    		return(0);
    	}
    
    	if (!strcmp(format, "wav49"))
    		format = "WAV";
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
    
    	/* Make a temporary file instead of piping directly to sendmail, in case the mail
    	   command hangs */
    
    	if ((p = vm_mkftemp(tmp)) == NULL) {
    		ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
    
    		return -1;
    	} else {
    
    		gethostname(host, sizeof(host)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (strchr(srcemail, '@'))
    
    			ast_copy_string(who, srcemail, sizeof(who));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		else {
    			snprintf(who, sizeof(who), "%s@%s", srcemail, host);
    		}
    
    		snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
    
    		strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		fprintf(p, "Date: %s\n", date);
    
    		/* Set date format for voicemail mail */
    		strftime(date, sizeof(date), emaildateformat, &tm);
    
    
    			struct ast_channel *ast;
    			if ((ast = ast_channel_alloc(0))) {
    
    				char *passdata;
    				int vmlen = strlen(fromstring)*3 + 200;
    				if ((passdata = alloca(vmlen))) {
    					memset(passdata, 0, vmlen);
    
    					prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
    
    					pbx_substitute_variables_helper(ast, fromstring, passdata, vmlen);
    
    					fprintf(p, "From: %s <%s>\n",passdata,who);
    
    				} else
    					ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
    
    			} else
    				ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
    
    			fprintf(p, "From: Asterisk PBX <%s>\n", who);
    		fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
    
    
    			struct ast_channel *ast;
    			if ((ast = ast_channel_alloc(0))) {
    
    				char *passdata;
    				int vmlen = strlen(emailsubject)*3 + 200;
    				if ((passdata = alloca(vmlen))) {
    					memset(passdata, 0, vmlen);
    
    					prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
    
    					pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen);
    					fprintf(p, "Subject: %s\n", passdata);
    				} else
    					ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
    
    			} else
    				ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
    
    		if (*emailtitle) {
    
    			fprintf(p, emailtitle, msgnum + 1, mailbox) ;
    
    		} else if (ast_test_flag((&globalflags), VM_PBXSKIP))
    
    			fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
    		else
    			fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
    
    		fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)ast_random(), mailbox, getpid(), host);
    
    #ifdef IMAP_STORAGE
    		/* additional information needed for IMAP searching */
    		fprintf(p, "X-Asterisk-VM-Message-Num: %d\n", msgnum + 1);
    		/* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s\n", ext); */
    		fprintf(p, "X-Asterisk-VM-Server-Name: %s\n", fromstring);
    		fprintf(p, "X-Asterisk-VM-Context: %s\n", context);
    		fprintf(p, "X-Asterisk-VM-Extension: %s\n", chan->exten);
    		fprintf(p, "X-Asterisk-VM-Priority: %d\n", chan->priority);
    		fprintf(p, "X-Asterisk-VM-Caller-channel: %s\n", chan->name);
    		fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s\n", cidnum);
    		fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s\n", cidname);
    		fprintf(p, "X-Asterisk-VM-Duration: %d\n", duration);
    
    		if (!ast_strlen_zero(category))
    
    			fprintf(p, "X-Asterisk-VM-Category: %s\n", category);
    		fprintf(p, "X-Asterisk-VM-Orig-date: %s\n", date);
    		fprintf(p, "X-Asterisk-VM-Orig-time: %ld\n", (long)time(NULL));
    #endif
    
    		if (!ast_strlen_zero(cidnum))
    			fprintf(p, "X-Asterisk-CallerID: %s\n", cidnum);
    		if (!ast_strlen_zero(cidname))
    			fprintf(p, "X-Asterisk-CallerIDName: %s\n", cidname);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		fprintf(p, "MIME-Version: 1.0\n");
    
    			/* Something unique. */
    
    			snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)ast_random());
    
    			fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			fprintf(p, "--%s\n", bound);
    		}
    
    		fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
    
    			struct ast_channel *ast;
    			if ((ast = ast_channel_alloc(0))) {
    
    				char *passdata;
    				int vmlen = strlen(emailbody)*3 + 200;
    				if ((passdata = alloca(vmlen))) {
    					memset(passdata, 0, vmlen);
    
    					prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
    
    					pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
    					fprintf(p, "%s\n", passdata);
    				} else
    					ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
    
    			} else
    				ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    			fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
    
    			"in mailbox %s from %s, on %s so you might\n"
    			"want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, 
    
    			dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
    
    			/* Eww. We want formats to tell us their own MIME type */
    
    			char *ctype = (!strcasecmp(format, "ogg")) ?  "application/" : "audio/x-";
    
    			create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
    			snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
    			tmpfd = mkstemp(newtmp);
    
    			if (option_debug)
    				ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
    
    			if (vmu->volgain < -.001 || vmu->volgain > .001) {
    				snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
    				ast_safe_system(tmpcmd);
    				attach = newtmp;
    
    				if (option_debug)
    					ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			fprintf(p, "--%s\n", bound);