--- app_voicemail.c 2004-07-15 13:53:36.000000000 -0700 +++ asterisk/apps/app_voicemail.c 2004-07-14 00:34:34.000000000 -0700 @@ -40,9 +40,6 @@ #include #include -#define EXTRA_LOG 0 -#define SUPPORT_EMAILHTMLBODY 1 - /* we define USESQLVM when we have MySQL or POSTGRES */ #ifdef USEMYSQLVM #include @@ -275,9 +272,6 @@ static char *emailbody = NULL; -#if SUPPORT_EMAILHTMLBODY -static char *emailhtmlbody = NULL; -#endif static int pbxskip = 0; static char *emailsubject = NULL; static char fromstring[100]; @@ -364,19 +358,155 @@ } -#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 */ #ifndef USESQLVM @@ -689,37 +819,6 @@ 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; @@ -735,8 +834,6 @@ 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); @@ -785,14 +882,36 @@ strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); fprintf(p, "Date: %s\n", date); - if (*fromstring) - subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,fromstring,"From: \"%s\" <%s>\n",who); - else + 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 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) { - subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,emailsubject,"Subject: %s\n",0); + 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"); } else if( *emailtitle) { @@ -804,83 +923,52 @@ 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: \n", msgnum, mailbox, getpid(), host); fprintf(p, "MIME-Version: 1.0\n"); - - strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); -#if SUPPORT_EMAILHTMLBODY - multipart = attach_voicemail || emailhtmlbody; -#else - multipart = attach_voicemail; -#endif - if (multipart) { + if (attach_user_voicemail) { /* Something unique. */ - snprintf(bound, sizeof(bound)-1, "voicemail_%d%s%d", msgnum, mailbox, getpid()); + snprintf(bound, sizeof(bound), "voicemail_%d%s%d", msgnum, mailbox, getpid()); + 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); + fprintf(p, "--%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) { - subst_email_sub_vars(p,vmu,msgnum,mailbox,callerid,dur,date,emailbody,"%s\n\n",0); + 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"); } else { 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, (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); fprintf(p, "Content-Transfer-Encoding: base64\n"); fprintf(p, "Content-Description: Voicemail sound attachment.\n"); fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format); + snprintf(fname, sizeof(fname), "%s.%s", attach, format); base_encode(fname, p); - } - - if (multipart) { fprintf(p, "\n\n--%s--\n.\n", bound); } fclose(p); - -#if EXTRA_LOG - snprintf(tmp2, sizeof(tmp2), "( %s < %s ) &", mailcmd, tmp); -#else snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); -#endif ast_safe_system(tmp2); -#if EXTRA_LOG - fprintf(stderr,"tmp2=%s\n", tmp2); -#endif - ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", who, mailcmd); } else { ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd); @@ -4051,30 +4139,6 @@ #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; @@ -4277,33 +4341,6 @@ 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); @@ -4390,12 +4427,6 @@ memset(fromstring,0,sizeof(fromstring)); memset(emailtitle,0,sizeof(emailtitle)); strncpy(charset, "ISO-8859-1", sizeof(charset) - 1); -#if SUPPORT_EMAILHTMLBODY - if (emailhtmlbody) { - free(emailhtmlbody); - emailhtmlbody = NULL; - } -#endif if (emailbody) { free(emailbody); emailbody = NULL; @@ -4416,12 +4447,29 @@ } if ((s=ast_variable_retrieve(cfg, "general", "emailsubject"))) emailsubject = strdup(s); - 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"))) - emailhtmlbody = subst_escapes_in_string(strdup(s)); -#endif + 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; + } + } ast_destroy(cfg); ast_mutex_unlock(&vmlock); return 0;