55 #ifdef USE_SYSTEM_IMAP 56 #include <imap/c-client.h> 57 #include <imap/imap4r1.h> 58 #include <imap/linkage.h> 59 #elif defined (USE_SYSTEM_CCLIENT) 60 #include <c-client/c-client.h> 61 #include <c-client/imap4r1.h> 62 #include <c-client/linkage.h> 76 #if defined(__FreeBSD__) || defined(__OpenBSD__) 442 static char imapserver[48] =
"localhost";
443 static char imapport[8] =
"143";
444 static char imapflags[128];
445 static char imapfolder[64] =
"INBOX";
446 static char imapparentfolder[64];
447 static char greetingfolder[64] =
"INBOX";
448 static char authuser[32];
449 static char authpassword[42];
450 static int imapversion = 1;
452 static int expungeonhangup = 1;
453 static int imapgreetings;
454 static int imap_poll_logout;
455 static char delimiter;
466 static int init_mailstream(
struct vm_state *vms,
int box);
467 static void write_file(
char *filename,
char *buffer,
unsigned long len);
468 static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len);
469 static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu);
470 static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len);
471 static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive);
472 static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive);
474 static void vmstate_insert(
struct vm_state *vms);
475 static void vmstate_delete(
struct vm_state *vms);
476 static void set_update(MAILSTREAM * stream);
477 static void init_vm_state(
struct vm_state *vms);
478 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *
format,
int is_intro);
479 static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream);
480 static void mm_parsequota (MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota);
481 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int target);
482 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *
flag,
const char *msg_id);
483 static void vm_imap_update_msg_id(
char *dir,
int msgnum,
const char *msg_id,
struct ast_vm_user *vmu,
struct ast_config *msg_cfg,
int folder);
484 static void update_messages_by_imapuser(
const char *
user,
unsigned long number);
487 static int imap_remove_file (
char *dir,
int msgnum);
488 static int imap_retrieve_file (
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context);
489 static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms);
492 static void imap_logout(
const char *mailbox_id);
503 #define SMDI_MWI_WAIT_TIMEOUT 1000 505 #define COMMAND_TIMEOUT 5000 507 #define VOICEMAIL_DIR_MODE 0777 508 #define VOICEMAIL_FILE_MODE 0666 509 #define CHUNKSIZE 65536 511 #define VOICEMAIL_CONFIG "voicemail.conf" 512 #define ASTERISK_USERNAME "asterisk" 517 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#" 518 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*" 519 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0" 520 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2" 521 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789" 522 #define VALID_DTMF "1234567890*#" 526 #define SENDMAIL "/usr/sbin/sendmail -t" 528 #define INTRO "vm-intro" 530 #define MAX_MAIL_BODY_CONTENT_SIZE 134217728L // 128 Mbyte 533 #define MAXMSGLIMIT 9999 535 #define MINPASSWORD 0 537 #define BASELINELEN 72 538 #define BASEMAXINLINE 256 545 #define MAX_DATETIME_FORMAT 512 546 #define MAX_NUM_CID_CONTEXTS 10 548 #define VM_REVIEW (1 << 0) 549 #define VM_OPERATOR (1 << 1) 550 #define VM_SAYCID (1 << 2) 551 #define VM_SVMAIL (1 << 3) 552 #define VM_ENVELOPE (1 << 4) 553 #define VM_SAYDURATION (1 << 5) 554 #define VM_SKIPAFTERCMD (1 << 6) 555 #define VM_FORCENAME (1 << 7) 556 #define VM_FORCEGREET (1 << 8) 557 #define VM_PBXSKIP (1 << 9) 558 #define VM_DIRECFORWARD (1 << 10) 559 #define VM_ATTACH (1 << 11) 560 #define VM_DELETE (1 << 12) 561 #define VM_ALLOCED (1 << 13) 562 #define VM_SEARCH (1 << 14) 563 #define VM_TEMPGREETWARN (1 << 15) 564 #define VM_MOVEHEARD (1 << 16) 565 #define VM_MESSAGEWRAP (1 << 17) 566 #define VM_FWDURGAUTO (1 << 18) 567 #define ERROR_LOCK_PATH -100 568 #define ERROR_MAX_MSGS -101 569 #define OPERATOR_EXIT 300 643 #ifdef TEST_FRAMEWORK 748 #define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION) 749 #define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT) 751 #define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN) 786 char imappassword[80];
788 char imapvmshareid[80];
800 char msg_format[512];
803 #define VMSTATE_MAX_MSG_ARRAY 256 828 unsigned msg_array_max;
829 MAILSTREAM *mailstream;
839 unsigned int quota_limit;
840 unsigned int quota_usage;
846 static char odbc_database[80] =
"asterisk";
847 static char odbc_table[80] =
"voicemessages";
848 #define RETRIEVE(a,b,c,d) retrieve_file(a,b) 849 #define DISPOSE(a,b) remove_file(a,b) 850 #define STORE(a,b,c,d,e,f,g,h,i,j,k) store_file(a,b,c,d) 851 #define EXISTS(a,b,c,d) (message_exists(a,b)) 852 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f)) 853 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f)) 854 #define DELETE(a,b,c,d) (delete_file(a,b)) 855 #define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c))) 858 #define DISPOSE(a,b) (imap_remove_file(a,b)) 859 #define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k)) 860 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d) 861 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0) 862 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h)); 863 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h)); 864 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d)) 865 #define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f))) 867 #define RETRIEVE(a,b,c,d) 869 #define STORE(a,b,c,d,e,f,g,h,i,j,k) 870 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0) 871 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h)); 872 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h)); 873 #define DELETE(a,b,c,d) (vm_delete(c)) 874 #define UPDATE_MSG_ID(a, b, c, d, e, f) 885 #define PWDCHANGE_INTERNAL (1 << 1) 886 #define PWDCHANGE_EXTERNAL (1 << 2) 890 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage" 893 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage" 895 # define tdesc "Comedian Mail (Voicemail System)" 943 #define DEFAULT_POLL_FREQ 30 966 #define MAPPING_BUCKETS 511 1024 static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
1025 static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
1036 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
1037 signed char record_gain,
struct vm_state *vms,
char *
flag,
const char *msg_id,
int forwardintro);
1041 static void make_email_file(FILE *p,
char *srcemail,
struct ast_vm_user *vmu,
int msgnum,
char *
context,
char *
mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *attach,
char *attach2,
char *
format,
int duration,
int attach_user_voicemail,
struct ast_channel *chan,
const char *category,
int imap,
const char *
flag,
const char *msg_id);
1072 static int vm_msg_forward(
const char *
from_mailbox,
const char *from_context,
const char *from_folder,
const char *to_mailbox,
const char *to_context,
const char *to_folder,
size_t num_msgs,
const char *msg_ids[],
int delete_old);
1073 static int vm_msg_move(
const char *
mailbox,
const char *
context,
size_t num_msgs,
const char *oldfolder,
const char *old_msg_ids[],
const char *newfolder);
1077 #ifdef TEST_FRAMEWORK 1099 *context = mailbox_id;
1100 *mailbox =
strsep(context,
"@");
1105 *context =
"default";
1127 if (strcmp(i->
mailbox, j->mailbox)) {
1135 int context_len = strlen(context) + 1;
1136 int mailbox_len = strlen(mailbox) + 1;
1142 if ((i =
ao2_find(inprocess_container, arg, 0))) {
1151 if (!(i =
ao2_alloc(
sizeof(*i) + context_len + mailbox_len,
NULL))) {
1165 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE)) 1178 for (; *
input; input++) {
1183 if (bufptr == buf + buflen - 1) {
1209 if (saydurationminfo) {
1226 if (maxdeletedmsg) {
1237 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1238 ast_copy_string(vmu->imapserver, imapserver,
sizeof(vmu->imapserver));
1255 if (!strcasecmp(var,
"attach")) {
1257 }
else if (!strcasecmp(var,
"attachfmt")) {
1259 }
else if (!strcasecmp(var,
"serveremail")) {
1261 }
else if (!strcasecmp(var,
"fromstring")) {
1263 }
else if (!strcasecmp(var,
"emailbody")) {
1266 }
else if (!strcasecmp(var,
"emailsubject")) {
1269 }
else if (!strcasecmp(var,
"language")) {
1271 }
else if (!strcasecmp(var,
"tz")) {
1273 }
else if (!strcasecmp(var,
"locale")) {
1276 }
else if (!strcasecmp(var,
"imapuser")) {
1278 vmu->imapversion = imapversion;
1279 }
else if (!strcasecmp(var,
"imapserver")) {
1281 vmu->imapversion = imapversion;
1282 }
else if (!strcasecmp(var,
"imapport")) {
1284 vmu->imapversion = imapversion;
1285 }
else if (!strcasecmp(var,
"imapflags")) {
1287 vmu->imapversion = imapversion;
1288 }
else if (!strcasecmp(var,
"imappassword") || !strcasecmp(var,
"imapsecret")) {
1290 vmu->imapversion = imapversion;
1291 }
else if (!strcasecmp(var,
"imapfolder")) {
1293 vmu->imapversion = imapversion;
1294 }
else if (!strcasecmp(var,
"imapvmshareid")) {
1295 ast_copy_string(vmu->imapvmshareid, value,
sizeof(vmu->imapvmshareid));
1296 vmu->imapversion = imapversion;
1298 }
else if (!strcasecmp(var,
"delete") || !strcasecmp(var,
"deletevoicemail")) {
1300 }
else if (!strcasecmp(var,
"saycid")){
1302 }
else if (!strcasecmp(var,
"sendvoicemail")){
1304 }
else if (!strcasecmp(var,
"review")){
1306 }
else if (!strcasecmp(var,
"tempgreetwarn")){
1308 }
else if (!strcasecmp(var,
"messagewrap")){
1310 }
else if (!strcasecmp(var,
"operator")) {
1312 }
else if (!strcasecmp(var,
"envelope")){
1314 }
else if (!strcasecmp(var,
"moveheard")){
1316 }
else if (!strcasecmp(var,
"sayduration")){
1318 }
else if (!strcasecmp(var,
"saydurationm")){
1319 if (sscanf(value,
"%30d", &x) == 1) {
1324 }
else if (!strcasecmp(var,
"forcename")){
1326 }
else if (!strcasecmp(var,
"forcegreetings")){
1328 }
else if (!strcasecmp(var,
"callback")) {
1330 }
else if (!strcasecmp(var,
"dialout")) {
1332 }
else if (!strcasecmp(var,
"exitcontext")) {
1334 }
else if (!strcasecmp(var,
"minsecs")) {
1335 if (sscanf(value,
"%30d", &x) == 1 && x >= 0) {
1338 ast_log(
LOG_WARNING,
"Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1341 }
else if (!strcasecmp(var,
"maxmessage") || !strcasecmp(var,
"maxsecs")) {
1349 if (!strcasecmp(var,
"maxmessage"))
1350 ast_log(
AST_LOG_WARNING,
"Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1351 }
else if (!strcasecmp(var,
"maxmsg")) {
1352 vmu->
maxmsg = atoi(value);
1361 }
else if (!strcasecmp(var,
"nextaftercmd")) {
1363 }
else if (!strcasecmp(var,
"backupdeleted")) {
1364 if (sscanf(value,
"%30d", &x) == 1)
1372 ast_log(
AST_LOG_WARNING,
"Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value,
MAXMSG);
1378 }
else if (!strcasecmp(var,
"volgain")) {
1379 sscanf(value,
"%30lf", &vmu->
volgain);
1380 }
else if (!strcasecmp(var,
"passwordlocation")) {
1381 if (!strcasecmp(value,
"spooldir")) {
1386 }
else if (!strcasecmp(var,
"options")) {
1393 int fds[2], pid = 0;
1395 memset(buf, 0, len);
1398 snprintf(buf, len,
"FAILURE: Pipe failed: %s", strerror(
errno));
1407 snprintf(buf, len,
"FAILURE: Fork failed");
1411 if (read(fds[0], buf, len) < 0) {
1423 dup2(fds[1], STDOUT_FILENO);
1429 execv(arg.v[0], arg.v);
1430 printf(
"FAILURE: %s", strerror(
errno));
1447 if (strlen(password) < minpassword)
1453 char cmd[255],
buf[255];
1455 ast_debug(1,
"Verify password policies for %s\n", password);
1457 snprintf(cmd,
sizeof(cmd),
"%s %s %s %s %s", ext_pass_check_cmd, vmu->
mailbox, vmu->
context, vmu->
password, password);
1460 if (!strncasecmp(buf,
"VALID", 5)) {
1461 ast_debug(3,
"Passed password check: '%s'\n", buf);
1463 }
else if (!strncasecmp(buf,
"FAILURE", 7)) {
1488 if (!strcmp(vmu->
password, password)) {
1493 if (strlen(password) > 10) {
1513 while ((s =
strsep(&stringp,
"|"))) {
1515 if ((var =
strsep(&value,
"=")) && value) {
1528 for (;
var; var = var->
next) {
1529 if (!strcasecmp(var->
name,
"vmsecret")) {
1531 }
else if (!strcasecmp(var->
name,
"secret") || !strcasecmp(var->
name,
"password")) {
1535 "\n\tmust be reset in voicemail.conf.\n", retval->
mailbox);
1540 }
else if (!strcasecmp(var->
name,
"uniqueid")) {
1542 }
else if (!strcasecmp(var->
name,
"pager")) {
1544 }
else if (!strcasecmp(var->
name,
"email")) {
1547 }
else if (!strcasecmp(var->
name,
"fullname")) {
1549 }
else if (!strcasecmp(var->
name,
"context")) {
1551 }
else if (!strcasecmp(var->
name,
"emailsubject")) {
1554 }
else if (!strcasecmp(var->
name,
"emailbody")) {
1558 }
else if (!strcasecmp(var->
name,
"imapuser")) {
1560 retval->imapversion = imapversion;
1561 }
else if (!strcasecmp(var->
name,
"imapserver")) {
1563 retval->imapversion = imapversion;
1564 }
else if (!strcasecmp(var->
name,
"imapport")) {
1566 retval->imapversion = imapversion;
1567 }
else if (!strcasecmp(var->
name,
"imapflags")) {
1569 retval->imapversion = imapversion;
1570 }
else if (!strcasecmp(var->
name,
"imappassword") || !strcasecmp(var->
name,
"imapsecret")) {
1572 retval->imapversion = imapversion;
1573 }
else if (!strcasecmp(var->
name,
"imapfolder")) {
1575 retval->imapversion = imapversion;
1576 }
else if (!strcasecmp(var->
name,
"imapvmshareid")) {
1578 retval->imapversion = imapversion;
1597 for (i = 0; i < strlen(key); ++i) {
1622 if ((retval = (ivm ? ivm :
ast_calloc(1,
sizeof(*retval))))) {
1624 memset(retval, 0,
sizeof(*retval));
1665 context =
"default";
1669 if (cur->imapversion != imapversion) {
1675 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1680 if ((vmu = (ivm ? ivm :
ast_calloc(1,
sizeof(*vmu))))) {
1707 char *search_mailbox =
NULL;
1708 char *search_context =
NULL;
1712 vmu =
find_user(ivm, search_mailbox, search_context);
1729 static int reset_user_pw(
const char *context,
const char *mailbox,
const char *newpass)
1736 if ((!context || !strcasecmp(context, cur->
context)) &&
1737 (!strcasecmp(mailbox, cur->
mailbox)))
1768 char *category =
NULL;
1780 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->
context, vmu->
mailbox);
1783 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
1788 ast_verb(4,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
1794 if (!strcasecmp(category, vmu->
context)) {
1801 value = strstr(tmp,
",");
1804 sprintf(
new,
"%s", newpassword);
1806 new =
ast_malloc((strlen(value) + strlen(newpassword) + 1));
1807 sprintf(
new,
"%s%s", newpassword, value);
1821 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
1838 ast_debug(4,
"users.conf: %s\n", category);
1839 if (!strcasecmp(category, vmu->
mailbox)) {
1840 char new[strlen(newpassword) + 1];
1842 ast_debug(3,
"looks like we need to make vmsecret!\n");
1848 sprintf(
new,
"%s", newpassword);
1850 ast_debug(4,
"failed to get category!\n");
1879 snprintf(buf,
sizeof(buf),
"%s %s %s %s", ext_pass_cmd, vmu->
context, vmu->
mailbox, newpassword);
1880 ast_debug(1,
"External password: %s\n",buf);
1902 static int make_dir(
char *dest,
int len,
const char *context,
const char *
ext,
const char *folder)
1904 return snprintf(dest, len,
"%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
1919 static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
1921 return snprintf(dest, len,
"%s/msg%04d", dir, num);
1928 int pfd = mkstemp(
template);
1931 p = fdopen(pfd,
"w+");
1953 make_dir(dest, len, context, ext, folder);
1964 if (vmu &&
id == 0) {
1965 return vmu->imapfolder;
1968 return (
id >= 0 &&
id <
ARRAY_LEN(mailbox_folders)) ? mailbox_folders[
id] :
"Unknown";
1981 for (i = 0; i <
ARRAY_LEN(mailbox_folders); i++) {
1982 if (strcasecmp(name, mailbox_folders[i]) == 0) {
2023 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
2036 if (arraysize > 0) {
2054 static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu)
2058 unsigned long messageNum;
2061 if (msgnum < 0 && !imapgreetings) {
2066 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2067 ast_log(
LOG_WARNING,
"Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->
mailbox, msgnum);
2072 imap_delete_old_greeting(file, vms);
2078 messageNum = vms->msgArray[msgnum];
2079 if (messageNum == 0) {
2080 ast_log(
LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2083 ast_debug(3,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2085 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
2087 mail_setflag (vms->mailstream, arg,
"\\DELETED");
2088 mail_expunge(vms->mailstream);
2092 static void vm_imap_update_msg_id(
char *dir,
int msgnum,
const char *msg_id,
struct ast_vm_user *vmu,
struct ast_config *msg_cfg,
int folder)
2099 const char *duration_str;
2143 sscanf(duration_str,
"%30d", &duration);
2154 if (!imap_store_file(dir, vmu->
mailbox, vmu->
context, msgnum, chan, vmu, vmfmts,
2159 vm_imap_delete(dir, msgnum, vmu);
2165 static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
2168 char *
file, *filename;
2178 if (msgnum > -1 || !imapgreetings) {
2185 ast_debug(1,
"Failed to procure file name from directory passed.\n");
2191 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
2192 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2197 if (!(vms_p = create_vm_state_from_user(vmu))) {
2204 *vms_p->introfn =
'\0';
2218 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2219 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2221 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2222 char *attachment = body->nested.part->next->body.parameter->value;
2223 char copy[strlen(attachment) + 1];
2225 strcpy(copy, attachment);
2228 filename =
strsep(&attachment,
".");
2229 if (!strcmp(filename, file)) {
2231 vms_p->msgArray[vms_p->
curmsg] = i + 1;
2233 save_body(body, vms_p,
"2", attachment, 0);
2244 if (curr_mbox != -1) {
2246 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2255 static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *mailbox,
const char *context)
2258 char *header_content;
2259 char *attachedfilefmt;
2263 FILE *text_file_ptr;
2274 if (imapgreetings) {
2275 res = imap_retrieve_greeting(dir, msgnum, vmu);
2286 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2301 if (curr_mbox < 0) {
2302 ast_debug(3,
"Mailbox folder curbox not set, defaulting to Inbox\n");
2305 init_mailstream(vms, curr_mbox);
2306 if (!vms->mailstream) {
2313 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->
fn);
2321 ast_debug(3,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2322 if (vms->msgArray[msgnum] == 0) {
2330 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2334 ast_log(
LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2340 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2344 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2345 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2354 strsep(&attachedfilefmt,
".");
2355 if (!attachedfilefmt) {
2356 ast_log(
LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2361 save_body(body, vms,
"2", attachedfilefmt, 0);
2362 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2363 *vms->introfn =
'\0';
2367 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->
fn,
"txt");
2369 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2374 fprintf(text_file_ptr,
"%s\n",
"[message]");
2376 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:", buf,
sizeof(buf))) {
2377 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(buf,
""));
2379 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:", buf,
sizeof(buf))) {
2380 fprintf(text_file_ptr,
"<%s>\n",
S_OR(buf,
""));
2382 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Context:", buf,
sizeof(buf))) {
2383 fprintf(text_file_ptr,
"context=%s\n",
S_OR(buf,
""));
2385 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:", buf,
sizeof(buf))) {
2386 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(buf,
""));
2388 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:", buf,
sizeof(buf))) {
2389 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(buf,
""));
2391 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Category:", buf,
sizeof(buf))) {
2392 fprintf(text_file_ptr,
"category=%s\n",
S_OR(buf,
""));
2394 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:", buf,
sizeof(buf))) {
2395 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(buf,
""));
2397 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Message-ID:", buf,
sizeof(buf))) {
2398 fprintf(text_file_ptr,
"msg_id=%s\n",
S_OR(buf,
""));
2400 fclose(text_file_ptr);
2407 static int folder_int(
const char *folder)
2413 if (!strcasecmp(folder, imapfolder)) {
2415 }
else if (!strcasecmp(folder,
"Old")) {
2417 }
else if (!strcasecmp(folder,
"Work")) {
2419 }
else if (!strcasecmp(folder,
"Family")) {
2421 }
else if (!strcasecmp(folder,
"Friends")) {
2423 }
else if (!strcasecmp(folder,
"Cust1")) {
2425 }
else if (!strcasecmp(folder,
"Cust2")) {
2427 }
else if (!strcasecmp(folder,
"Cust3")) {
2429 }
else if (!strcasecmp(folder,
"Cust4")) {
2431 }
else if (!strcasecmp(folder,
"Cust5")) {
2433 }
else if (!strcasecmp(folder,
"Urgent")) {
2440 static int __messagecount(
const char *context,
const char *mailbox,
const char *folder)
2448 int fold = folder_int(folder);
2461 memset(&vmus, 0,
sizeof(vmus));
2462 vmu =
find_user(&vmus, context, mailbox);
2469 if (vmu->imapuser[0] ==
'\0') {
2477 if (vmu->imapuser[0] ==
'\0') {
2484 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2486 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2489 ast_debug(3,
"Returning before search - user is logged in\n");
2501 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2503 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2507 vms_p = create_vm_state_from_user(vmu);
2509 ret = init_mailstream(vms_p, fold);
2510 if (!vms_p->mailstream) {
2517 pgm = mail_newsearchpgm ();
2518 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
2519 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(context,
"default"));
2545 vms_p->vmArrayIndex = 0;
2546 mail_search_full (vms_p->mailstream,
NULL, pgm, NIL);
2547 if (fold == 0 && urgent == 0)
2551 if (fold == 0 && urgent == 1)
2554 mail_free_searchpgm(&pgm);
2558 return vms_p->vmArrayIndex;
2561 mail_ping(vms_p->mailstream);
2571 check_quota(vms, vmu->imapfolder);
2572 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2573 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2583 ast_log(
LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2602 static int messagecount(
const char *mailbox_id,
const char *folder)
2613 return __messagecount(context, mailbox,
"INBOX") + __messagecount(context, mailbox,
"Urgent");
2615 return __messagecount(context, mailbox, folder);
2619 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *
flag,
const char *msg_id)
2627 char tmp[80] =
"/tmp/astmail-XXXXXX";
2633 char *imap_flags = NIL;
2637 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", vmu->
mailbox, vmu->
context);
2642 if(!imapgreetings) {
2649 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2655 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2656 imap_flags =
"\\FLAGGED";
2672 snprintf(introfn,
sizeof(introfn),
"%sintro", fn);
2687 if (!strcmp(fmt,
"wav49"))
2689 ast_debug(3,
"Storing file '%s', format '%s'\n", fn, fmt);
2702 if (msgnum < 0 && imapgreetings) {
2707 imap_delete_old_greeting(fn, vms);
2713 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
2721 *(vmu->
email) =
'\0';
2724 if (fread(buf, 1, len, p) !=
len) {
2730 ((
char *) buf)[
len] =
'\0';
2731 INIT(&str, mail_string, buf, len);
2732 ret = init_mailstream(vms, box);
2734 imap_mailbox_name(mailbox,
sizeof(mailbox), vms, box, 1);
2736 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
2752 *(vmu->
email) =
'\0';
2771 static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
2785 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
2791 context = strchr(tmp,
'@');
2792 if (strchr(mailbox_context,
',')) {
2793 int tmpnew, tmpold, tmpurgent;
2796 while ((cur =
strsep(&mb,
", "))) {
2798 if (
inboxcount2(cur, urgentmsgs ? &tmpurgent :
NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
2806 *urgentmsgs += tmpurgent;
2817 context =
"default";
2818 mailboxnc = (
char *) mailbox_context;
2827 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
2834 if ((*oldmsgs = __messagecount(context, mailboxnc,
"Old")) < 0) {
2839 if ((*urgentmsgs = __messagecount(context, mailboxnc,
"Urgent")) < 0) {
2856 static int has_voicemail(
const char *mailbox,
const char *folder)
2861 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
2862 while ((box =
strsep(&tmp2,
",&"))) {
2870 if ((context = strchr(tmp,
'@'))) {
2873 context =
"default";
2875 return __messagecount(context, tmp, folder) ? 1 : 0;
2896 char messagestring[10];
2897 if (msgnum >= recip->
maxmsg) {
2901 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
2905 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
2909 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
2911 if ((mail_copy(sendvms->mailstream, messagestring, (
char *)
mbox(vmu, imbox)) == T)) {
2920 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
2923 size_t left =
sizeof(
tmp);
2956 snprintf(spec, len,
"%s%s", tmp, use_folder? vms->imapfolder:
"INBOX");
2958 snprintf(spec, len,
"%s%s", tmp, greetingfolder);
2962 snprintf(spec, len,
"%s%s%c%s", tmp, imapparentfolder, delimiter,
mbox(
NULL, box));
2964 snprintf(spec, len,
"%s%s", tmp,
mbox(
NULL, box));
2969 static int init_mailstream(
struct vm_state *vms,
int box)
2971 MAILSTREAM *stream = NIL;
2979 ast_debug(3,
"vm_state user is:%s\n", vms->imapuser);
2980 if (vms->mailstream == NIL || !vms->mailstream) {
2983 stream = vms->mailstream;
2988 if (delimiter ==
'\0') {
2990 #ifdef USE_SYSTEM_IMAP 2991 #include <imap/linkage.c> 2992 #elif defined(USE_SYSTEM_CCLIENT) 2993 #include <c-client/linkage.c> 2995 #include "linkage.c" 2998 imap_mailbox_name(tmp,
sizeof(tmp), vms, 0, 1);
3001 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3004 if (stream == NIL) {
3008 get_mailbox_delimiter(vms, stream);
3010 for (cp = vms->imapfolder; *cp; cp++)
3015 imap_mailbox_name(tmp,
sizeof(tmp), vms, box, 1);
3016 ast_debug(3,
"Before mail_open, server: %s, box:%d\n", tmp, box);
3019 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3021 if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) {
3022 mail_create(vms->mailstream, tmp);
3026 if (vms->mailstream == NIL) {
3046 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
3047 ast_copy_string(vms->imapserver, vmu->imapserver,
sizeof(vms->imapserver));
3049 ast_copy_string(vms->imapflags, vmu->imapflags,
sizeof(vms->imapflags));
3050 vms->imapversion = vmu->imapversion;
3051 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
3053 if (init_mailstream(vms, box) || !vms->mailstream) {
3062 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n",
mbox(vmu, box));
3063 check_quota(vms, (
char *)
mbox(vmu, box));
3067 pgm = mail_newsearchpgm();
3070 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
3071 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
3082 }
else if (box ==
NEW_FOLDER && urgent == 0) {
3092 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
3094 vms->vmArrayIndex = 0;
3095 mail_search_full (vms->mailstream,
NULL, pgm, NIL);
3096 vms->
lastmsg = vms->vmArrayIndex - 1;
3097 mail_free_searchpgm(&pgm);
3103 ast_log(
LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
3114 static void write_file(
char *filename,
char *buffer,
unsigned long len)
3118 if (!filename || !buffer) {
3122 if (!(output = fopen(filename,
"w"))) {
3127 if (fwrite(buffer, len, 1, output) != 1) {
3128 if (ferror(output)) {
3135 static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
3137 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
3139 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
3143 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
3146 if (vms->vmArrayIndex >= vms->msg_array_max) {
3147 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
3151 vms->msgArray = new_mem;
3152 vms->msg_array_max *= 2;
3155 vms->msgArray[vms->vmArrayIndex++] = number;
3158 void mm_searched(MAILSTREAM *stream,
unsigned long number)
3160 char *mailbox = stream->mailbox,
buf[1024] =
"", *
user;
3162 if (!(user = get_user_by_mailbox(mailbox,
buf,
sizeof(
buf))))
3165 update_messages_by_imapuser(user, number);
3168 static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
3193 void mm_exists(MAILSTREAM * stream,
unsigned long number)
3196 ast_debug(4,
"Entering EXISTS callback for message %ld\n", number);
3197 if (number == 0)
return;
3202 void mm_expunged(MAILSTREAM * stream,
unsigned long number)
3205 ast_debug(4,
"Entering EXPUNGE callback for message %ld\n", number);
3206 if (number == 0)
return;
3211 void mm_flags(MAILSTREAM * stream,
unsigned long number)
3214 ast_debug(4,
"Entering FLAGS callback for message %ld\n", number);
3215 if (number == 0)
return;
3220 void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
3222 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
3223 mm_log (
string, errflg);
3227 void mm_list(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
3229 if (delimiter ==
'\0') {
3233 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
3234 if (attributes & LATT_NOINFERIORS)
3236 if (attributes & LATT_NOSELECT)
3238 if (attributes & LATT_MARKED)
3240 if (attributes & LATT_UNMARKED)
3245 void mm_lsub(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
3247 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
3248 if (attributes & LATT_NOINFERIORS)
3250 if (attributes & LATT_NOSELECT)
3252 if (attributes & LATT_MARKED)
3254 if (attributes & LATT_UNMARKED)
3259 void mm_status(MAILSTREAM * stream,
char *mailbox, MAILSTATUS *
status)
3268 if (status->flags & SA_MESSAGES) {
3271 if (status->flags & SA_RECENT) {
3274 if (status->flags & SA_UNSEEN) {
3277 if (status->flags & SA_UIDVALIDITY) {
3278 ast_str_append(&str, 0,
", %lu UID validity", status->uidvalidity);
3280 if (status->flags & SA_UIDNEXT) {
3289 void mm_log(
char *
string,
long errflg)
3291 switch ((
short) errflg) {
3293 ast_debug(1,
"IMAP Info: %s\n",
string);
3306 void mm_dlog(
char *
string)
3312 void mm_login(NETMBX * mb,
char *user,
char *pwd,
long trial)
3316 ast_debug(4,
"Entering callback mm_login\n");
3325 if (!strcasecmp(mb->user, vmu->imapuser)) {
3331 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3340 void mm_critical(MAILSTREAM * stream)
3345 void mm_nocritical(MAILSTREAM * stream)
3350 long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
3352 kill (getpid (), SIGSTOP);
3357 void mm_fatal(
char *
string)
3363 static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
3366 char *mailbox = stream->mailbox, *
user;
3367 char buf[1024] =
"";
3368 unsigned long usage = 0, limit = 0;
3371 usage = pquota->usage;
3372 limit = pquota->limit;
3373 pquota = pquota->next;
3376 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
3381 ast_debug(3,
"User %s usage is %lu, limit is %lu\n", user, usage, limit);
3383 vms->quota_usage =
usage;
3384 vms->quota_limit = limit;
3387 static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len)
3389 char *start, *eol_pnt;
3395 taglen = strlen(tag) + 1;
3403 memset(buf, 0, len);
3406 if ((eol_pnt = strchr(buf,
'\r')) || (eol_pnt = strchr(buf,
'\n')))
3411 static char *get_user_by_mailbox(
char *mailbox,
char *buf,
size_t len)
3413 char *start, *eol_pnt, *
quote;
3418 if (!(start = strstr(mailbox,
"/user=")))
3423 if (!(quote = strchr(buf,
'"'))) {
3424 if ((eol_pnt = strchr(buf,
'/')) || (eol_pnt = strchr(buf,
'}'))) {
3429 if ((eol_pnt = strchr(quote + 1,
'"'))) {
3440 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3441 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->
username, vmu->
mailbox)) {
3444 ast_debug(5,
"Adding new vmstate for %s\n", vmu->imapuser);
3446 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3448 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3449 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3450 ast_copy_string(vms_p->imapserver, vmu->imapserver,
sizeof(vms_p->imapserver));
3451 ast_copy_string(vms_p->imapport, vmu->imapport,
sizeof(vms_p->imapport));
3452 ast_copy_string(vms_p->imapflags, vmu->imapflags,
sizeof(vms_p->imapflags));
3455 vms_p->mailstream = NIL;
3456 vms_p->imapversion = vmu->imapversion;
3457 ast_debug(5,
"Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3461 init_vm_state(vms_p);
3462 vmstate_insert(vms_p);
3466 static struct vm_state *get_vm_state_by_imapuser(
const char *user,
int interactive)
3468 struct vmstate *vlist =
NULL;
3472 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3473 if ((vms = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms->imapuser, user)) {
3481 ast_debug(3,
"error: vms is NULL for %s\n", user);
3484 if (vlist->vms->imapversion != imapversion) {
3488 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3495 ast_debug(3,
"%s not found in vmstates\n", user);
3500 static struct vm_state *get_vm_state_by_mailbox(
const char *mailbox,
const char *context,
int interactive)
3503 struct vmstate *vlist =
NULL;
3504 const char *local_context =
S_OR(context,
"default");
3508 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3509 if ((vms = pthread_getspecific(ts_vmstate.key)) &&
3510 !strcmp(vms->
username,mailbox) && !strcmp(vms->
context, local_context)) {
3518 ast_debug(3,
"error: vms is NULL for %s\n", mailbox);
3521 if (vlist->vms->imapversion != imapversion) {
3525 ast_debug(3,
"comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
3527 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3535 ast_debug(3,
"%s not found in vmstates\n", mailbox);
3540 static void vmstate_insert(
struct vm_state *vms)
3548 if (vms->interactive == 1) {
3554 vms->vmArrayIndex = altvms->vmArrayIndex;
3559 vms->persist_vms = altvms;
3561 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS 3562 vms->mailstream = altvms->mailstream;
3564 vms->mailstream = NIL;
3575 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3582 static void vmstate_delete(
struct vm_state *vms)
3584 struct vmstate *vc =
NULL;
3589 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3593 altvms->updated = 1;
3594 vms->mailstream = mail_close(vms->mailstream);
3600 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3604 if (vc->vms == vms) {
3615 vc->vms->msgArray =
NULL;
3616 vc->vms->msg_array_max = 0;
3624 static void set_update(MAILSTREAM * stream)
3627 char *mailbox = stream->mailbox, *
user;
3628 char buf[1024] =
"";
3630 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3636 ast_debug(3,
"User %s mailbox set for update.\n", user);
3641 static void init_vm_state(
struct vm_state *vms)
3644 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3645 if (!vms->msgArray) {
3647 vms->msg_array_max = 0;
3649 vms->vmArrayIndex = 0;
3653 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *
format,
int is_intro)
3657 char *
fn = is_intro ? vms->introfn : vms->
fn;
3658 unsigned long len = 0;
3659 unsigned long newlen = 0;
3662 if (!body || body == NIL)
3666 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->
curmsg], section, &len);
3670 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
3674 if (body_content != NIL && len) {
3675 snprintf(filename,
sizeof(filename),
"%s.%s", fn, format);
3677 body_decoded = rfc822_base64((
unsigned char *) body_content, len, &newlen);
3679 if (!newlen || !body_decoded) {
3682 write_file(filename, (
char *) body_decoded, newlen);
3684 ast_debug(5,
"Body of message is NULL.\n");
3698 static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream) {
3700 snprintf(tmp,
sizeof(tmp),
"{%s}",
S_OR(vms->imapserver, imapserver));
3701 mail_list(stream, tmp,
"*");
3711 static void check_quota(
struct vm_state *vms,
char *mailbox) {
3713 mail_parameters(
NULL, SET_QUOTA, (
void *) mm_parsequota);
3714 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n", mailbox);
3715 if (vms && vms->mailstream !=
NULL) {
3716 imap_getquotaroot(vms->mailstream, mailbox);
3739 #define MSG_ID_LEN 256 3751 struct generic_prepare_struct {
3759 struct generic_prepare_struct *gps = data;
3763 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
3764 if (!SQL_SUCCEEDED(res)) {
3769 if (!SQL_SUCCEEDED(res)) {
3771 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3774 for (i = 0; i < gps->argc; i++)
3775 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0,
NULL);
3780 static void odbc_update_msg_id(
char *dir,
int msg_num,
char *msg_id)
3785 char msg_num_str[20];
3786 char *argv[] = { msg_id, dir, msg_num_str };
3787 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
3791 ast_log(
LOG_WARNING,
"Unable to update message ID for message %d in %s\n", msg_num, dir);
3795 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
3796 snprintf(sql,
sizeof(sql),
"UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?", odbc_table);
3801 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3821 static int retrieve_file(
char *dir,
int msgnum)
3827 void *fdm = MAP_FAILED;
3828 SQLSMALLINT colcount = 0;
3835 SQLSMALLINT datatype;
3836 SQLSMALLINT decimaldigits;
3837 SQLSMALLINT nullable;
3846 char *argv[] = { dir, msgnums };
3847 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3857 c = strchr(fmt,
'|');
3860 if (!strcasecmp(fmt,
"wav49"))
3863 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
3870 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
3872 if (!(f = fopen(full_fn,
"w+"))) {
3877 snprintf(full_fn,
sizeof(full_fn),
"%s.%s", fn, fmt);
3878 snprintf(sql,
sizeof(sql),
"SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3886 res = SQLFetch(stmt);
3887 if (!SQL_SUCCEEDED(res)) {
3888 if (res != SQL_NO_DATA) {
3891 goto bail_with_handle;
3897 goto bail_with_handle;
3900 res = SQLNumResultCols(stmt, &colcount);
3901 if (!SQL_SUCCEEDED(res)) {
3903 goto bail_with_handle;
3906 fprintf(f,
"[message]\n");
3907 for (x = 0; x < colcount; x++) {
3910 collen =
sizeof(coltitle);
3911 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
3912 &datatype, &colsize, &decimaldigits, &nullable);
3913 if (!SQL_SUCCEEDED(res)) {
3915 goto bail_with_handle;
3917 if (!strcasecmp(coltitle,
"recording")) {
3919 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
3923 lseek(fd, fdlen - 1, SEEK_SET);
3924 if (write(fd, tmp, 1) != 1) {
3930 for (offset = 0; offset < colsize2; offset +=
CHUNKSIZE) {
3931 if ((fdm = mmap(
NULL,
CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
3933 goto bail_with_handle;
3935 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm,
CHUNKSIZE,
NULL);
3937 if (!SQL_SUCCEEDED(res)) {
3940 goto bail_with_handle;
3943 if (truncate(full_fn, fdlen) < 0) {
3948 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
3949 if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"msg_id")) {
3953 snprintf(rowdata,
sizeof(rowdata),
"%s", msg_id);
3954 }
else if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"category")) {
3956 ast_debug(3,
"Ignoring null category column in ODBC voicemail retrieve_file.\n");
3958 }
else if (!SQL_SUCCEEDED(res)) {
3960 goto bail_with_handle;
3962 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir")) {
3963 fprintf(f,
"%s=%s\n", coltitle, rowdata);
3969 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3983 odbc_update_msg_id(dir, msgnum, msg_id);
4007 char *argv[] = { dir };
4008 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4017 snprintf(sql,
sizeof(sql),
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
4025 res = SQLFetch(stmt);
4026 if (!SQL_SUCCEEDED(res)) {
4027 if (res == SQL_NO_DATA) {
4028 ast_log(
AST_LOG_DEBUG,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4032 goto bail_with_handle;
4035 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4036 if (!SQL_SUCCEEDED(res)) {
4038 goto bail_with_handle;
4041 if (sscanf(rowdata,
"%30d", &x) != 1) {
4046 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4063 static int message_exists(
char *dir,
int msgnum)
4071 char *argv[] = { dir, msgnums };
4072 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4081 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4082 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
4089 res = SQLFetch(stmt);
4090 if (!SQL_SUCCEEDED(res)) {
4092 goto bail_with_handle;
4095 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4096 if (!SQL_SUCCEEDED(res)) {
4098 goto bail_with_handle;
4101 if (sscanf(rowdata,
"%30d", &x) != 1) {
4106 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4129 char *argv[] = { dir };
4130 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4139 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
4146 res = SQLFetch(stmt);
4147 if (!SQL_SUCCEEDED(res)) {
4149 goto bail_with_handle;
4152 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4153 if (!SQL_SUCCEEDED(res)) {
4155 goto bail_with_handle;
4158 if (sscanf(rowdata,
"%30d", &x) != 1) {
4163 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4180 static void delete_file(
const char *sdir,
int smsg)
4185 char *argv[] = {
NULL, msgnums };
4186 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4197 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4198 snprintf(sql,
sizeof(sql),
"DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
4203 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4221 static void copy_file(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
4229 char *argv[] = { ddir, msgnumd, msg_id, dmailboxuser, dmailboxcontext, sdir, msgnums };
4230 struct generic_prepare_struct gps = { .sql = sql, .argc = 7, .argv = argv };
4240 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4241 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4242 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);
4245 ast_log(
AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4247 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4253 struct insert_data {
4256 const char *msgnums;
4261 const char *macrocontext;
4262 const char *callerid;
4263 const char *origtime;
4264 const char *duration;
4265 const char *mailboxuser;
4266 const char *mailboxcontext;
4267 const char *category;
4272 static SQLHSTMT insert_data_cb(
struct odbc_obj *obj,
void *vdata)
4274 struct insert_data *data = vdata;
4278 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4279 if (!SQL_SUCCEEDED(res)) {
4284 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0,
NULL);
4285 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0,
NULL);
4286 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (
void *) data->data, data->datalen, &data->indlen);
4287 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (
void *) data->context, 0,
NULL);
4288 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (
void *) data->macrocontext, 0,
NULL);
4289 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (
void *) data->callerid, 0,
NULL);
4290 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (
void *) data->origtime, 0,
NULL);
4291 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (
void *) data->duration, 0,
NULL);
4292 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (
void *) data->mailboxuser, 0,
NULL);
4293 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (
void *) data->mailboxcontext, 0,
NULL);
4294 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (
void *) data->flag, 0,
NULL);
4295 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (
void *) data->msg_id, 0,
NULL);
4297 SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (
void *) data->category, 0,
NULL);
4300 if (!SQL_SUCCEEDED(res)) {
4302 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4322 static int store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum)
4326 void *fdm = MAP_FAILED;
4337 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
4338 .context =
"", .macrocontext =
"", .callerid =
"", .origtime =
"", .duration =
"", .category =
"", .flag =
"", .msg_id =
"" };
4351 c = strchr(fmt,
'|');
4354 if (!strcasecmp(fmt,
"wav49"))
4356 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4361 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
4363 snprintf(full_fn,
sizeof(full_fn),
"%s.%s", fn, fmt);
4364 fd = open(full_fn, O_RDWR);
4375 idata.macrocontext =
"";
4378 idata.callerid =
"";
4381 idata.origtime =
"";
4384 idata.duration =
"";
4387 idata.category =
"";
4396 fdlen = lseek(fd, 0, SEEK_END);
4397 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
4402 fdm = mmap(
NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4403 if (fdm == MAP_FAILED) {
4409 idata.datalen = idata.indlen = fdlen;
4412 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
4414 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
4417 idata.origtime =
"0";
4421 idata.duration =
"0";
4425 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4436 if (fdm != MAP_FAILED)
4456 static void rename_file(
char *sdir,
int smsg,
char *mailboxuser,
char *mailboxcontext,
char *ddir,
int dmsg)
4463 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
4464 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4474 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4475 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4476 snprintf(sql,
sizeof(sql),
"UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
4481 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4497 static int remove_file(
char *dir,
int msgnum)
4504 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4509 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
4514 #ifndef IMAP_STORAGE 4529 struct dirent *vment =
NULL;
4534 if ((vmdir = opendir(dir))) {
4535 while ((vment = readdir(vmdir))) {
4536 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,
".txt", 4)) {
4559 snprintf(stxt,
sizeof(stxt),
"%s.txt", sfn);
4560 snprintf(dtxt,
sizeof(dtxt),
"%s.txt", dfn);
4583 struct dirent *msgdirent;
4592 if (!(msgdir = opendir(dir))) {
4596 while ((msgdirent = readdir(msgdir))) {
4597 if (sscanf(msgdirent->d_name,
"msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension,
"txt") && msgdirint <
MAXMSGLIMIT) {
4600 ast_debug(4,
"%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
4605 for (x = 0; x < vmu->
maxmsg; x++) {
4608 }
else if (map[x] == 0 && !stopcount) {
4618 #ifndef IMAP_STORAGE 4629 static int copy(
char *infile,
char *outfile)
4637 #ifdef HARDLINK_WHEN_POSSIBLE 4639 if (!link(infile, outfile)) {
4644 if ((ifd = open(infile, O_RDONLY)) < 0) {
4658 len = read(ifd, buf,
sizeof(buf));
4669 wrlen = write(ofd, buf, len);
4670 if (
errno == ENOMEM ||
errno == ENOSPC || wrlen != len) {
4698 const char *origmailbox =
"", *context =
"", *macrocontext =
"", *
exten =
"";
4699 const char *
priority =
"", *callerchan =
"", *callerid =
"", *origdate =
"";
4700 const char *origtime =
"", *category =
"", *duration =
"";
4703 snprintf(frompath2,
sizeof(frompath2),
"%s.txt", frompath);
4704 snprintf(topath2,
sizeof(topath2),
"%s.txt", topath);
4709 for (tmp = var;
tmp; tmp = tmp->
next) {
4710 if (!strcasecmp(tmp->
name,
"origmailbox")) {
4711 origmailbox = tmp->
value;
4712 }
else if (!strcasecmp(tmp->
name,
"context")) {
4713 context = tmp->
value;
4714 }
else if (!strcasecmp(tmp->
name,
"macrocontext")) {
4715 macrocontext = tmp->
value;
4716 }
else if (!strcasecmp(tmp->
name,
"exten")) {
4718 }
else if (!strcasecmp(tmp->
name,
"priority")) {
4719 priority = tmp->
value;
4720 }
else if (!strcasecmp(tmp->
name,
"callerchan")) {
4721 callerchan = tmp->
value;
4722 }
else if (!strcasecmp(tmp->
name,
"callerid")) {
4723 callerid = tmp->
value;
4724 }
else if (!strcasecmp(tmp->
name,
"origdate")) {
4725 origdate = tmp->
value;
4726 }
else if (!strcasecmp(tmp->
name,
"origtime")) {
4727 origtime = tmp->
value;
4728 }
else if (!strcasecmp(tmp->
name,
"category")) {
4729 category = tmp->
value;
4730 }
else if (!strcasecmp(tmp->
name,
"duration")) {
4731 duration = tmp->
value;
4734 ast_store_realtime(
"voicemail_data",
"filename", topath,
"origmailbox", origmailbox,
"context", context,
"macrocontext", macrocontext,
"exten",
exten,
"priority", priority,
"callerchan", callerchan,
"callerid", callerid,
"origdate", origdate,
"origtime", origtime,
"category", category,
"duration", duration,
SENTINEL);
4736 copy(frompath2, topath2);
4754 txtsize = (strlen(file) + 5)*
sizeof(
char);
4762 snprintf(txt, txtsize,
"%s.txt", file);
4797 if (!
inbuf(bio, fi))
4810 if (fputs(
ENDL, so) == EOF) {
4817 if (putc(((
unsigned char) c), so) == EOF) {
4837 static const unsigned char dtable[] = {
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
4838 'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
4839 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
4840 '1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/'};
4845 memset(&bio, 0,
sizeof(bio));
4848 if (!(fi = fopen(filename,
"rb"))) {
4854 unsigned char igroup[3], ogroup[4];
4857 memset(igroup, 0,
sizeof(igroup));
4859 for (n = 0; n < 3; n++) {
4860 if ((c =
inchar(&bio, fi)) == EOF) {
4865 igroup[n] = (
unsigned char) c;
4869 ogroup[0]= dtable[igroup[0] >> 2];
4870 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
4871 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
4872 ogroup[3]= dtable[igroup[2] & 0x3F];
4881 for (i = 0; i < 4; i++)
4882 ochar(&bio, ogroup[i], so);
4888 if (fputs(
ENDL, so) == EOF) {
4895 static void prep_email_sub_vars(
struct ast_channel *ast,
struct ast_vm_user *vmu,
int msgnum,
char *context,
char *mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *dur,
char *date,
const char *category,
const char *flag)
4899 char fromdir[256], fromfile[256];
4901 const char *origcallerid, *origtime;
4902 char origcidname[80], origcidnum[80], origdate[80];
4909 snprintf(num,
sizeof(num),
"%d", msgnum);
4923 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum - 1);
4924 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
4925 strcat(fromfile,
".txt");
4928 ast_debug(1,
"Config load for message text file '%s' failed\n", fromfile);
4934 ast_callerid_split(origcallerid, origcidname,
sizeof(origcidname), origcidnum,
sizeof(origcidnum));
4939 if ((origtime =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(origtime,
"%30d", &inttime) == 1) {
4940 struct timeval tv = { inttime, };
4963 for (ptr = from; *ptr; ptr++) {
4964 if (*ptr ==
'"' || *ptr ==
'\\') {
5004 for (; *
str; str++) {
5005 if (*str > 126 || *str < 32 || strchr(
"()<>@,:;/\"[]?.=", *str)) {
5032 int first_section = 1;
5036 for (; *start; start++) {
5037 int need_encoding = 0;
5038 if (*start < 33 || *start > 126 || strchr(
"()<>@,:;/\"[]?.=_", *start)) {
5041 if ((first_section && need_encoding && preamble +
ast_str_strlen(tmp) > 70) ||
5042 (first_section && !need_encoding && preamble +
ast_str_strlen(tmp) > 72) ||
5044 (!first_section && !need_encoding &&
ast_str_strlen(tmp) > 72)) {
5050 if (need_encoding && *start ==
' ') {
5052 }
else if (need_encoding) {
5091 const char *fromfolder,
5098 int attach_user_voicemail,
5100 const char *category,
5111 char enc_cidnum[256] =
"", enc_cidname[256] =
"";
5113 char *greeting_attachment;
5119 if (!str1 || !str2) {
5131 gethostname(host,
sizeof(host) - 1);
5133 if (strchr(srcemail,
'@')) {
5136 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5139 greeting_attachment = strrchr(
ast_strdupa(attach),
'/');
5140 if (greeting_attachment) {
5141 *greeting_attachment++ =
'\0';
5144 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5146 fprintf(p,
"Date: %s" ENDL, date);
5156 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5178 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
5184 while ((email =
strsep(&emailsbuf,
"|"))) {
5185 char *next = emailsbuf;
5203 fprintf(p,
"Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date);
5208 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5231 fprintf(p,
"Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5233 fprintf(p,
"Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5237 fprintf(p,
"Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5239 fprintf(p,
"Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5243 fprintf(p,
"Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
5244 (
unsigned int)
ast_random(), mailbox, (
int) getpid(), host);
5247 fprintf(p,
"X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
5249 fprintf(p,
"X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
5250 fprintf(p,
"X-Asterisk-VM-Context: %s" ENDL, context);
5252 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
5254 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, mailbox);
5257 fprintf(p,
"X-Asterisk-VM-Flag: %s" ENDL,
S_OR(flag,
""));
5259 fprintf(p,
"X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
5260 fprintf(p,
"X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
5261 fprintf(p,
"X-Asterisk-VM-Duration: %d" ENDL, duration);
5263 fprintf(p,
"X-Asterisk-VM-Category: %s" ENDL, category);
5265 fprintf(p,
"X-Asterisk-VM-Category: " ENDL);
5267 fprintf(p,
"X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ?
"Message" : greeting_attachment);
5268 fprintf(p,
"X-Asterisk-VM-Orig-date: %s" ENDL, date);
5269 fprintf(p,
"X-Asterisk-VM-Orig-time: %ld" ENDL, (
long) time(
NULL));
5270 fprintf(p,
"X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
5273 fprintf(p,
"X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
5276 fprintf(p,
"X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
5278 fprintf(p,
"MIME-Version: 1.0" ENDL);
5279 if (attach_user_voicemail) {
5281 snprintf(bound,
sizeof(bound),
"----voicemail_%d%s%d%u", msgnum + 1, mailbox,
5282 (
int) getpid(), (
unsigned int)
ast_random());
5284 fprintf(p,
"Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
5285 fprintf(p,
ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
5286 fprintf(p,
"--%s" ENDL, bound);
5288 fprintf(p,
"Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
5290 fprintf(p,
"This message is to let you know that your greeting '%s' was changed on %s." ENDL
5291 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL,
5292 greeting_attachment, date);
5293 }
else if (emailbody || vmu->
emailbody) {
5297 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5305 if ((next = strchr(line,
'\n'))) {
5308 fprintf(p,
"%s" ENDL, line);
5320 if (strcmp(vmu->
mailbox, mailbox)) {