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__)
568static char imapserver[48] =
"localhost";
569static char imapport[8] =
"143";
570static char imapflags[128];
571static char imapfolder[64] =
"INBOX";
572static char imapparentfolder[64];
573static char greetingfolder[64] =
"INBOX";
574static char authuser[32];
575static char authpassword[42];
576static int imapversion = 1;
578static int expungeonhangup = 1;
579static int imapgreetings;
580static int imap_poll_logout;
581static char delimiter;
592static int init_mailstream(
struct vm_state *vms,
int box);
593static void write_file(
char *filename,
char *buffer,
unsigned long len);
594static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len);
595static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu);
596static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len);
597static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive);
598static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive);
600static void vmstate_insert(
struct vm_state *vms);
601static void vmstate_delete(
struct vm_state *vms);
602static void set_update(MAILSTREAM * stream);
603static void init_vm_state(
struct vm_state *vms);
604static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro);
605static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream);
606static void mm_parsequota (MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota);
607static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int target);
608static 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);
609static 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);
610static void update_messages_by_imapuser(
const char *
user,
unsigned long number);
613static int imap_remove_file (
char *dir,
int msgnum);
614static int imap_retrieve_file (
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context);
615static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms);
618static void imap_logout(
const char *mailbox_id);
629#define SMDI_MWI_WAIT_TIMEOUT 1000
631#define COMMAND_TIMEOUT 5000
633#define VOICEMAIL_DIR_MODE 0777
634#define VOICEMAIL_FILE_MODE 0666
635#define CHUNKSIZE 65536
637#define VOICEMAIL_CONFIG "voicemail.conf"
638#define ASTERISK_USERNAME "asterisk"
643#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
644#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
645#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
646#define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
647#define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
648#define VALID_DTMF "1234567890*#"
652#define SENDMAIL "/usr/sbin/sendmail -t"
653#define INTRO "vm-intro"
655#define MAX_MAIL_BODY_CONTENT_SIZE 134217728L
658#define MAXMSGLIMIT 9999
668#define MAX_DATETIME_FORMAT 512
669#define MAX_NUM_CID_CONTEXTS 10
671#define VM_REVIEW (1 << 0)
672#define VM_OPERATOR (1 << 1)
673#define VM_SAYCID (1 << 2)
674#define VM_SVMAIL (1 << 3)
675#define VM_ENVELOPE (1 << 4)
676#define VM_SAYDURATION (1 << 5)
677#define VM_SKIPAFTERCMD (1 << 6)
678#define VM_FORCENAME (1 << 7)
679#define VM_FORCEGREET (1 << 8)
680#define VM_PBXSKIP (1 << 9)
681#define VM_DIRECTFORWARD (1 << 10)
682#define VM_ATTACH (1 << 11)
683#define VM_DELETE (1 << 12)
684#define VM_ALLOCED (1 << 13)
685#define VM_SEARCH (1 << 14)
686#define VM_TEMPGREETWARN (1 << 15)
687#define VM_MOVEHEARD (1 << 16)
688#define VM_MESSAGEWRAP (1 << 17)
689#define VM_FWDURGAUTO (1 << 18)
690#define VM_EMAIL_EXT_RECS (1 << 19)
691#define VM_MARK_URGENT (1 << 20)
692#define VM_ODBC_AUDIO_ON_DISK (1 << 21)
694#define ERROR_LOCK_PATH -100
695#define ERROR_MAX_MSGS -101
696#define OPERATOR_EXIT 300
698#define MSGFILE_LEN (7)
785#define force_reload_config() load_config_force(1, 1)
885#define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
886#define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
888#define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
923 char imappassword[80];
925 char imapvmshareid[80];
940#define VMSTATE_MAX_MSG_ARRAY 256
965 unsigned msg_array_max;
966 MAILSTREAM *mailstream;
976 unsigned int quota_limit;
977 unsigned int quota_usage;
983static char odbc_database[80] =
"asterisk";
984static char odbc_table[80] =
"voicemessages";
985size_t odbc_table_len =
sizeof(odbc_table);
986#define COUNT(a, b) odbc_count_messages(a,b)
987#define LAST_MSG_INDEX(a) odbc_last_message_index(a)
988#define RETRIEVE(a,b,c,d) odbc_retrieve_message(a,b)
989#define DISPOSE(a,b) odbc_remove_files(a,b)
990#define STORE(a,b,c,d,e,f,g,h,i,j,k) odbc_store_message(a,b,c,d)
991#define EXISTS(a,b,c,d) (odbc_message_exists(a,b))
992#define RENAME(a,b,c,d,e,f,g,h) (odbc_rename_message(a,b,c,d,e,f))
993#define COPY(a,b,c,d,e,f,g,h) (odbc_copy_message(a,b,c,d,e,f))
994#define DELETE(a,b,c,d) (odbc_delete_message(a,b))
995#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
998#define DISPOSE(a,b) (imap_remove_file(a,b))
999#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))
1000#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
1001#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1002#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1003#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
1004#define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
1005#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
1007#define COUNT(a, b) count_messages(a,b)
1008#define LAST_MSG_INDEX(a) last_message_index(a)
1009#define RETRIEVE(a,b,c,d)
1011#define STORE(a,b,c,d,e,f,g,h,i,j,k)
1012#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1013#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1014#define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
1015#define DELETE(a,b,c,d) (vm_delete(c))
1016#define UPDATE_MSG_ID(a, b, c, d, e, f)
1027#define PWDCHANGE_INTERNAL (1 << 1)
1028#define PWDCHANGE_EXTERNAL (1 << 2)
1032#define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
1035# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
1037# define tdesc "Comedian Mail (Voicemail System)"
1085#define DEFAULT_POLL_FREQ 30
1108#define MAPPING_BUCKETS 511
1166static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
1167static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
1178 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
1179 signed char record_gain,
struct vm_state *vms,
char *
flag,
const char *msg_id,
int forwardintro);
1183static 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);
1215static 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);
1216static 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);
1220#ifdef TEST_FRAMEWORK
1221static int vm_test_destroy_user(
const char *
context,
const char *
mailbox);
1222static int vm_test_create_user(
const char *
context,
const char *
mailbox);
1270 if (strcmp(i->
mailbox, j->mailbox)) {
1278 int context_len = strlen(
context) + 1;
1279 int mailbox_len = strlen(
mailbox) + 1;
1294 if (!(i =
ao2_alloc(
sizeof(*i) + context_len + mailbox_len,
NULL))) {
1308#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1326 if (bufptr ==
buf + buflen - 1) {
1353static size_t get_msg_path_len(
const char *dir)
1367#define MAX_SOUND_EXTEN_LEN 12
1380static size_t get_msg_path_ext_len(
const char *dir)
1386 return strlen(dir) + 1 +
MSGFILE_LEN + MAX_SOUND_EXTEN_LEN + 1;
1410#define MAKE_FILE_PTRA(dir, msgnum) \
1412 size_t __len = get_msg_path_len(dir); \
1415 __var = ast_strdupa(dir); \
1417 __var = ast_alloca(__len); \
1418 snprintf(__var, __len, "%s/msg%04d", dir, msgnum); \
1452#define MAKE_FILE_EXT_PTRA(dir, msgnum, ext) \
1454 size_t __len = get_msg_path_ext_len(dir); \
1455 char *__var = ast_alloca(__len); \
1457 snprintf(__var, __len, "%s.%s", dir, ext); \
1459 snprintf(__var, __len, "%s/msg%04d.%s", dir, msgnum, ext); \
1510 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1511 ast_copy_string(vmu->imapserver, imapserver,
sizeof(vmu->imapserver));
1528 if (!strcasecmp(
var,
"attach")) {
1530 }
else if (!strcasecmp(
var,
"attachfmt")) {
1532 }
else if (!strcasecmp(
var,
"attachextrecs")) {
1534 }
else if (!strcasecmp(
var,
"serveremail")) {
1536 }
else if (!strcasecmp(
var,
"fromstring")) {
1538 }
else if (!strcasecmp(
var,
"emailbody")) {
1541 }
else if (!strcasecmp(
var,
"emailsubject")) {
1544 }
else if (!strcasecmp(
var,
"language")) {
1546 }
else if (!strcasecmp(
var,
"tz")) {
1548 }
else if (!strcasecmp(
var,
"locale")) {
1551 }
else if (!strcasecmp(
var,
"imapuser")) {
1553 vmu->imapversion = imapversion;
1554 }
else if (!strcasecmp(
var,
"imapserver")) {
1556 vmu->imapversion = imapversion;
1557 }
else if (!strcasecmp(
var,
"imapport")) {
1559 vmu->imapversion = imapversion;
1560 }
else if (!strcasecmp(
var,
"imapflags")) {
1562 vmu->imapversion = imapversion;
1563 }
else if (!strcasecmp(
var,
"imappassword") || !strcasecmp(
var,
"imapsecret")) {
1565 vmu->imapversion = imapversion;
1566 }
else if (!strcasecmp(
var,
"imapfolder")) {
1568 vmu->imapversion = imapversion;
1569 }
else if (!strcasecmp(
var,
"imapvmshareid")) {
1571 vmu->imapversion = imapversion;
1573 }
else if (!strcasecmp(
var,
"delete") || !strcasecmp(
var,
"deletevoicemail")) {
1575 }
else if (!strcasecmp(
var,
"saycid")){
1577 }
else if (!strcasecmp(
var,
"sendvoicemail")){
1579 }
else if (!strcasecmp(
var,
"review")){
1581 }
else if (!strcasecmp(
var,
"leaveurgent")){
1583 }
else if (!strcasecmp(
var,
"tempgreetwarn")){
1585 }
else if (!strcasecmp(
var,
"messagewrap")){
1587 }
else if (!strcasecmp(
var,
"operator")) {
1589 }
else if (!strcasecmp(
var,
"envelope")){
1591 }
else if (!strcasecmp(
var,
"moveheard")){
1593 }
else if (!strcasecmp(
var,
"sayduration")){
1595 }
else if (!strcasecmp(
var,
"saydurationm")){
1596 if (sscanf(
value,
"%30d", &x) == 1) {
1601 }
else if (!strcasecmp(
var,
"forcename")){
1603 }
else if (!strcasecmp(
var,
"forcegreetings")){
1605 }
else if (!strcasecmp(
var,
"callback")) {
1607 }
else if (!strcasecmp(
var,
"dialout")) {
1609 }
else if (!strcasecmp(
var,
"exitcontext")) {
1611 }
else if (!strcasecmp(
var,
"minsecs")) {
1612 if (sscanf(
value,
"%30d", &x) == 1 && x >= 0) {
1618 }
else if (!strcasecmp(
var,
"maxmessage") || !strcasecmp(
var,
"maxsecs")) {
1626 if (!strcasecmp(
var,
"maxmessage"))
1627 ast_log(
AST_LOG_WARNING,
"Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1628 }
else if (!strcasecmp(
var,
"maxmsg")) {
1638 }
else if (!strcasecmp(
var,
"nextaftercmd")) {
1640 }
else if (!strcasecmp(
var,
"backupdeleted")) {
1641 if (sscanf(
value,
"%30d", &x) == 1)
1655 }
else if (!strcasecmp(
var,
"volgain")) {
1657 }
else if (!strcasecmp(
var,
"passwordlocation")) {
1658 if (!strcasecmp(
value,
"spooldir")) {
1663 }
else if (!strcasecmp(
var,
"options")) {
1670 int fds[2], pid = 0;
1675 snprintf(
buf,
len,
"FAILURE: Pipe failed: %s", strerror(
errno));
1684 snprintf(
buf,
len,
"FAILURE: Fork failed");
1688 if (read(fds[0],
buf,
len) < 0) {
1700 dup2(fds[1], STDOUT_FILENO);
1706 execv(arg.v[0], arg.v);
1707 printf(
"FAILURE: %s", strerror(
errno));
1730 char cmd[255],
buf[255];
1732 ast_debug(1,
"Verify password policies for %s\n", password);
1737 if (!strncasecmp(
buf,
"VALID", 5)) {
1740 }
else if (!strncasecmp(
buf,
"FAILURE", 7)) {
1765 if (!strcmp(vmu->
password, password)) {
1770 if (strlen(password) > 10) {
1790 while ((s =
strsep(&stringp,
"|"))) {
1806 if (!strcasecmp(
var->name,
"vmsecret")) {
1808 }
else if (!strcasecmp(
var->name,
"secret") || !strcasecmp(
var->name,
"password")) {
1812 "\n\tmust be reset in voicemail.conf.\n",
retval->mailbox);
1817 }
else if (!strcasecmp(
var->name,
"uniqueid")) {
1819 }
else if (!strcasecmp(
var->name,
"pager")) {
1821 }
else if (!strcasecmp(
var->name,
"email")) {
1824 }
else if (!strcasecmp(
var->name,
"fullname")) {
1826 }
else if (!strcasecmp(
var->name,
"context")) {
1828 }
else if (!strcasecmp(
var->name,
"emailsubject")) {
1831 }
else if (!strcasecmp(
var->name,
"emailbody")) {
1835 }
else if (!strcasecmp(
var->name,
"imapuser")) {
1837 retval->imapversion = imapversion;
1838 }
else if (!strcasecmp(
var->name,
"imapserver")) {
1840 retval->imapversion = imapversion;
1841 }
else if (!strcasecmp(
var->name,
"imapport")) {
1843 retval->imapversion = imapversion;
1844 }
else if (!strcasecmp(
var->name,
"imapflags")) {
1846 retval->imapversion = imapversion;
1847 }
else if (!strcasecmp(
var->name,
"imappassword") || !strcasecmp(
var->name,
"imapsecret")) {
1849 retval->imapversion = imapversion;
1850 }
else if (!strcasecmp(
var->name,
"imapfolder")) {
1852 retval->imapversion = imapversion;
1853 }
else if (!strcasecmp(
var->name,
"imapvmshareid")) {
1855 retval->imapversion = imapversion;
1874 for (i = 0; i < strlen(key); ++i) {
1946 if (cur->imapversion != imapversion) {
1957 if ((vmu = (ivm ? ivm :
ast_calloc(1,
sizeof(*vmu))))) {
1984 char *search_mailbox =
NULL;
1985 char *search_context =
NULL;
1989 vmu =
find_user(ivm, search_mailbox, search_context);
2028 "NewPassword", newpass);
2055 char *category =
NULL;
2070 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
2075 ast_log(
LOG_WARNING,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2081 if (!strcasecmp(category, vmu->
context)) {
2091 sprintf(
new,
"%s", newpassword);
2094 sprintf(
new,
"%s%s", newpassword,
value);
2108 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2125 ast_debug(4,
"users.conf: %s\n", category);
2126 if (!strcasecmp(category, vmu->
mailbox)) {
2127 char new[strlen(newpassword) + 1];
2129 ast_debug(3,
"looks like we need to make vmsecret!\n");
2135 sprintf(
new,
"%s", newpassword);
2137 ast_debug(4,
"failed to get category!\n");
2206static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
2208 return snprintf(dest,
len,
"%s/msg%04d", dir, num);
2235 if (vmu &&
id == 0) {
2236 return vmu->imapfolder;
2294 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
2307 if (arraysize > 0) {
2325static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu)
2329 unsigned long messageNum;
2332 if (msgnum < 0 && !imapgreetings) {
2337 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2338 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);
2343 imap_delete_old_greeting(
file, vms);
2349 messageNum = vms->msgArray[msgnum];
2350 if (messageNum == 0) {
2351 ast_log(
LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2354 ast_debug(3,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2356 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
2358 mail_setflag (vms->mailstream, arg,
"\\DELETED");
2359 mail_expunge(vms->mailstream);
2363static 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)
2370 const char *duration_str;
2414 sscanf(duration_str,
"%30d", &duration);
2430 vm_imap_delete(dir, msgnum, vmu);
2436static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
2439 char *
file, *filename;
2449 if (msgnum > -1 || !imapgreetings) {
2456 ast_debug(1,
"Failed to procure file name from directory passed.\n");
2462 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
2463 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2468 if (!(vms_p = create_vm_state_from_user(vmu))) {
2475 *vms_p->introfn =
'\0';
2489 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2490 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2492 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2493 char *attachment = body->nested.part->next->body.parameter->value;
2494 char copy[strlen(attachment) + 1];
2496 strcpy(
copy, attachment);
2499 filename =
strsep(&attachment,
".");
2500 if (!strcmp(filename,
file)) {
2502 vms_p->msgArray[vms_p->
curmsg] = i + 1;
2504 save_body(body, vms_p,
"2", attachment, 0);
2515 if (curr_mbox != -1) {
2517 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2526static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context)
2529 char *header_content;
2530 char *attachedfilefmt;
2534 FILE *text_file_ptr;
2545 if (imapgreetings) {
2546 res = imap_retrieve_greeting(dir, msgnum, vmu);
2557 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2572 if (curr_mbox < 0) {
2573 ast_debug(3,
"Mailbox folder curbox not set, defaulting to Inbox\n");
2576 init_mailstream(vms, curr_mbox);
2577 if (!vms->mailstream) {
2584 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->
fn);
2592 ast_debug(3,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2593 if (vms->msgArray[msgnum] == 0) {
2601 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2605 ast_log(
LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2611 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2615 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2616 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2625 strsep(&attachedfilefmt,
".");
2626 if (!attachedfilefmt) {
2627 ast_log(
LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2632 save_body(body, vms,
"2", attachedfilefmt, 0);
2633 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2634 *vms->introfn =
'\0';
2638 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->
fn,
"txt");
2640 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2645 fprintf(text_file_ptr,
"%s\n",
"[message]");
2647 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:",
buf,
sizeof(
buf))) {
2648 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(
buf,
""));
2650 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:",
buf,
sizeof(
buf))) {
2651 fprintf(text_file_ptr,
"<%s>\n",
S_OR(
buf,
""));
2653 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Context:",
buf,
sizeof(
buf))) {
2654 fprintf(text_file_ptr,
"context=%s\n",
S_OR(
buf,
""));
2656 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:",
buf,
sizeof(
buf))) {
2657 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(
buf,
""));
2659 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:",
buf,
sizeof(
buf))) {
2660 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(
buf,
""));
2662 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Category:",
buf,
sizeof(
buf))) {
2663 fprintf(text_file_ptr,
"category=%s\n",
S_OR(
buf,
""));
2665 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:",
buf,
sizeof(
buf))) {
2666 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(
buf,
""));
2668 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Message-ID:",
buf,
sizeof(
buf))) {
2669 fprintf(text_file_ptr,
"msg_id=%s\n",
S_OR(
buf,
""));
2671 fclose(text_file_ptr);
2678static int folder_int(
const char *folder)
2684 if (!strcasecmp(folder, imapfolder)) {
2686 }
else if (!strcasecmp(folder,
"Old")) {
2688 }
else if (!strcasecmp(folder,
"Work")) {
2690 }
else if (!strcasecmp(folder,
"Family")) {
2692 }
else if (!strcasecmp(folder,
"Friends")) {
2694 }
else if (!strcasecmp(folder,
"Cust1")) {
2696 }
else if (!strcasecmp(folder,
"Cust2")) {
2698 }
else if (!strcasecmp(folder,
"Cust3")) {
2700 }
else if (!strcasecmp(folder,
"Cust4")) {
2702 }
else if (!strcasecmp(folder,
"Cust5")) {
2704 }
else if (!strcasecmp(folder,
"Urgent")) {
2711static int __messagecount(
const char *
context,
const char *
mailbox,
const char *folder)
2719 int fold = folder_int(folder);
2732 memset(&vmus, 0,
sizeof(vmus));
2740 if (vmu->imapuser[0] ==
'\0') {
2748 if (vmu->imapuser[0] ==
'\0') {
2755 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2760 ast_debug(3,
"Returning before search - user is logged in\n");
2772 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2778 vms_p = create_vm_state_from_user(vmu);
2780 ret = init_mailstream(vms_p, fold);
2781 if (!vms_p->mailstream) {
2788 pgm = mail_newsearchpgm ();
2789 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid :
mailbox));
2790 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(
context,
"default"));
2816 vms_p->vmArrayIndex = 0;
2817 mail_search_full (vms_p->mailstream,
NULL, pgm, NIL);
2818 if (fold == 0 && urgent == 0)
2822 if (fold == 0 && urgent == 1)
2825 mail_free_searchpgm(&pgm);
2829 return vms_p->vmArrayIndex;
2832 mail_ping(vms_p->mailstream);
2842 check_quota(vms, vmu->imapfolder);
2843 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2844 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2854 ast_log(
LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2873static int messagecount(
const char *mailbox_id,
const char *folder)
2889 return count < 0 ? 0 : count;
2892static 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)
2900 char tmp[80] =
"/tmp/astmail-XXXXXX";
2906 char *imap_flags = NIL;
2915 if(!imapgreetings) {
2922 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2928 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2929 imap_flags =
"\\FLAGGED";
2945 snprintf(introfn,
sizeof(introfn),
"%sintro",
fn);
2960 if (!strcmp(fmt,
"wav49"))
2962 ast_debug(3,
"Storing file '%s', format '%s'\n",
fn, fmt);
2975 if (msgnum < 0 && imapgreetings) {
2980 imap_delete_old_greeting(
fn, vms);
2986 fn, introfn, fmt, duration, 1, chan,
NULL, 1,
flag, msg_id);
2994 *(vmu->
email) =
'\0';
3003 ((
char *)
buf)[
len] =
'\0';
3005 ret = init_mailstream(vms, box);
3009 if(!mail_append_full(vms->mailstream,
mailbox, imap_flags, NIL, &
str))
3025 *(vmu->
email) =
'\0';
3044static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
3059 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
3066 if (strchr(mailbox_context,
',')) {
3067 int tmpnew, tmpold, tmpurgent;
3070 while ((cur =
strsep(&mb,
", "))) {
3080 *urgentmsgs += tmpurgent;
3092 mailboxnc = (
char *) mailbox_context;
3101 if ((count = __messagecount(
context, mailboxnc, vmu->imapfolder)) < 0) {
3109 if ((count = __messagecount(
context, mailboxnc,
"Old")) < 0) {
3115 if ((count = __messagecount(
context, mailboxnc,
"Urgent")) < 0) {
3118 *urgentmsgs = count;
3138 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
3139 while ((box =
strsep(&tmp2,
",&"))) {
3152 return __messagecount(
context,
tmp, folder) > 0 ? 1 : 0;
3174 char messagestring[10];
3175 if (msgnum >= recip->
maxmsg) {
3179 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
3183 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
3187 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
3189 if ((mail_copy(sendvms->mailstream, messagestring, (
char *)
mbox(vmu, imbox)) == T)) {
3198static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
3201 size_t left =
sizeof(
tmp);
3234 snprintf(spec,
len,
"%s%s",
tmp, use_folder? vms->imapfolder:
"INBOX");
3236 snprintf(spec,
len,
"%s%s",
tmp, greetingfolder);
3240 snprintf(spec,
len,
"%s%s%c%s",
tmp, imapparentfolder, delimiter,
mbox(
NULL, box));
3247static int init_mailstream(
struct vm_state *vms,
int box)
3249 MAILSTREAM *stream = NIL;
3257 ast_debug(3,
"vm_state user is:%s\n", vms->imapuser);
3258 if (vms->mailstream == NIL || !vms->mailstream) {
3261 stream = vms->mailstream;
3266 if (delimiter ==
'\0') {
3268#ifdef USE_SYSTEM_IMAP
3269#include <imap/linkage.c>
3270#elif defined(USE_SYSTEM_CCLIENT)
3271#include <c-client/linkage.c>
3276 imap_mailbox_name(
tmp,
sizeof(
tmp), vms, 0, 1);
3279 stream = mail_open (stream,
tmp,
debug ? OP_DEBUG : NIL);
3282 if (stream == NIL) {
3286 get_mailbox_delimiter(vms, stream);
3288 for (cp = vms->imapfolder; *cp; cp++)
3293 imap_mailbox_name(
tmp,
sizeof(
tmp), vms, box, 1);
3294 ast_debug(3,
"Before mail_open, server: %s, box:%d\n",
tmp, box);
3297 vms->mailstream = mail_open (stream,
tmp,
debug ? OP_DEBUG : NIL);
3299 if (vms->mailstream && !mail_status(vms->mailstream,
tmp, SA_UIDNEXT)) {
3300 mail_create(vms->mailstream,
tmp);
3304 if (vms->mailstream == NIL) {
3324 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
3325 ast_copy_string(vms->imapserver, vmu->imapserver,
sizeof(vms->imapserver));
3327 ast_copy_string(vms->imapflags, vmu->imapflags,
sizeof(vms->imapflags));
3328 vms->imapversion = vmu->imapversion;
3329 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
3331 if (init_mailstream(vms, box) || !vms->mailstream) {
3340 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n",
mbox(vmu, box));
3341 check_quota(vms, (
char *)
mbox(vmu, box));
3345 pgm = mail_newsearchpgm();
3348 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
3349 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
3360 }
else if (box ==
NEW_FOLDER && urgent == 0) {
3370 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
3372 vms->vmArrayIndex = 0;
3373 mail_search_full (vms->mailstream,
NULL, pgm, NIL);
3374 vms->
lastmsg = vms->vmArrayIndex - 1;
3375 mail_free_searchpgm(&pgm);
3381 ast_log(
LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
3392static void write_file(
char *filename,
char *buffer,
unsigned long len)
3396 if (!filename || !buffer) {
3400 if (!(output = fopen(filename,
"w"))) {
3405 if (fwrite(buffer,
len, 1, output) != 1) {
3406 if (ferror(output)) {
3413static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
3415 struct vm_state *vms = get_vm_state_by_imapuser(
user, 1);
3417 if (!vms && !(vms = get_vm_state_by_imapuser(
user, 0))) {
3421 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n",
number, vms->vmArrayIndex, vms->interactive);
3424 if (vms->vmArrayIndex >= vms->msg_array_max) {
3425 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
3429 vms->msgArray = new_mem;
3430 vms->msg_array_max *= 2;
3433 vms->msgArray[vms->vmArrayIndex++] =
number;
3436void mm_searched(MAILSTREAM *stream,
unsigned long number)
3446static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
3471void mm_exists(MAILSTREAM * stream,
unsigned long number)
3480void mm_expunged(MAILSTREAM * stream,
unsigned long number)
3489void mm_flags(MAILSTREAM * stream,
unsigned long number)
3498void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
3500 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
3501 mm_log (
string, errflg);
3505void mm_list(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3507 if (delimiter ==
'\0') {
3512 if (attributes & LATT_NOINFERIORS)
3514 if (attributes & LATT_NOSELECT)
3516 if (attributes & LATT_MARKED)
3518 if (attributes & LATT_UNMARKED)
3523void mm_lsub(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3526 if (attributes & LATT_NOINFERIORS)
3528 if (attributes & LATT_NOSELECT)
3530 if (attributes & LATT_MARKED)
3532 if (attributes & LATT_UNMARKED)
3537void mm_status(MAILSTREAM * stream,
char *
mailbox, MAILSTATUS *
status)
3546 if (
status->flags & SA_MESSAGES) {
3549 if (
status->flags & SA_RECENT) {
3552 if (
status->flags & SA_UNSEEN) {
3555 if (
status->flags & SA_UIDVALIDITY) {
3558 if (
status->flags & SA_UIDNEXT) {
3567void mm_log(
char *
string,
long errflg)
3569 switch ((
short) errflg) {
3571 ast_debug(1,
"IMAP Info: %s\n",
string);
3584void mm_dlog(
char *
string)
3590void mm_login(NETMBX * mb,
char *
user,
char *pwd,
long trial)
3594 ast_debug(4,
"Entering callback mm_login\n");
3603 if (!strcasecmp(mb->user, vmu->imapuser)) {
3609 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3618void mm_critical(MAILSTREAM * stream)
3623void mm_nocritical(MAILSTREAM * stream)
3628long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
3630 kill (getpid (), SIGSTOP);
3635void mm_fatal(
char *
string)
3641static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
3645 char buf[1024] =
"";
3646 unsigned long usage = 0, limit = 0;
3649 usage = pquota->usage;
3650 limit = pquota->limit;
3651 pquota = pquota->next;
3654 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)))) {
3661 vms->quota_usage =
usage;
3662 vms->quota_limit = limit;
3665static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len)
3667 char *start, *eol_pnt;
3673 taglen = strlen(tag) + 1;
3684 if ((eol_pnt = strchr(
buf,
'\r')) || (eol_pnt = strchr(
buf,
'\n')))
3689static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len)
3691 char *start, *eol_pnt, *
quote;
3696 if (!(start = strstr(
mailbox,
"/user=")))
3702 if ((eol_pnt = strchr(
buf,
'/')) || (eol_pnt = strchr(
buf,
'}'))) {
3707 if ((eol_pnt = strchr(
quote + 1,
'"'))) {
3718 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3719 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->
username, vmu->
mailbox)) {
3722 ast_debug(5,
"Adding new vmstate for %s\n", vmu->imapuser);
3724 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3726 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3727 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3728 ast_copy_string(vms_p->imapserver, vmu->imapserver,
sizeof(vms_p->imapserver));
3729 ast_copy_string(vms_p->imapport, vmu->imapport,
sizeof(vms_p->imapport));
3730 ast_copy_string(vms_p->imapflags, vmu->imapflags,
sizeof(vms_p->imapflags));
3733 vms_p->mailstream = NIL;
3734 vms_p->imapversion = vmu->imapversion;
3735 ast_debug(5,
"Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3739 init_vm_state(vms_p);
3740 vmstate_insert(vms_p);
3744static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive)
3746 struct vmstate *vlist =
NULL;
3750 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3751 if ((vms = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms->imapuser,
user)) {
3762 if (vlist->vms->imapversion != imapversion) {
3766 if (!strcmp(vlist->vms->imapuser,
user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3778static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive)
3781 struct vmstate *vlist =
NULL;
3782 const char *local_context =
S_OR(
context,
"default");
3786 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3787 if ((vms = pthread_getspecific(ts_vmstate.key)) &&
3799 if (vlist->vms->imapversion != imapversion) {
3803 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);
3805 if (!strcmp(vlist->vms->username,
mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3818static void vmstate_insert(
struct vm_state *vms)
3826 if (vms->interactive == 1) {
3832 vms->vmArrayIndex = altvms->vmArrayIndex;
3837 vms->persist_vms = altvms;
3839#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3840 vms->mailstream = altvms->mailstream;
3842 vms->mailstream = NIL;
3853 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3860static void vmstate_delete(
struct vm_state *vms)
3862 struct vmstate *vc =
NULL;
3867 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3871 altvms->updated = 1;
3872 vms->mailstream = mail_close(vms->mailstream);
3878 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3882 if (vc->vms == vms) {
3893 vc->vms->msgArray =
NULL;
3894 vc->vms->msg_array_max = 0;
3902static void set_update(MAILSTREAM * stream)
3906 char buf[1024] =
"";
3908 if (!(
user = get_user_by_mailbox(
mailbox,
buf,
sizeof(
buf))) || !(vms = get_vm_state_by_imapuser(
user, 0))) {
3919static void init_vm_state(
struct vm_state *vms)
3922 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3923 if (!vms->msgArray) {
3925 vms->msg_array_max = 0;
3927 vms->vmArrayIndex = 0;
3931static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro)
3935 char *
fn = is_intro ? vms->introfn : vms->
fn;
3936 unsigned long len = 0;
3937 unsigned long newlen = 0;
3940 if (!body || body == NIL)
3944 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->
curmsg], section, &
len);
3948 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
3952 if (body_content != NIL &&
len) {
3953 snprintf(filename,
sizeof(filename),
"%s.%s",
fn, format);
3955 body_decoded = rfc822_base64((
unsigned char *) body_content,
len, &newlen);
3957 if (!newlen || !body_decoded) {
3960 write_file(filename, (
char *) body_decoded, newlen);
3962 ast_debug(5,
"Body of message is NULL.\n");
3976static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream) {
3978 snprintf(
tmp,
sizeof(
tmp),
"{%s}",
S_OR(vms->imapserver, imapserver));
3979 mail_list(stream,
tmp,
"*");
3991 mail_parameters(
NULL, SET_QUOTA, (
void *) mm_parsequota);
3993 if (vms && vms->mailstream !=
NULL) {
3994 imap_getquotaroot(vms->mailstream,
mailbox);
4017#define MSG_ID_LEN 256
4040#define MAKE_SQL_PTRA(__sql_fmt) \
4043 char *__sql = ast_alloca(strlen(__sql_fmt) + odbc_table_len); \
4044 sprintf(__sql, __sql_fmt, odbc_table); \
4058#define MAKE_SQL_PTRA2(__sql_fmt) \
4061 char *__sql = ast_alloca(strlen(__sql_fmt) + (odbc_table_len * 2)); \
4062 sprintf(__sql, __sql_fmt, odbc_table, odbc_table); \
4066struct generic_prepare_struct {
4074 struct generic_prepare_struct *gps = data;
4078 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4079 if (!SQL_SUCCEEDED(res)) {
4084 if (!SQL_SUCCEEDED(res)) {
4086 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4089 for (i = 0; i < gps->argc; i++)
4090 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0,
NULL);
4095static void odbc_update_msg_id(
char *dir,
int msg_num,
char *msg_id)
4098 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?");
4100 char msg_num_str[20];
4101 char *argv[] = { msg_id, dir, msg_num_str };
4102 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
4103 SCOPE_ENTER(3,
"dir: %s msg_num: %d msg_id: %s\n", dir, msg_num, msg_id);
4110 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4115 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4121#define AUDIO_ON_DISK_MAGIC "AUDMAGIC"
4122#define AUDIO_ON_DISK_MAGIC_LEN 8
4124static void odbc_update_set_audmagic(
char *dir,
int msg_num)
4127 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET recording=? WHERE dir=? AND msgnum=?");
4129 SQLLEN datalen = AUDIO_ON_DISK_MAGIC_LEN;
4130 SQLLEN indlen = datalen;
4132 char msg_num_str[20];
4133 SCOPE_ENTER(3,
"dir: %s msg_num: %d\n", dir, msg_num);
4140 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4141 if (!SQL_SUCCEEDED(res)) {
4146 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4148 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
4149 datalen, 0, (
void *) AUDIO_ON_DISK_MAGIC,
4152 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4153 strlen(dir), 0, (
void *) dir, 0,
NULL);
4155 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4156 strlen(msg_num_str), 0, (
void *) msg_num_str, 0,
NULL);
4159 if (!SQL_SUCCEEDED(res)) {
4163 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4170static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum);
4186static int odbc_retrieve_message(
char *dir,
int msgnum)
4192 void *fdm = MAP_FAILED;
4193 SQLSMALLINT colcount = 0;
4195 char *sql = MAKE_SQL_PTRA(
"SELECT * FROM %s WHERE dir=? AND msgnum=?");
4200 SQLSMALLINT datatype;
4201 SQLSMALLINT decimaldigits;
4202 SQLSMALLINT nullable;
4207 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4208 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4210 char *mailboxuser =
NULL;
4211 char *mailboxcontext =
NULL;
4213 char *argv[] = { dir, msgnums };
4214 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4216 int storage_conversion_to_disk = 0;
4217 int storage_conversion_to_odbc = 0;
4218 SCOPE_ENTER(3,
"dir: %s msgnum: %d msgtype: %s\n", dir, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4226 c = strchr(fmt,
'|');
4229 if (!strcasecmp(fmt,
"wav49"))
4232 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4234 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4235 if (!(f = fopen(full_fn,
"w+"))) {
4240 sprintf(full_fn,
"%s.%s", fn, fmt);
4248 res = SQLFetch(stmt);
4249 if (!SQL_SUCCEEDED(res)) {
4250 if (res != SQL_NO_DATA) {
4253 goto bail_with_handle;
4256 res = SQLNumResultCols(stmt, &colcount);
4257 if (!SQL_SUCCEEDED(res)) {
4259 goto bail_with_handle;
4262 fprintf(f,
"[message]\n");
4263 for (x = 0; x < colcount; x++) {
4266 collen =
sizeof(coltitle);
4267 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
4268 &datatype, &colsize, &decimaldigits, &nullable);
4269 if (!SQL_SUCCEEDED(res)) {
4271 goto bail_with_handle;
4274 if (!strcasecmp(coltitle,
"recording")) {
4278 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
4280 ast_trace(-1,
"Audio size: %ld\n", colsize2);
4281 if (colsize2 == AUDIO_ON_DISK_MAGIC_LEN) {
4282 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, AUDIO_ON_DISK_MAGIC_LEN,
NULL);
4283 if (memcmp(rowdata, AUDIO_ON_DISK_MAGIC, AUDIO_ON_DISK_MAGIC_LEN) != 0) {
4285 rowdata[0], rowdata[1], rowdata[2], rowdata[3], rowdata[4], rowdata[5], rowdata[6],
4286 rowdata[7], full_fn);
4287 goto bail_with_handle;
4289 ast_trace(-1,
"Audio is stored on disk. No need to write '%s'\n", full_fn);
4291 storage_conversion_to_odbc = 1;
4297 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4301 goto bail_with_handle;
4304 storage_conversion_to_disk = 1;
4307 lseek(fd, fdlen - 1, SEEK_SET);
4308 if (write(fd,
tmp, 1) != 1) {
4314 for (offset = 0; offset < colsize2; offset +=
CHUNKSIZE) {
4315 if ((fdm = mmap(
NULL,
CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
4317 goto bail_with_handle;
4319 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm,
CHUNKSIZE,
NULL);
4321 if (!SQL_SUCCEEDED(res)) {
4324 goto bail_with_handle;
4327 if (truncate(full_fn, fdlen) < 0) {
4330 ast_trace(-1,
"Wrote %d bytes to '%s'\n", (
int)fdlen, full_fn);
4332 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4333 if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"msg_id")) {
4339 ast_trace(-1,
"msg_id was NULL. Generating new one: %s\n", msg_id);
4340 snprintf(rowdata,
sizeof(rowdata),
"%s", msg_id);
4341 }
else if (!strcasecmp(coltitle,
"mailboxuser")) {
4343 }
else if (!strcasecmp(coltitle,
"mailboxcontext")) {
4345 }
else if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"category")) {
4347 ast_trace(-1,
"Ignoring null category column in ODBC voicemail retrieve_file.\n");
4349 }
else if (!SQL_SUCCEEDED(res)) {
4351 goto bail_with_handle;
4353 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir")) {
4354 fprintf(f,
"%s=%s\n", coltitle, rowdata);
4360 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4374 odbc_update_msg_id(dir, msgnum, msg_id);
4377 if (SQL_SUCCEEDED(res)) {
4378 if (storage_conversion_to_disk) {
4384 SCOPE_CALL(-1, odbc_update_set_audmagic, dir, msgnum);
4386 if (storage_conversion_to_odbc) {
4393 SCOPE_CALL(-1, odbc_store_message, dir, mailboxuser, mailboxcontext, msgnum);
4409static int odbc_last_message_index(
char *dir)
4414 char *sql = MAKE_SQL_PTRA(
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc");
4416 char *argv[] = { dir };
4417 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4432 res = SQLFetch(stmt);
4433 if (!SQL_SUCCEEDED(res)) {
4434 if (res == SQL_NO_DATA) {
4435 ast_trace(-1,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4439 goto bail_with_handle;
4442 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4443 if (!SQL_SUCCEEDED(res)) {
4445 goto bail_with_handle;
4448 if (sscanf(rowdata,
"%30d", &x) != 1) {
4453 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4470static int odbc_message_exists(
char *dir,
int msgnum)
4475 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?");
4478 char *argv[] = { dir, msgnums };
4479 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4481 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4488 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4495 res = SQLFetch(stmt);
4496 if (!SQL_SUCCEEDED(res)) {
4498 goto bail_with_handle;
4501 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4502 if (!SQL_SUCCEEDED(res)) {
4504 goto bail_with_handle;
4507 if (sscanf(rowdata,
"%30d", &x) != 1) {
4512 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4528static int odbc_count_messages(
struct ast_vm_user *vmu,
char *dir)
4533 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=?");
4535 char *argv[] = { dir };
4536 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4551 res = SQLFetch(stmt);
4552 if (!SQL_SUCCEEDED(res)) {
4554 goto bail_with_handle;
4557 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4558 if (!SQL_SUCCEEDED(res)) {
4560 goto bail_with_handle;
4563 if (sscanf(rowdata,
"%30d", &x) != 1) {
4568 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4583#define DELETE_SQL_FMT "DELETE FROM %s WHERE dir=? AND msgnum=?"
4584static void odbc_delete_message(
const char *sdir,
int smsg)
4587 char *sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4589 char *argv[] = {
NULL, msgnums };
4590 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4592 SCOPE_ENTER(3,
"sdir: %s smsg: %d\n", sdir, smsg);
4601 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4606 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4611 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4612 ast_trace(-1,
"Audio stored on disk. Deleting '%s'\n", src_fn);
4630#define COPY_SQL_FMT "INSERT INTO %s (dir, msgnum, msg_id, context, callerid, origtime, " \
4631 "duration, recording, flag, mailboxuser, mailboxcontext) " \
4632 "SELECT ?,?,msg_id,context,callerid,origtime,duration,recording,flag,?,? " \
4633 "FROM %s WHERE dir=? AND msgnum=?"
4634static void odbc_copy_message(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
4637 char *sql = MAKE_SQL_PTRA2(COPY_SQL_FMT);
4641 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
4642 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4643 SCOPE_ENTER(3,
"sdir: %s smsg: %d duser: %s dcontext: %s ddir: %s dmsg: %d\n",
4644 sdir, smsg, dmailboxuser, dmailboxcontext, ddir, dmsg);
4646 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4653 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4654 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4658 ast_log(
AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4660 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4664 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4665 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);