Index: asterisk/apps/app_voicemail.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v retrieving revision 1.147 diff -u -b -r1.147 app_voicemail.c --- asterisk/apps/app_voicemail.c 6 Sep 2004 15:43:43 -0000 1.147 +++ asterisk/apps/app_voicemail.c 13 Sep 2004 22:45:43 -0000 @@ -41,24 +41,10 @@ #include /* we define USESQLVM when we have MySQL or POSTGRES */ -#ifdef USEMYSQLVM -#include -#define USESQLVM 1 -#endif - -#ifdef USEPOSTGRESVM -/* - * PostgreSQL routines written by Otmar Lendl - */ -#include +#if defined(USEMYSQLVM) || defined(USEPOSTGRESVM) || defined(USEODBCVM) #define USESQLVM 1 #endif -#ifndef USESQLVM -static inline int sql_init(void) { return 0; } -static inline void sql_close(void) { } -#endif - #include "../asterisk.h" #include "../astconf.h" @@ -276,6 +262,9 @@ static char *emailbody = NULL; +#if SUPPORT_EMAILHTMLBODY +static char *emailhtmlbody = NULL; +#endif static int pbxskip = 0; static char *emailsubject = NULL; static char fromstring[100]; @@ -370,155 +359,23 @@ } +#ifdef USESQLVM +char db_changepassword_query[1024]; +char db_setpassword_query[1024]; +char db_getvmuser_query[1024]; +#endif + #ifdef USEMYSQLVM #include "mysql-vm-routines.h" #endif #ifdef USEPOSTGRESVM +#include "postgres-vm-routines.h" +#endif -PGconn *dbhandler; -char dboption[256] = ""; -AST_MUTEX_DEFINE_STATIC(postgreslock); - -static int sql_init(void) -{ - ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption); -/* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */ - - dbhandler=PQconnectdb(dboption); - if (PQstatus(dbhandler) == CONNECTION_BAD) { - ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler)); - return(-1); - } -/* fprintf(stderr,"postgres login OK\n"); */ - return(0); -} - -static void sql_close(void) -{ - PQfinish(dbhandler); -} - - -static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox) -{ - PGresult *PGSQLres; - - - int numFields, i; - char *fname; - char query[240]; - char options[160] = ""; - struct ast_vm_user *retval; - - retval=malloc(sizeof(struct ast_vm_user)); - -/* fprintf(stderr,"postgres find_user:\n"); */ - - if (retval) { - memset(retval, 0, sizeof(struct ast_vm_user)); - retval->alloced=1; - if (mailbox) { - strncpy(retval->mailbox, mailbox, sizeof(retval->mailbox) - 1); - } - if (context) { - strncpy(retval->context, context, sizeof(retval->context) - 1); - } - else - { - strncpy(retval->context, "default", sizeof(retval->context) - 1); - } - populate_defaults(retval); - snprintf(query, sizeof(query), "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", retval->context, mailbox); - -/* fprintf(stderr,"postgres find_user: query = %s\n",query); */ - ast_mutex_lock(&postgreslock); - PGSQLres=PQexec(dbhandler,query); - if (PGSQLres!=NULL) { - if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE || - PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR || - PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) { - - ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres)); - PQclear(PGSQLres); - PQreset(dbhandler); - ast_mutex_unlock(&postgreslock); - free(retval); - return(NULL); - } else { - numFields = PQnfields(PGSQLres); -/* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */ - if (PQntuples(PGSQLres) != 1) { - ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox); - PQclear(PGSQLres); - ast_mutex_unlock(&postgreslock); - free(retval); - return(NULL); - } - for (i=0; ipassword, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1); - } else if (!strcmp(fname, "fullname")) { - strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1); - } else if (!strcmp(fname, "email")) { - strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1); - } else if (!strcmp(fname, "pager")) { - strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1); - } else if (!strcmp(fname, "options")) { - strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1); - apply_options(retval, options); - } - } - } - PQclear(PGSQLres); - ast_mutex_unlock(&postgreslock); - return(retval); - } - else { - ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler)); - ast_mutex_unlock(&postgreslock); - free(retval); - return(NULL); - } - /* not reached */ - } /* malloc() retval */ - return(NULL); -} - - -static void vm_change_password(struct ast_vm_user *vmu, char *password) -{ - char query[400]; - - if (*vmu->context) { - snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->context, vmu->mailbox, vmu->password); - } else { - snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password); - } -/* fprintf(stderr,"postgres change_password: query = %s\n",query); */ - ast_mutex_lock(&postgreslock); - PQexec(dbhandler, query); - strncpy(vmu->password, password, sizeof(vmu->password) - 1); - ast_mutex_unlock(&postgreslock); -} - -static void reset_user_pw(char *context, char *mailbox, char *password) -{ - char query[320]; - - if (context) { - snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox); - } else { - snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox); - } - ast_mutex_lock(&postgreslock); -/* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */ - PQexec(dbhandler, query); - ast_mutex_unlock(&postgreslock); -} - -#endif /* Postgres */ +#ifdef USEODBCVM +#include "odbc-vm-routines.h" +#endif #ifndef USESQLVM @@ -689,7 +546,8 @@ reset_user_pw(vmu->context, vmu->mailbox, newpassword); strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1); } -#endif + +#endif /* ndef(USESQLVM) */ static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword) { @@ -842,6 +700,37 @@ pbx_builtin_setvar_helper(ast, "VM_DATE", date); } +static void subst_email_sub_vars( + FILE* p, + struct ast_vm_user *vmu, + int msgnum, + char* mailbox, + char* callerid, + char* dur, + char* date, + char *template, + char* format, + char* extraarg ) +{ + struct ast_channel *chan = ast_channel_alloc(0); + if (chan) { + char *passdata; + int vmlen = strlen(template)*3 + 200; + if ((passdata = alloca(vmlen))) { + memset(passdata, 0, vmlen); + prep_email_sub_vars(chan,vmu,msgnum+1,mailbox,callerid,dur,date,passdata,vmlen); + pbx_substitute_variables_helper(chan,template,passdata,vmlen); + fprintf(p,format,passdata,extraarg); + } else { + ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + } + ast_channel_free(chan); + } + else { + ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + } +} + static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *attach, char *format, int duration, int attach_user_voicemail) { FILE *p=NULL; @@ -856,7 +745,8 @@ char tmp2[256]; time_t t; struct tm tm; - struct vm_zone *the_zone = NULL; + int multipart = 0; + if (vmu && ast_strlen_zero(vmu->email)) { ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox); return(0); @@ -891,50 +781,30 @@ z = zones; while (z) { if (!strcmp(z->name, vmu->zonetag)) { - the_zone = z; + ast_localtime(&t,&tm,z->timezone); break; } z = z->next; } + /* If not found then use zonetag as the last resort */ + if( !z ) { + ast_localtime(&t,&tm,vmu->zonetag[0] ? vmu->zonetag : NULL); } - - if (the_zone) - ast_localtime(&t,&tm,the_zone->timezone); - else + } + else { ast_localtime(&t,&tm,NULL); + } strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); fprintf(p, "Date: %s\n", date); - if (*fromstring) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(fromstring)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen); - 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"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); - } else + if (*fromstring) + subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,fromstring,"From: \"%s\" <%s>\n",who); + else fprintf(p, "From: Asterisk PBX <%s>\n", who); - fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email); + fprintf(p, "To: \"%s\" <%s>\n", vmu->fullname, vmu->email); if (emailsubject) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(emailsubject)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen); - 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"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,emailsubject,"Subject: %s\n",0); } else if( *emailtitle) { @@ -948,29 +818,35 @@ fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox); fprintf(p, "Message-ID: \n", msgnum, (unsigned int)rand(), mailbox, getpid(), host); fprintf(p, "MIME-Version: 1.0\n"); - if (attach_user_voicemail) { + strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); +#if SUPPORT_EMAILHTMLBODY + multipart = attach_user_voicemail || emailhtmlbody; +#else + multipart = attach_user_voicemail; +#endif + if (multipart) { /* Something unique. */ - snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand()); + snprintf(bound, sizeof(bound)-1, "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand()); fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound); fprintf(p, "--%s\n", bound); } + +#if SUPPORT_EMAILHTMLBODY + if (emailbody && emailhtmlbody) { + /* Need to have miltipart/alternative attachment that will contain both text and HTML text */ + /* Opening multipart/alternative attachment */ + fprintf(p, "Content-Type: multipart/alternative; boundary=\"alternative_%s\"\n\n\n", bound); + /* Start boundary for inner alternative text attachment */ + fprintf(p, "--alternative_%s\n", bound); + } +#endif + + /* Plain text */ fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset); - strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); if (emailbody) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(emailbody)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen); - 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"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,emailbody,"%s\n\n",0); } else { fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n" @@ -978,6 +854,20 @@ "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, (callerid ? callerid : "an unknown caller"), date); } +#if SUPPORT_EMAILHTMLBODY + /* HTML text */ + if (emailhtmlbody) { + /* if emailbody then we have alternative boundary */ + fprintf(p, emailbody ? "--alternative_%s\n" : "--%s\n" , bound); + fprintf(p, "Content-Type: text/html; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset); + subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,emailhtmlbody,"%s\n\n",0); + if (emailbody) { + /* If multipart/alternative attachment has started then it is place to close it */ + fprintf(p, "--alternative_%s--\n\n", bound); + } + } +#endif + /* The voicemail */ if (attach_user_voicemail) { fprintf(p, "--%s\n", bound); fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format); @@ -987,6 +877,8 @@ snprintf(fname, sizeof(fname), "%s.%s", attach, format); base_encode(fname, p); + } + if (multipart) { fprintf(p, "\n\n--%s--\n.\n", bound); } fclose(p); @@ -4196,7 +4088,7 @@ return 0; } -#ifndef USEMYSQLVM +#ifndef USESQLVM /* XXX TL Bug 690 */ static char show_voicemail_users_help[] = "Usage: show voicemail users [for ]\n" @@ -4321,6 +4213,30 @@ #endif +static char* subst_escapes_in_string( char* s ) { + char *tmpread, *tmpwrite; + + /* substitute strings \t and \n into the apropriate characters */ + tmpread = tmpwrite = s; + while ((tmpwrite = strchr(tmpread,'\\'))) { + int len = strlen("\n"); + switch (tmpwrite[1]) { + case 'n': + strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1); + strncpy(tmpwrite,"\n",len); + break; + case 't': + strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1); + strncpy(tmpwrite,"\t",len); + break; + default: + ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n",tmpwrite[1]); + } + tmpread = tmpwrite+len; + } + return s; +} + static int load_config(void) { struct ast_vm_user *cur, *l; @@ -4539,6 +4455,33 @@ exitcontext[0] = '\0'; } +#ifdef USESQLVM + if (!(s=ast_variable_retrieve(cfg, "general", "db_changepassword_query"))) { + strncpy(db_changepassword_query, + "UPDATE voicemail SET password='%s' WHERE (password='%s' OR password IS NULL) AND (mailbox='%s') AND (context='%s')", + sizeof(db_changepassword_query)-1); + } + else { + strncpy(db_changepassword_query, s,sizeof(db_changepassword_query)); + } + if (!(s=ast_variable_retrieve(cfg, "general", "db_setpassword_query"))) { + strncpy(db_setpassword_query, + "UPDATE voicemail SET password='%s' WHERE (mailbox='%s') AND (context='%s')", + sizeof(db_setpassword_query)-1); + } + else { + strncpy(db_setpassword_query, s, sizeof(db_setpassword_query)); + } + if (!(s=ast_variable_retrieve(cfg, "general", "db_getvmuser_query"))) { + strncpy(db_getvmuser_query, + "SELECT password,fullname,email,pager,options FROM voicemail WHERE (mailbox='%s') AND (context='%s')", + sizeof(db_getvmuser_query)-1); + } + else { + strncpy(db_getvmuser_query,s,sizeof(db_getvmuser_query)-1); + } +#endif + #ifdef USEMYSQLVM if (!(s=ast_variable_retrieve(cfg, "general", "dbuser"))) { strncpy(dbuser, "test", sizeof(dbuser) - 1); @@ -4569,6 +4512,14 @@ strncpy(dboption, s, sizeof(dboption) - 1); } #endif + +#ifdef USEODBCVM + if (!(s=ast_variable_retrieve(cfg, "general", "db_conn_string"))) { + strncpy(db_conn_string, "dbconn_string not-specified in voicemail.conf", sizeof(db_conn_string) - 1); + } else { + strncpy(db_conn_string, s, sizeof(db_conn_string) - 1); + } +#endif cat = ast_category_browse(cfg, NULL); while(cat) { if (strcasecmp(cat, "general")) { @@ -4648,29 +4599,14 @@ } if ((s=ast_variable_retrieve(cfg, "general", "emailsubject"))) emailsubject = strdup(s); - if ((s=ast_variable_retrieve(cfg, "general", "emailbody"))) { - char *tmpread, *tmpwrite; - emailbody = strdup(s); - - /* substitute strings \t and \n into the apropriate characters */ - tmpread = tmpwrite = emailbody; - while ((tmpwrite = strchr(tmpread,'\\'))) { - int len = strlen("\n"); - switch (tmpwrite[1]) { - case 'n': - strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1); - strncpy(tmpwrite,"\n",len); - break; - case 't': - strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1); - strncpy(tmpwrite,"\t",len); - break; - default: - ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n",tmpwrite[1]); - } - tmpread = tmpwrite+len; - } + if ((s=ast_variable_retrieve(cfg, "general", "emailbody"))) + emailbody = subst_escapes_in_string(strdup(s)); +#if SUPPORT_EMAILHTMLBODY + if ((s=ast_variable_retrieve(cfg, "general", "emailhtmlbody"))) { + if( emailhtmlbody ) free(emailhtmlbody); + emailhtmlbody = subst_escapes_in_string(strdup(s)); } +#endif ast_destroy(cfg); ast_mutex_unlock(&vmlock); return 0; @@ -4695,8 +4631,9 @@ res |= ast_unregister_application(app2); res |= ast_unregister_application(capp2); res |= ast_unregister_application(app3); +#ifdef USESQLVM sql_close(); -#ifndef USEMYSQLVM +#else ast_cli_unregister(&show_voicemail_users_cli); ast_cli_unregister(&show_voicemail_zones_cli); #endif @@ -4718,11 +4655,12 @@ return(res); } +#ifdef USESQLVM if ((res = sql_init())) { ast_log(LOG_WARNING, "SQL init\n"); return res; } -#ifndef USEMYSQLVM +#else ast_cli_register(&show_voicemail_users_cli); ast_cli_register(&show_voicemail_zones_cli); #endif