2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Comedian Mail - Voicemail System
23 * \author Mark Spencer <markster@digium.com>
27 * \ingroup applications
28 * \note This module requires res_adsi to load.
32 <depend>res_adsi</depend>
33 <depend>res_smdi</depend>
37 <category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" remove_on_change="apps/app_voicemail.o apps/app_directory.o">
38 <member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
39 <depend>unixodbc</depend>
41 <conflict>IMAP_STORAGE</conflict>
42 <defaultenabled>no</defaultenabled>
44 <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
45 <depend>imap_tk</depend>
46 <conflict>ODBC_STORAGE</conflict>
48 <defaultenabled>no</defaultenabled>
55 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
65 #include <sys/types.h>
73 #ifdef USE_SYSTEM_IMAP
74 #include <imap/c-client.h>
75 #include <imap/imap4r1.h>
76 #include <imap/linkage.h>
77 #elif defined (USE_SYSTEM_CCLIENT)
78 #include <c-client/c-client.h>
79 #include <c-client/imap4r1.h>
80 #include <c-client/linkage.h>
87 #include "asterisk/lock.h"
88 #include "asterisk/file.h"
89 #include "asterisk/logger.h"
90 #include "asterisk/channel.h"
91 #include "asterisk/pbx.h"
92 #include "asterisk/options.h"
93 #include "asterisk/config.h"
94 #include "asterisk/say.h"
95 #include "asterisk/module.h"
96 #include "asterisk/adsi.h"
97 #include "asterisk/app.h"
98 #include "asterisk/manager.h"
99 #include "asterisk/dsp.h"
100 #include "asterisk/localtime.h"
101 #include "asterisk/cli.h"
102 #include "asterisk/utils.h"
103 #include "asterisk/stringfields.h"
104 #include "asterisk/smdi.h"
106 #include "asterisk/res_odbc.h"
110 AST_MUTEX_DEFINE_STATIC(imaptemp_lock
);
111 static char imaptemp
[1024];
113 static char imapserver
[48];
114 static char imapport
[8];
115 static char imapflags
[128];
116 static char imapfolder
[64];
117 static char authuser
[32];
118 static char authpassword
[42];
120 static int expungeonhangup
= 1;
121 static char delimiter
= '\0';
126 static int init_mailstream (struct vm_state
*vms
, int box
);
127 static void write_file (char *filename
, char *buffer
, unsigned long len
);
128 /*static void status (MAILSTREAM *stream); */ /* No need for this. */
129 static char *get_header_by_tag(char *header
, char *tag
);
130 static void vm_imap_delete(int msgnum
, struct vm_state
*vms
);
131 static char *get_user_by_mailbox(char *mailbox
);
132 static struct vm_state
*get_vm_state_by_imapuser(char *user
, int interactive
);
133 static struct vm_state
*get_vm_state_by_mailbox(const char *mailbox
, int interactive
);
134 static void vmstate_insert(struct vm_state
*vms
);
135 static void vmstate_delete(struct vm_state
*vms
);
136 static void set_update(MAILSTREAM
* stream
);
137 static void init_vm_state(struct vm_state
*vms
);
138 static void check_msgArray(struct vm_state
*vms
);
139 static void copy_msgArray(struct vm_state
*dst
, struct vm_state
*src
);
140 static int save_body(BODY
*body
, struct vm_state
*vms
, char *section
, char *format
);
141 static int make_gsm_file(char *dest
, size_t len
, char *imapuser
, char *dir
, int num
);
142 static void get_mailbox_delimiter(MAILSTREAM
*stream
);
143 static void mm_parsequota (MAILSTREAM
*stream
, unsigned char *msg
, QUOTALIST
*pquota
);
144 static void imap_mailbox_name(char *spec
, size_t len
, struct vm_state
*vms
, int box
, int target
);
145 static int imap_store_file(char *dir
, char *mailboxuser
, char *mailboxcontext
, int msgnum
, struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *fmt
, int duration
, struct vm_state
*vms
);
146 static void check_quota(struct vm_state
*vms
, char *mailbox
);
147 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
,int box
);
149 struct vm_state
*vms
;
150 struct vmstate
*next
;
152 AST_MUTEX_DEFINE_STATIC(vmstate_lock
);
153 static struct vmstate
*vmstates
= NULL
;
156 #define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
158 #define COMMAND_TIMEOUT 5000
159 /* Don't modify these here; set your umask at runtime instead */
160 #define VOICEMAIL_DIR_MODE 0777
161 #define VOICEMAIL_FILE_MODE 0666
162 #define CHUNKSIZE 65536
164 #define VOICEMAIL_CONFIG "voicemail.conf"
165 #define ASTERISK_USERNAME "asterisk"
167 /* Default mail command to mail voicemail. Change it with the
168 mailcmd= command in voicemail.conf */
169 #define SENDMAIL "/usr/sbin/sendmail -t"
171 #define INTRO "vm-intro"
175 #define MAXMSGLIMIT 9999
177 #define MAXMSGLIMIT 255
180 #define BASEMAXINLINE 256
181 #define BASELINELEN 72
182 #define BASEMAXINLINE 256
185 #define MAX_DATETIME_FORMAT 512
186 #define MAX_NUM_CID_CONTEXTS 10
188 #define VM_REVIEW (1 << 0)
189 #define VM_OPERATOR (1 << 1)
190 #define VM_SAYCID (1 << 2)
191 #define VM_SVMAIL (1 << 3)
192 #define VM_ENVELOPE (1 << 4)
193 #define VM_SAYDURATION (1 << 5)
194 #define VM_SKIPAFTERCMD (1 << 6)
195 #define VM_FORCENAME (1 << 7) /*!< Have new users record their name */
196 #define VM_FORCEGREET (1 << 8) /*!< Have new users record their greetings */
197 #define VM_PBXSKIP (1 << 9)
198 #define VM_DIRECFORWARD (1 << 10) /*!< directory_forward */
199 #define VM_ATTACH (1 << 11)
200 #define VM_DELETE (1 << 12)
201 #define VM_ALLOCED (1 << 13)
202 #define VM_SEARCH (1 << 14)
203 #define VM_TEMPGREETWARN (1 << 15) /*!< Remind user tempgreeting is set */
204 #define ERROR_LOCK_PATH -100
205 #define ERROR_MAILBOX_FULL -200
209 OPT_SILENT
= (1 << 0),
210 OPT_BUSY_GREETING
= (1 << 1),
211 OPT_UNAVAIL_GREETING
= (1 << 2),
212 OPT_RECORDGAIN
= (1 << 3),
213 OPT_PREPEND_MAILBOX
= (1 << 4),
214 OPT_PRIORITY_JUMP
= (1 << 5),
215 OPT_AUTOPLAY
= (1 << 6),
219 OPT_ARG_RECORDGAIN
= 0,
220 OPT_ARG_PLAYFOLDER
= 1,
221 /* This *must* be the last value in this enum! */
222 OPT_ARG_ARRAY_SIZE
= 2,
225 AST_APP_OPTIONS(vm_app_options
, {
226 AST_APP_OPTION('s', OPT_SILENT
),
227 AST_APP_OPTION('b', OPT_BUSY_GREETING
),
228 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING
),
229 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN
, OPT_ARG_RECORDGAIN
),
230 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX
),
231 AST_APP_OPTION('j', OPT_PRIORITY_JUMP
),
232 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY
, OPT_ARG_PLAYFOLDER
),
235 static int load_config(void);
237 /*! \page vmlang Voicemail Language Syntaxes Supported
239 \par Syntaxes supported, not really language codes.
247 \arg \b pt - Portuguese
248 \arg \b pt_BR - Portuguese (Brazil)
250 \arg \b no - Norwegian
252 \arg \b ua - Ukrainian
254 German requires the following additional soundfile:
255 \arg \b 1F einE (feminine)
257 Spanish requires the following additional soundfile:
258 \arg \b 1M un (masculine)
260 Dutch, Portuguese & Spanish require the following additional soundfiles:
261 \arg \b vm-INBOXs singular of 'new'
262 \arg \b vm-Olds singular of 'old/heard/read'
265 \arg \b vm-INBOX nieuwe (nl)
266 \arg \b vm-Old oude (nl)
269 \arg \b vm-new-a 'new', feminine singular accusative
270 \arg \b vm-new-e 'new', feminine plural accusative
271 \arg \b vm-new-ych 'new', feminine plural genitive
272 \arg \b vm-old-a 'old', feminine singular accusative
273 \arg \b vm-old-e 'old', feminine plural accusative
274 \arg \b vm-old-ych 'old', feminine plural genitive
275 \arg \b digits/1-a 'one', not always same as 'digits/1'
276 \arg \b digits/2-ie 'two', not always same as 'digits/2'
279 \arg \b vm-nytt singular of 'new'
280 \arg \b vm-nya plural of 'new'
281 \arg \b vm-gammalt singular of 'old'
282 \arg \b vm-gamla plural of 'old'
283 \arg \b digits/ett 'one', not always same as 'digits/1'
286 \arg \b vm-ny singular of 'new'
287 \arg \b vm-nye plural of 'new'
288 \arg \b vm-gammel singular of 'old'
289 \arg \b vm-gamle plural of 'old'
297 Ukrainian requires the following additional soundfile:
298 \arg \b vm-nove 'nove'
299 \arg \b vm-stare 'stare'
300 \arg \b digits/ua/1e 'odne'
302 Italian requires the following additional soundfile:
306 \arg \b vm-nuovi new plural
307 \arg \b vm-vecchio old
308 \arg \b vm-vecchi old plural
310 \note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
311 spelled among others when you have to change folder. For the above reasons, vm-INBOX
312 and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
321 unsigned char iobuf
[BASEMAXINLINE
];
324 /*! Structure for linked list of users */
326 char context
[AST_MAX_CONTEXT
]; /*!< Voicemail context */
327 char mailbox
[AST_MAX_EXTENSION
]; /*!< Mailbox id, unique within vm context */
328 char password
[80]; /*!< Secret pin code, numbers only */
329 char fullname
[80]; /*!< Full name, for directory app */
330 char email
[80]; /*!< E-mail address */
331 char pager
[80]; /*!< E-mail address to pager (no attachment) */
332 char serveremail
[80]; /*!< From: Mail address */
333 char mailcmd
[160]; /*!< Configurable mail command */
334 char language
[MAX_LANGUAGE
]; /*!< Config: Language setting */
335 char zonetag
[80]; /*!< Time zone */
338 char uniqueid
[80]; /*!< Unique integer identifier */
340 char attachfmt
[20]; /*!< Attachment format */
341 unsigned int flags
; /*!< VM_ flags */
343 int maxmsg
; /*!< Maximum number of msgs per folder for this mailbox */
345 char imapuser
[80]; /* IMAP server login */
346 char imappassword
[80]; /* IMAP server password if authpassword not defined */
348 double volgain
; /*!< Volume gain for voicemails sent via email */
349 AST_LIST_ENTRY(ast_vm_user
) list
;
353 AST_LIST_ENTRY(vm_zone
) list
;
356 char msg_format
[512];
362 char curdir
[PATH_MAX
];
363 char vmbox
[PATH_MAX
];
375 int updated
; /* decremented on each mail check until 1 -allows delay */
377 MAILSTREAM
*mailstream
;
379 char imapuser
[80]; /* IMAP server login */
381 unsigned int quota_limit
;
382 unsigned int quota_usage
;
383 struct vm_state
*persist_vms
;
386 static int advanced_options(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, int msg
, int option
, signed char record_gain
);
387 static int dialout(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *num
, char *outgoing_context
);
388 static int play_record_review(struct ast_channel
*chan
, char *playfile
, char *recordfile
, int maxtime
,
389 char *fmt
, int outsidecaller
, struct ast_vm_user
*vmu
, int *duration
, const char *unlockdir
,
390 signed char record_gain
, struct vm_state
*vms
);
391 static int vm_tempgreeting(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
);
392 static int vm_play_folder_name(struct ast_channel
*chan
, char *mbox
);
393 static int notify_new_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int msgnum
, long duration
, char *fmt
, char *cidnum
, char *cidname
);
394 static void make_email_file(FILE *p
, char *srcemail
, struct ast_vm_user
*vmu
, int msgnum
, char *context
, char *mailbox
, char *cidnum
, char *cidname
, char *attach
, char *format
, int duration
, int attach_user_voicemail
, struct ast_channel
*chan
, const char *category
, int imap
);
395 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
396 static int __has_voicemail(const char *context
, const char *mailbox
, const char *folder
, int shortcircuit
);
398 static void apply_options(struct ast_vm_user
*vmu
, const char *options
);
401 static char odbc_database
[80];
402 static char odbc_table
[80];
403 #define RETRIEVE(a,b) retrieve_file(a,b)
404 #define DISPOSE(a,b) remove_file(a,b)
405 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
406 #define EXISTS(a,b,c,d) (message_exists(a,b))
407 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
408 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
409 #define DELETE(a,b,c) (delete_file(a,b))
412 #define RETRIEVE(a,b)
414 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
415 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
416 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
417 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
418 #define IMAP_DELETE(a,b,c,d) (vm_imap_delete(b,d))
419 #define DELETE(a,b,c) (vm_delete(c))
421 #define RETRIEVE(a,b)
423 #define STORE(a,b,c,d,e,f,g,h,i)
424 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
425 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
426 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
427 #define DELETE(a,b,c) (vm_delete(c))
431 static char VM_SPOOL_DIR
[PATH_MAX
];
433 static char ext_pass_cmd
[128];
438 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
440 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
442 #define tdesc "Comedian Mail (Voicemail System)"
445 static char userscontext
[AST_MAX_EXTENSION
] = "default";
447 static char *addesc
= "Comedian Mail";
449 static char *synopsis_vm
=
450 "Leave a Voicemail message";
452 static char *descrip_vm
=
453 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
454 "application allows the calling party to leave a message for the specified\n"
455 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
456 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
457 "specified mailbox does not exist.\n"
458 " The Voicemail application will exit if any of the following DTMF digits are\n"
460 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
461 " * - Jump to the 'a' extension in the current dialplan context.\n"
462 " This application will set the following channel variable upon completion:\n"
463 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
464 " application. The possible values are:\n"
465 " SUCCESS | USEREXIT | FAILED\n\n"
467 " b - Play the 'busy' greeting to the calling party.\n"
468 " g(#) - Use the specified amount of gain when recording the voicemail\n"
469 " message. The units are whole-number decibels (dB).\n"
470 " s - Skip the playback of instructions for leaving a message to the\n"
472 " u - Play the 'unavailable' greeting.\n"
473 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
476 static char *synopsis_vmain
=
477 "Check Voicemail messages";
479 static char *descrip_vmain
=
480 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
481 "calling party to check voicemail messages. A specific mailbox, and optional\n"
482 "corresponding context, may be specified. If a mailbox is not provided, the\n"
483 "calling party will be prompted to enter one. If a context is not specified,\n"
484 "the 'default' context will be used.\n\n"
486 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
487 " is entered by the caller.\n"
488 " g(#) - Use the specified amount of gain when recording a voicemail\n"
489 " message. The units are whole-number decibels (dB).\n"
490 " s - Skip checking the passcode for the mailbox.\n"
491 " a(#) - Skip folder prompt and go directly to folder specified.\n"
492 " Defaults to INBOX\n";
494 static char *synopsis_vm_box_exists
=
495 "Check to see if Voicemail mailbox exists";
497 static char *descrip_vm_box_exists
=
498 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
499 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
501 " This application will set the following channel variable upon completion:\n"
502 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
503 " MailboxExists application. Possible values include:\n"
504 " SUCCESS | FAILED\n\n"
506 " j - Jump to priority n+101 if the mailbox is found.\n";
508 static char *synopsis_vmauthenticate
=
509 "Authenticate with Voicemail passwords";
511 static char *descrip_vmauthenticate
=
512 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
513 "same way as the Authenticate application, but the passwords are taken from\n"
515 " If the mailbox is specified, only that mailbox's password will be considered\n"
516 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
517 "be set with the authenticated mailbox.\n\n"
519 " s - Skip playing the initial prompts.\n";
521 /* Leave a message */
522 static char *app
= "VoiceMail";
524 /* Check mail, control, etc */
525 static char *app2
= "VoiceMailMain";
527 static char *app3
= "MailboxExists";
528 static char *app4
= "VMAuthenticate";
530 static AST_LIST_HEAD_STATIC(users
, ast_vm_user
);
531 static AST_LIST_HEAD_STATIC(zones
, vm_zone
);
532 static int maxsilence
;
534 static int silencethreshold
= 128;
535 static char serveremail
[80];
536 static char mailcmd
[160]; /* Configurable mail cmd */
537 static char externnotify
[160];
538 static struct ast_smdi_interface
*smdi_iface
= NULL
;
539 static char vmfmts
[80];
540 static double volgain
;
541 static int vmminmessage
;
542 static int vmmaxmessage
;
545 static int maxlogins
;
547 static struct ast_flags globalflags
= {0};
549 static int saydurationminfo
;
551 static char dialcontext
[AST_MAX_CONTEXT
];
552 static char callcontext
[AST_MAX_CONTEXT
];
553 static char exitcontext
[AST_MAX_CONTEXT
];
555 static char cidinternalcontexts
[MAX_NUM_CID_CONTEXTS
][64];
558 static char *emailbody
= NULL
;
559 static char *emailsubject
= NULL
;
560 static char *pagerbody
= NULL
;
561 static char *pagersubject
= NULL
;
562 static char fromstring
[100];
563 static char pagerfromstring
[100];
564 static char emailtitle
[100];
565 static char charset
[32] = "ISO-8859-1";
567 static unsigned char adsifdn
[4] = "\x00\x00\x00\x0F";
568 static unsigned char adsisec
[4] = "\x9B\xDB\xF7\xAC";
569 static int adsiver
= 1;
570 static char emaildateformat
[32] = "%A, %B %d, %Y at %r";
573 static void populate_defaults(struct ast_vm_user
*vmu
)
575 ast_copy_flags(vmu
, (&globalflags
), AST_FLAGS_ALL
);
576 if (saydurationminfo
)
577 vmu
->saydurationm
= saydurationminfo
;
578 ast_copy_string(vmu
->callback
, callcontext
, sizeof(vmu
->callback
));
579 ast_copy_string(vmu
->dialout
, dialcontext
, sizeof(vmu
->dialout
));
580 ast_copy_string(vmu
->exit
, exitcontext
, sizeof(vmu
->exit
));
582 vmu
->maxmsg
= maxmsg
;
583 vmu
->volgain
= volgain
;
586 static void apply_option(struct ast_vm_user
*vmu
, const char *var
, const char *value
)
589 if (!strcasecmp(var
, "attach")) {
590 ast_set2_flag(vmu
, ast_true(value
), VM_ATTACH
);
591 } else if (!strcasecmp(var
, "attachfmt")) {
592 ast_copy_string(vmu
->attachfmt
, value
, sizeof(vmu
->attachfmt
));
593 } else if (!strcasecmp(var
, "serveremail")) {
594 ast_copy_string(vmu
->serveremail
, value
, sizeof(vmu
->serveremail
));
595 } else if (!strcasecmp(var
, "language")) {
596 ast_copy_string(vmu
->language
, value
, sizeof(vmu
->language
));
597 } else if (!strcasecmp(var
, "tz")) {
598 ast_copy_string(vmu
->zonetag
, value
, sizeof(vmu
->zonetag
));
600 } else if (!strcasecmp(var
, "imapuser")) {
601 ast_copy_string(vmu
->imapuser
, value
, sizeof(vmu
->imapuser
));
602 } else if (!strcasecmp(var
, "imappassword")) {
603 ast_copy_string(vmu
->imappassword
, value
, sizeof(vmu
->imappassword
));
605 } else if (!strcasecmp(var
, "delete") || !strcasecmp(var
, "deletevoicemail")) {
606 ast_set2_flag(vmu
, ast_true(value
), VM_DELETE
);
607 } else if (!strcasecmp(var
, "saycid")){
608 ast_set2_flag(vmu
, ast_true(value
), VM_SAYCID
);
609 } else if (!strcasecmp(var
,"sendvoicemail")){
610 ast_set2_flag(vmu
, ast_true(value
), VM_SVMAIL
);
611 } else if (!strcasecmp(var
, "review")){
612 ast_set2_flag(vmu
, ast_true(value
), VM_REVIEW
);
613 } else if (!strcasecmp(var
, "tempgreetwarn")){
614 ast_set2_flag(vmu
, ast_true(value
), VM_TEMPGREETWARN
);
615 } else if (!strcasecmp(var
, "operator")){
616 ast_set2_flag(vmu
, ast_true(value
), VM_OPERATOR
);
617 } else if (!strcasecmp(var
, "envelope")){
618 ast_set2_flag(vmu
, ast_true(value
), VM_ENVELOPE
);
619 } else if (!strcasecmp(var
, "sayduration")){
620 ast_set2_flag(vmu
, ast_true(value
), VM_SAYDURATION
);
621 } else if (!strcasecmp(var
, "saydurationm")){
622 if (sscanf(value
, "%d", &x
) == 1) {
623 vmu
->saydurationm
= x
;
625 ast_log(LOG_WARNING
, "Invalid min duration for say duration\n");
627 } else if (!strcasecmp(var
, "forcename")){
628 ast_set2_flag(vmu
, ast_true(value
), VM_FORCENAME
);
629 } else if (!strcasecmp(var
, "forcegreetings")){
630 ast_set2_flag(vmu
, ast_true(value
), VM_FORCEGREET
);
631 } else if (!strcasecmp(var
, "callback")) {
632 ast_copy_string(vmu
->callback
, value
, sizeof(vmu
->callback
));
633 } else if (!strcasecmp(var
, "dialout")) {
634 ast_copy_string(vmu
->dialout
, value
, sizeof(vmu
->dialout
));
635 } else if (!strcasecmp(var
, "exitcontext")) {
636 ast_copy_string(vmu
->exit
, value
, sizeof(vmu
->exit
));
637 } else if (!strcasecmp(var
, "maxmsg")) {
638 vmu
->maxmsg
= atoi(value
);
639 if (vmu
->maxmsg
<= 0) {
640 ast_log(LOG_WARNING
, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value
, MAXMSG
);
641 vmu
->maxmsg
= MAXMSG
;
642 } else if (vmu
->maxmsg
> MAXMSGLIMIT
) {
643 ast_log(LOG_WARNING
, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT
, value
);
644 vmu
->maxmsg
= MAXMSGLIMIT
;
646 } else if (!strcasecmp(var
, "volgain")) {
647 sscanf(value
, "%lf", &vmu
->volgain
);
648 } else if (!strcasecmp(var
, "options")) {
649 apply_options(vmu
, value
);
653 static int change_password_realtime(struct ast_vm_user
*vmu
, const char *password
)
656 if (!ast_strlen_zero(vmu
->uniqueid
)) {
657 res
= ast_update_realtime("voicemail", "uniqueid", vmu
->uniqueid
, "password", password
, NULL
);
659 ast_copy_string(vmu
->password
, password
, sizeof(vmu
->password
));
669 static void apply_options(struct ast_vm_user
*vmu
, const char *options
)
670 { /* Destructively Parse options and apply */
674 stringp
= ast_strdupa(options
);
675 while ((s
= strsep(&stringp
, "|"))) {
677 if ((var
= strsep(&value
, "=")) && value
) {
678 apply_option(vmu
, var
, value
);
683 static void apply_options_full(struct ast_vm_user
*retval
, struct ast_variable
*var
)
685 struct ast_variable
*tmp
;
688 if (!strcasecmp(tmp
->name
, "vmsecret")) {
689 ast_copy_string(retval
->password
, tmp
->value
, sizeof(retval
->password
));
690 } else if (!strcasecmp(tmp
->name
, "secret") || !strcasecmp(tmp
->name
, "password")) { /* don't overwrite vmsecret if it exists */
691 if (ast_strlen_zero(retval
->password
))
692 ast_copy_string(retval
->password
, tmp
->value
, sizeof(retval
->password
));
693 } else if (!strcasecmp(tmp
->name
, "uniqueid")) {
694 ast_copy_string(retval
->uniqueid
, tmp
->value
, sizeof(retval
->uniqueid
));
695 } else if (!strcasecmp(tmp
->name
, "pager")) {
696 ast_copy_string(retval
->pager
, tmp
->value
, sizeof(retval
->pager
));
697 } else if (!strcasecmp(tmp
->name
, "email")) {
698 ast_copy_string(retval
->email
, tmp
->value
, sizeof(retval
->email
));
699 } else if (!strcasecmp(tmp
->name
, "fullname")) {
700 ast_copy_string(retval
->fullname
, tmp
->value
, sizeof(retval
->fullname
));
701 } else if (!strcasecmp(tmp
->name
, "context")) {
702 ast_copy_string(retval
->context
, tmp
->value
, sizeof(retval
->context
));
704 } else if (!strcasecmp(tmp
->name
, "imapuser")) {
705 ast_copy_string(retval
->imapuser
, tmp
->value
, sizeof(retval
->imapuser
));
706 } else if (!strcasecmp(tmp
->name
, "imappassword")) {
707 ast_copy_string(retval
->imappassword
, tmp
->value
, sizeof(retval
->imappassword
));
710 apply_option(retval
, tmp
->name
, tmp
->value
);
715 static struct ast_vm_user
*find_user_realtime(struct ast_vm_user
*ivm
, const char *context
, const char *mailbox
)
717 struct ast_variable
*var
;
718 struct ast_vm_user
*retval
;
720 if ((retval
= (ivm
? ivm
: ast_calloc(1, sizeof(*retval
))))) {
722 ast_set_flag(retval
, VM_ALLOCED
);
724 memset(retval
, 0, sizeof(*retval
));
726 ast_copy_string(retval
->mailbox
, mailbox
, sizeof(retval
->mailbox
));
727 populate_defaults(retval
);
728 if (!context
&& ast_test_flag((&globalflags
), VM_SEARCH
))
729 var
= ast_load_realtime("voicemail", "mailbox", mailbox
, NULL
);
731 var
= ast_load_realtime("voicemail", "mailbox", mailbox
, "context", context
, NULL
);
733 apply_options_full(retval
, var
);
734 ast_variables_destroy(var
);
744 static struct ast_vm_user
*find_user(struct ast_vm_user
*ivm
, const char *context
, const char *mailbox
)
746 /* This function could be made to generate one from a database, too */
747 struct ast_vm_user
*vmu
=NULL
, *cur
;
748 AST_LIST_LOCK(&users
);
750 if (!context
&& !ast_test_flag((&globalflags
), VM_SEARCH
))
753 AST_LIST_TRAVERSE(&users
, cur
, list
) {
754 if (ast_test_flag((&globalflags
), VM_SEARCH
) && !strcasecmp(mailbox
, cur
->mailbox
))
756 if (context
&& (!strcasecmp(context
, cur
->context
)) && (!strcasecmp(mailbox
, cur
->mailbox
)))
760 /* Make a copy, so that on a reload, we have no race */
761 if ((vmu
= (ivm
? ivm
: ast_malloc(sizeof(*vmu
))))) {
762 memcpy(vmu
, cur
, sizeof(*vmu
));
763 ast_set2_flag(vmu
, !ivm
, VM_ALLOCED
);
764 AST_LIST_NEXT(vmu
, list
) = NULL
;
767 vmu
= find_user_realtime(ivm
, context
, mailbox
);
768 AST_LIST_UNLOCK(&users
);
772 static int reset_user_pw(const char *context
, const char *mailbox
, const char *newpass
)
774 /* This function could be made to generate one from a database, too */
775 struct ast_vm_user
*cur
;
777 AST_LIST_LOCK(&users
);
778 AST_LIST_TRAVERSE(&users
, cur
, list
) {
779 if ((!context
|| !strcasecmp(context
, cur
->context
)) &&
780 (!strcasecmp(mailbox
, cur
->mailbox
)))
784 ast_copy_string(cur
->password
, newpass
, sizeof(cur
->password
));
787 AST_LIST_UNLOCK(&users
);
791 static void vm_change_password(struct ast_vm_user
*vmu
, const char *newpassword
)
793 struct ast_config
*cfg
=NULL
;
794 struct ast_variable
*var
=NULL
;
795 struct ast_category
*cat
=NULL
;
796 char *category
=NULL
, *value
=NULL
, *new=NULL
;
797 const char *tmp
=NULL
;
799 if (!change_password_realtime(vmu
, newpassword
))
802 /* check voicemail.conf */
803 if ((cfg
= ast_config_load_with_comments(VOICEMAIL_CONFIG
))) {
804 while ((category
= ast_category_browse(cfg
, category
))) {
805 if (!strcasecmp(category
, vmu
->context
)) {
806 tmp
= ast_variable_retrieve(cfg
, category
, vmu
->mailbox
);
808 ast_log(LOG_WARNING
, "We could not find the mailbox.\n");
811 value
= strstr(tmp
,",");
813 ast_log(LOG_WARNING
, "variable has bad format.\n");
816 new = alloca((strlen(value
)+strlen(newpassword
)+1));
817 sprintf(new,"%s%s", newpassword
, value
);
818 if (!(cat
= ast_category_get(cfg
, category
))) {
819 ast_log(LOG_WARNING
, "Failed to get category structure.\n");
822 ast_variable_update(cat
, vmu
->mailbox
, new, NULL
, 0);
825 /* save the results */
826 reset_user_pw(vmu
->context
, vmu
->mailbox
, newpassword
);
827 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
828 config_text_file_save(VOICEMAIL_CONFIG
, cfg
, "AppVoicemail");
832 /* check users.conf and update the password stored for the mailbox*/
833 /* if no vmsecret entry exists create one. */
834 if ((cfg
= ast_config_load_with_comments("users.conf"))) {
835 if (option_debug
> 3)
836 ast_log(LOG_DEBUG
, "we are looking for %s\n", vmu
->mailbox
);
837 while ((category
= ast_category_browse(cfg
, category
))) {
838 if (option_debug
> 3)
839 ast_log(LOG_DEBUG
, "users.conf: %s\n", category
);
840 if (!strcasecmp(category
, vmu
->mailbox
)) {
841 if (!(tmp
= ast_variable_retrieve(cfg
, category
, "vmsecret"))) {
842 if (option_debug
> 3)
843 ast_log(LOG_DEBUG
, "looks like we need to make vmsecret!\n");
844 var
= ast_variable_new("vmsecret", newpassword
);
846 new = alloca(strlen(newpassword
)+1);
847 sprintf(new, "%s", newpassword
);
848 if (!(cat
= ast_category_get(cfg
, category
))) {
849 if (option_debug
> 3)
850 ast_log(LOG_DEBUG
, "failed to get category!\n");
854 ast_variable_update(cat
, "vmsecret", new, NULL
, 0);
856 ast_variable_append(cat
, var
);
859 /* save the results and clean things up */
860 reset_user_pw(vmu
->context
, vmu
->mailbox
, newpassword
);
861 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
862 config_text_file_save("users.conf", cfg
, "AppVoicemail");
866 static void vm_change_password_shell(struct ast_vm_user
*vmu
, char *newpassword
)
869 snprintf(buf
,255,"%s %s %s %s",ext_pass_cmd
,vmu
->context
,vmu
->mailbox
,newpassword
);
870 if (!ast_safe_system(buf
)) {
871 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
872 /* Reset the password in memory, too */
873 reset_user_pw(vmu
->context
, vmu
->mailbox
, newpassword
);
877 static int make_dir(char *dest
, int len
, const char *context
, const char *ext
, const char *folder
)
879 return snprintf(dest
, len
, "%s%s/%s/%s", VM_SPOOL_DIR
, context
, ext
, folder
);
883 static int make_gsm_file(char *dest
, size_t len
, char *imapuser
, char *dir
, int num
)
885 if (mkdir(dir
, 01777) && (errno
!= EEXIST
)) {
886 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dir
, strerror(errno
));
887 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
889 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
892 static void vm_imap_delete(int msgnum
, struct vm_state
*vms
)
894 unsigned long messageNum
= 0;
897 /* find real message number based on msgnum */
898 /* this may be an index into vms->msgArray based on the msgnum. */
900 messageNum
= vms
->msgArray
[msgnum
];
901 if (messageNum
== 0) {
902 ast_log(LOG_WARNING
, "msgnum %d, mailbox message %lu is zero.\n",msgnum
,messageNum
);
905 if (option_debug
> 2)
906 ast_log(LOG_DEBUG
, "deleting msgnum %d, which is mailbox message %lu\n",msgnum
,messageNum
);
908 snprintf (arg
, sizeof(arg
), "%lu",messageNum
);
909 mail_setflag (vms
->mailstream
,arg
,"\\DELETED");
913 static int make_file(char *dest
, int len
, char *dir
, int num
)
915 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
918 /*! \brief basically mkdir -p $dest/$context/$ext/$folder
919 * \param dest String. base directory.
920 * \param len Length of dest.
921 * \param context String. Ignored if is null or empty string.
922 * \param ext String. Ignored if is null or empty string.
923 * \param folder String. Ignored if is null or empty string.
924 * \return -1 on failure, 0 on success.
926 static int create_dirpath(char *dest
, int len
, const char *context
, const char *ext
, const char *folder
)
928 mode_t mode
= VOICEMAIL_DIR_MODE
;
930 if (!ast_strlen_zero(context
)) {
931 make_dir(dest
, len
, context
, "", "");
932 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
933 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
937 if (!ast_strlen_zero(ext
)) {
938 make_dir(dest
, len
, context
, ext
, "");
939 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
940 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
944 if (!ast_strlen_zero(folder
)) {
945 make_dir(dest
, len
, context
, ext
, folder
);
946 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
947 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
954 /* only return failure if ast_lock_path returns 'timeout',
955 not if the path does not exist or any other reason
957 static int vm_lock_path(const char *path
)
959 switch (ast_lock_path(path
)) {
960 case AST_LOCK_TIMEOUT
:
969 struct generic_prepare_struct
{
975 static SQLHSTMT
generic_prepare(struct odbc_obj
*obj
, void *data
)
977 struct generic_prepare_struct
*gps
= data
;
981 res
= SQLAllocHandle(SQL_HANDLE_STMT
, obj
->con
, &stmt
);
982 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
983 ast_log(LOG_WARNING
, "SQL Alloc Handle failed!\n");
986 res
= SQLPrepare(stmt
, (unsigned char *)gps
->sql
, SQL_NTS
);
987 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
988 ast_log(LOG_WARNING
, "SQL Prepare failed![%s]\n", gps
->sql
);
989 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
992 for (i
= 0; i
< gps
->argc
; i
++)
993 SQLBindParameter(stmt
, i
+ 1, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(gps
->argv
[i
]), 0, gps
->argv
[i
], 0, NULL
);
998 static int retrieve_file(char *dir
, int msgnum
)
1004 void *fdm
= MAP_FAILED
;
1005 SQLSMALLINT colcount
=0;
1012 SQLSMALLINT datatype
;
1013 SQLSMALLINT decimaldigits
;
1014 SQLSMALLINT nullable
;
1020 char full_fn
[PATH_MAX
];
1022 char *argv
[] = { dir
, msgnums
};
1023 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1025 struct odbc_obj
*obj
;
1026 obj
= ast_odbc_request_obj(odbc_database
, 0);
1028 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
1029 c
= strchr(fmt
, '|');
1032 if (!strcasecmp(fmt
, "wav49"))
1034 snprintf(msgnums
, sizeof(msgnums
),"%d", msgnum
);
1036 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1038 ast_copy_string(fn
, dir
, sizeof(fn
));
1039 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1041 if (!(f
= fopen(full_fn
, "w+"))) {
1042 ast_log(LOG_WARNING
, "Failed to open/create '%s'\n", full_fn
);
1046 snprintf(full_fn
, sizeof(full_fn
), "%s.%s", fn
, fmt
);
1047 snprintf(sql
, sizeof(sql
), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1048 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1050 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1051 ast_odbc_release_obj(obj
);
1054 res
= SQLFetch(stmt
);
1055 if (res
== SQL_NO_DATA
) {
1056 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1057 ast_odbc_release_obj(obj
);
1060 else if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1061 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1062 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1063 ast_odbc_release_obj(obj
);
1066 fd
= open(full_fn
, O_RDWR
| O_CREAT
| O_TRUNC
, 0770);
1068 ast_log(LOG_WARNING
, "Failed to write '%s': %s\n", full_fn
, strerror(errno
));
1069 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1070 ast_odbc_release_obj(obj
);
1073 res
= SQLNumResultCols(stmt
, &colcount
);
1074 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1075 ast_log(LOG_WARNING
, "SQL Column Count error!\n[%s]\n\n", sql
);
1076 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1077 ast_odbc_release_obj(obj
);
1081 fprintf(f
, "[message]\n");
1082 for (x
=0;x
<colcount
;x
++) {
1084 collen
= sizeof(coltitle
);
1085 res
= SQLDescribeCol(stmt
, x
+ 1, (unsigned char *)coltitle
, sizeof(coltitle
), &collen
,
1086 &datatype
, &colsize
, &decimaldigits
, &nullable
);
1087 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1088 ast_log(LOG_WARNING
, "SQL Describe Column error!\n[%s]\n\n", sql
);
1089 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1090 ast_odbc_release_obj(obj
);
1093 if (!strcasecmp(coltitle
, "recording")) {
1095 res
= SQLGetData(stmt
, x
+ 1, SQL_BINARY
, rowdata
, 0, &colsize2
);
1099 lseek(fd
, fdlen
- 1, SEEK_SET
);
1100 if (write(fd
, tmp
, 1) != 1) {
1105 /* Read out in small chunks */
1106 for (offset
= 0; offset
< colsize2
; offset
+= CHUNKSIZE
) {
1107 if ((fdm
= mmap(NULL
, CHUNKSIZE
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, offset
)) == MAP_FAILED
) {
1108 ast_log(LOG_WARNING
, "Could not mmap the output file: %s (%d)\n", strerror(errno
), errno
);
1109 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1110 ast_odbc_release_obj(obj
);
1113 res
= SQLGetData(stmt
, x
+ 1, SQL_BINARY
, fdm
, CHUNKSIZE
, NULL
);
1114 munmap(fdm
, CHUNKSIZE
);
1115 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1116 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1118 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1119 ast_odbc_release_obj(obj
);
1124 truncate(full_fn
, fdlen
);
1127 res
= SQLGetData(stmt
, x
+ 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1128 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1129 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1130 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1131 ast_odbc_release_obj(obj
);
1134 if (strcasecmp(coltitle
, "msgnum") && strcasecmp(coltitle
, "dir") && f
)
1135 fprintf(f
, "%s=%s\n", coltitle
, rowdata
);
1138 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1139 ast_odbc_release_obj(obj
);
1141 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1150 static int remove_file(char *dir
, int msgnum
)
1153 char full_fn
[PATH_MAX
];
1157 snprintf(msgnums
, sizeof(msgnums
), "%d", msgnum
);
1158 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1160 ast_copy_string(fn
, dir
, sizeof(fn
));
1161 ast_filedelete(fn
, NULL
);
1162 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1167 static int last_message_index(struct ast_vm_user
*vmu
, char *dir
)
1174 char *argv
[] = { dir
};
1175 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 1, .argv
= argv
};
1177 struct odbc_obj
*obj
;
1178 obj
= ast_odbc_request_obj(odbc_database
, 0);
1180 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table
);
1181 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1183 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1184 ast_odbc_release_obj(obj
);
1187 res
= SQLFetch(stmt
);
1188 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1189 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1190 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1191 ast_odbc_release_obj(obj
);
1194 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1195 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1196 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1197 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1198 ast_odbc_release_obj(obj
);
1201 if (sscanf(rowdata
, "%d", &x
) != 1)
1202 ast_log(LOG_WARNING
, "Failed to read message count!\n");
1203 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1204 ast_odbc_release_obj(obj
);
1206 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1211 static int message_exists(char *dir
, int msgnum
)
1219 char *argv
[] = { dir
, msgnums
};
1220 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1222 struct odbc_obj
*obj
;
1223 obj
= ast_odbc_request_obj(odbc_database
, 0);
1225 snprintf(msgnums
, sizeof(msgnums
), "%d", msgnum
);
1226 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1227 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1229 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1230 ast_odbc_release_obj(obj
);
1233 res
= SQLFetch(stmt
);
1234 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1235 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1236 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1237 ast_odbc_release_obj(obj
);
1240 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1241 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1242 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1243 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1244 ast_odbc_release_obj(obj
);
1247 if (sscanf(rowdata
, "%d", &x
) != 1)
1248 ast_log(LOG_WARNING
, "Failed to read message count!\n");
1249 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1250 ast_odbc_release_obj(obj
);
1252 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1257 static int count_messages(struct ast_vm_user
*vmu
, char *dir
)
1259 return last_message_index(vmu
, dir
) + 1;
1262 static void delete_file(char *sdir
, int smsg
)
1267 char *argv
[] = { sdir
, msgnums
};
1268 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1270 struct odbc_obj
*obj
;
1271 obj
= ast_odbc_request_obj(odbc_database
, 0);
1273 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1274 snprintf(sql
, sizeof(sql
), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1275 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1277 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1279 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1280 ast_odbc_release_obj(obj
);
1282 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1286 static void copy_file(char *sdir
, int smsg
, char *ddir
, int dmsg
, char *dmailboxuser
, char *dmailboxcontext
)
1292 struct odbc_obj
*obj
;
1293 char *argv
[] = { ddir
, msgnumd
, dmailboxuser
, dmailboxcontext
, sdir
, msgnums
};
1294 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 6, .argv
= argv
};
1296 delete_file(ddir
, dmsg
);
1297 obj
= ast_odbc_request_obj(odbc_database
, 0);
1299 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1300 snprintf(msgnumd
, sizeof(msgnumd
), "%d", dmsg
);
1301 snprintf(sql
, sizeof(sql
), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table
,odbc_table
);
1302 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1304 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql
);
1306 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1307 ast_odbc_release_obj(obj
);
1309 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1313 static int store_file(char *dir
, char *mailboxuser
, char *mailboxcontext
, int msgnum
)
1318 void *fdm
= MAP_FAILED
;
1325 char full_fn
[PATH_MAX
];
1328 const char *context
="", *macrocontext
="", *callerid
="", *origtime
="", *duration
="";
1329 const char *category
= "";
1330 struct ast_config
*cfg
=NULL
;
1331 struct odbc_obj
*obj
;
1333 delete_file(dir
, msgnum
);
1334 obj
= ast_odbc_request_obj(odbc_database
, 0);
1336 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
1337 c
= strchr(fmt
, '|');
1340 if (!strcasecmp(fmt
, "wav49"))
1342 snprintf(msgnums
, sizeof(msgnums
),"%d", msgnum
);
1344 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1346 ast_copy_string(fn
, dir
, sizeof(fn
));
1347 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1348 cfg
= ast_config_load(full_fn
);
1349 snprintf(full_fn
, sizeof(full_fn
), "%s.%s", fn
, fmt
);
1350 fd
= open(full_fn
, O_RDWR
);
1352 ast_log(LOG_WARNING
, "Open of sound file '%s' failed: %s\n", full_fn
, strerror(errno
));
1353 ast_odbc_release_obj(obj
);
1357 context
= ast_variable_retrieve(cfg
, "message", "context");
1358 if (!context
) context
= "";
1359 macrocontext
= ast_variable_retrieve(cfg
, "message", "macrocontext");
1360 if (!macrocontext
) macrocontext
= "";
1361 callerid
= ast_variable_retrieve(cfg
, "message", "callerid");
1362 if (!callerid
) callerid
= "";
1363 origtime
= ast_variable_retrieve(cfg
, "message", "origtime");
1364 if (!origtime
) origtime
= "";
1365 duration
= ast_variable_retrieve(cfg
, "message", "duration");
1366 if (!duration
) duration
= "";
1367 category
= ast_variable_retrieve(cfg
, "message", "category");
1368 if (!category
) category
= "";
1370 fdlen
= lseek(fd
, 0, SEEK_END
);
1371 lseek(fd
, 0, SEEK_SET
);
1372 printf("Length is %zd\n", fdlen
);
1373 fdm
= mmap(NULL
, fdlen
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,fd
, 0);
1374 if (fdm
== MAP_FAILED
) {
1375 ast_log(LOG_WARNING
, "Memory map failed!\n");
1376 ast_odbc_release_obj(obj
);
1379 res
= SQLAllocHandle(SQL_HANDLE_STMT
, obj
->con
, &stmt
);
1380 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1381 ast_log(LOG_WARNING
, "SQL Alloc Handle failed!\n");
1382 ast_odbc_release_obj(obj
);
1385 if (!ast_strlen_zero(category
))
1386 snprintf(sql
, sizeof(sql
), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table
);
1388 snprintf(sql
, sizeof(sql
), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)",odbc_table
);
1389 res
= SQLPrepare(stmt
, (unsigned char *)sql
, SQL_NTS
);
1390 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1391 ast_log(LOG_WARNING
, "SQL Prepare failed![%s]\n", sql
);
1392 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1393 ast_odbc_release_obj(obj
);
1396 len
= fdlen
; /* SQL_LEN_DATA_AT_EXEC(fdlen); */
1397 SQLBindParameter(stmt
, 1, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(dir
), 0, (void *)dir
, 0, NULL
);
1398 SQLBindParameter(stmt
, 2, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(msgnums
), 0, (void *)msgnums
, 0, NULL
);
1399 SQLBindParameter(stmt
, 3, SQL_PARAM_INPUT
, SQL_C_BINARY
, SQL_LONGVARBINARY
, fdlen
, 0, (void *)fdm
, fdlen
, &len
);
1400 SQLBindParameter(stmt
, 4, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(context
), 0, (void *)context
, 0, NULL
);
1401 SQLBindParameter(stmt
, 5, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(macrocontext
), 0, (void *)macrocontext
, 0, NULL
);
1402 SQLBindParameter(stmt
, 6, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(callerid
), 0, (void *)callerid
, 0, NULL
);
1403 SQLBindParameter(stmt
, 7, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(origtime
), 0, (void *)origtime
, 0, NULL
);
1404 SQLBindParameter(stmt
, 8, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(duration
), 0, (void *)duration
, 0, NULL
);
1405 SQLBindParameter(stmt
, 9, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(mailboxuser
), 0, (void *)mailboxuser
, 0, NULL
);
1406 SQLBindParameter(stmt
, 10, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(mailboxcontext
), 0, (void *)mailboxcontext
, 0, NULL
);
1407 if (!ast_strlen_zero(category
))
1408 SQLBindParameter(stmt
, 11, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(category
), 0, (void *)category
, 0, NULL
);
1409 res
= ast_odbc_smart_execute(obj
, stmt
);
1410 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1411 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1412 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1413 ast_odbc_release_obj(obj
);
1416 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1417 ast_odbc_release_obj(obj
);
1419 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1422 ast_config_destroy(cfg
);
1423 if (fdm
!= MAP_FAILED
)
1430 static void rename_file(char *sdir
, int smsg
, char *mailboxuser
, char *mailboxcontext
, char *ddir
, int dmsg
)
1436 struct odbc_obj
*obj
;
1437 char *argv
[] = { ddir
, msgnumd
, mailboxuser
, mailboxcontext
, sdir
, msgnums
};
1438 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 6, .argv
= argv
};
1440 delete_file(ddir
, dmsg
);
1441 obj
= ast_odbc_request_obj(odbc_database
, 0);
1443 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1444 snprintf(msgnumd
, sizeof(msgnumd
), "%d", dmsg
);
1445 snprintf(sql
, sizeof(sql
), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table
);
1446 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1448 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1450 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1451 ast_odbc_release_obj(obj
);
1453 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1458 #ifndef IMAP_STORAGE
1459 static int count_messages(struct ast_vm_user
*vmu
, char *dir
)
1461 /* Find all .txt files - even if they are not in sequence from 0000 */
1465 struct dirent
*vment
= NULL
;
1467 if (vm_lock_path(dir
))
1468 return ERROR_LOCK_PATH
;
1470 if ((vmdir
= opendir(dir
))) {
1471 while ((vment
= readdir(vmdir
))) {
1472 if (strlen(vment
->d_name
) > 7 && !strncmp(vment
->d_name
+ 7, ".txt", 4))
1477 ast_unlock_path(dir
);
1482 static void rename_file(char *sfn
, char *dfn
)
1484 char stxt
[PATH_MAX
];
1485 char dtxt
[PATH_MAX
];
1486 ast_filerename(sfn
,dfn
,NULL
);
1487 snprintf(stxt
, sizeof(stxt
), "%s.txt", sfn
);
1488 snprintf(dtxt
, sizeof(dtxt
), "%s.txt", dfn
);
1494 * A negative return value indicates an error.
1496 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
1497 static int last_message_index(struct ast_vm_user
*vmu
, char *dir
)
1502 if (vm_lock_path(dir
))
1503 return ERROR_LOCK_PATH
;
1505 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
1506 make_file(fn
, sizeof(fn
), dir
, x
);
1507 if (ast_fileexists(fn
, NULL
, NULL
) < 1)
1510 ast_unlock_path(dir
);
1517 static int copy(char *infile
, char *outfile
)
1525 #ifdef HARDLINK_WHEN_POSSIBLE
1526 /* Hard link if possible; saves disk space & is faster */
1527 if (link(infile
, outfile
)) {
1529 if ((ifd
= open(infile
, O_RDONLY
)) < 0) {
1530 ast_log(LOG_WARNING
, "Unable to open %s in read-only mode\n", infile
);
1533 if ((ofd
= open(outfile
, O_WRONLY
| O_TRUNC
| O_CREAT
, VOICEMAIL_FILE_MODE
)) < 0) {
1534 ast_log(LOG_WARNING
, "Unable to open %s in write-only mode\n", outfile
);
1539 len
= read(ifd
, buf
, sizeof(buf
));
1541 ast_log(LOG_WARNING
, "Read failed on %s: %s\n", infile
, strerror(errno
));
1547 res
= write(ofd
, buf
, len
);
1548 if (errno
== ENOMEM
|| errno
== ENOSPC
|| res
!= len
) {
1549 ast_log(LOG_WARNING
, "Write failed on %s (%d of %d): %s\n", outfile
, res
, len
, strerror(errno
));
1559 #ifdef HARDLINK_WHEN_POSSIBLE
1561 /* Hard link succeeded */
1567 static void copy_plain_file(char *frompath
, char *topath
)
1569 char frompath2
[PATH_MAX
], topath2
[PATH_MAX
];
1570 ast_filecopy(frompath
, topath
, NULL
);
1571 snprintf(frompath2
, sizeof(frompath2
), "%s.txt", frompath
);
1572 snprintf(topath2
, sizeof(topath2
), "%s.txt", topath
);
1573 copy(frompath2
, topath2
);
1576 static int vm_delete(char *file
)
1581 txtsize
= (strlen(file
) + 5)*sizeof(char);
1582 txt
= alloca(txtsize
);
1583 /* Sprintf here would safe because we alloca'd exactly the right length,
1584 * but trying to eliminate all sprintf's anyhow
1586 snprintf(txt
, txtsize
, "%s.txt", file
);
1588 return ast_filedelete(file
, NULL
);
1591 static int inbuf(struct baseio
*bio
, FILE *fi
)
1598 if ((l
= fread(bio
->iobuf
,1,BASEMAXINLINE
,fi
)) <= 0) {
1612 static int inchar(struct baseio
*bio
, FILE *fi
)
1614 if (bio
->iocp
>=bio
->iolen
) {
1615 if (!inbuf(bio
, fi
))
1619 return bio
->iobuf
[bio
->iocp
++];
1622 static int ochar(struct baseio
*bio
, int c
, FILE *so
)
1624 if (bio
->linelength
>=BASELINELEN
) {
1625 if (fputs(eol
,so
)==EOF
)
1631 if (putc(((unsigned char)c
),so
)==EOF
)
1639 static int base_encode(char *filename
, FILE *so
)
1641 unsigned char dtable
[BASEMAXINLINE
];
1646 memset(&bio
, 0, sizeof(bio
));
1647 bio
.iocp
= BASEMAXINLINE
;
1649 if (!(fi
= fopen(filename
, "rb"))) {
1650 ast_log(LOG_WARNING
, "Failed to open file: %s: %s\n", filename
, strerror(errno
));
1654 for (i
= 0;i
<9;i
++) {
1657 dtable
[26+i
]= 'a'+i
;
1658 dtable
[26+i
+9]= 'j'+i
;
1660 for (i
= 0;i
<8;i
++) {
1661 dtable
[i
+18]= 'S'+i
;
1662 dtable
[26+i
+18]= 's'+i
;
1664 for (i
= 0;i
<10;i
++) {
1665 dtable
[52+i
]= '0'+i
;
1671 unsigned char igroup
[3],ogroup
[4];
1674 igroup
[0]= igroup
[1]= igroup
[2]= 0;
1676 for (n
= 0;n
<3;n
++) {
1677 if ((c
= inchar(&bio
, fi
)) == EOF
) {
1682 igroup
[n
]= (unsigned char)c
;
1686 ogroup
[0]= dtable
[igroup
[0]>>2];
1687 ogroup
[1]= dtable
[((igroup
[0]&3)<<4)|(igroup
[1]>>4)];
1688 ogroup
[2]= dtable
[((igroup
[1]&0xF)<<2)|(igroup
[2]>>6)];
1689 ogroup
[3]= dtable
[igroup
[2]&0x3F];
1699 ochar(&bio
, ogroup
[i
], so
);
1705 if (fputs(eol
,so
)==EOF
)
1711 static void prep_email_sub_vars(struct ast_channel
*ast
, struct ast_vm_user
*vmu
, int msgnum
, char *context
, char *mailbox
, char *cidnum
, char *cidname
, char *dur
, char *date
, char *passdata
, size_t passdatasize
, const char *category
)
1714 /* Prepare variables for substition in email body and subject */
1715 pbx_builtin_setvar_helper(ast
, "VM_NAME", vmu
->fullname
);
1716 pbx_builtin_setvar_helper(ast
, "VM_DUR", dur
);
1717 snprintf(passdata
, passdatasize
, "%d", msgnum
);
1718 pbx_builtin_setvar_helper(ast
, "VM_MSGNUM", passdata
);
1719 pbx_builtin_setvar_helper(ast
, "VM_CONTEXT", context
);
1720 pbx_builtin_setvar_helper(ast
, "VM_MAILBOX", mailbox
);
1721 pbx_builtin_setvar_helper(ast
, "VM_CALLERID", ast_callerid_merge(callerid
, sizeof(callerid
), cidname
, cidnum
, "Unknown Caller"));
1722 pbx_builtin_setvar_helper(ast
, "VM_CIDNAME", (cidname
? cidname
: "an unknown caller"));
1723 pbx_builtin_setvar_helper(ast
, "VM_CIDNUM", (cidnum
? cidnum
: "an unknown caller"));
1724 pbx_builtin_setvar_helper(ast
, "VM_DATE", date
);
1725 pbx_builtin_setvar_helper(ast
, "VM_CATEGORY", category
? ast_strdupa(category
) : "no category");
1728 static char *quote(const char *from
, char *to
, size_t len
)
1732 for (; ptr
< to
+ len
- 1; from
++) {
1735 else if (*from
== '\0')
1739 if (ptr
< to
+ len
- 1)
1745 * fill in *tm for current time according to the proper timezone, if any.
1746 * Return tm so it can be used as a function argument.
1748 static const struct tm
*vmu_tm(const struct ast_vm_user
*vmu
, struct tm
*tm
)
1750 const struct vm_zone
*z
= NULL
;
1751 time_t t
= time(NULL
);
1753 /* Does this user have a timezone specified? */
1754 if (!ast_strlen_zero(vmu
->zonetag
)) {
1755 /* Find the zone in the list */
1756 AST_LIST_LOCK(&zones
);
1757 AST_LIST_TRAVERSE(&zones
, z
, list
) {
1758 if (!strcmp(z
->name
, vmu
->zonetag
))
1761 AST_LIST_UNLOCK(&zones
);
1763 ast_localtime(&t
, tm
, z
? z
->timezone
: NULL
);
1767 /* same as mkstemp, but return a FILE * */
1768 static FILE *vm_mkftemp(char *template)
1771 int pfd
= mkstemp(template);
1772 chmod(template, VOICEMAIL_FILE_MODE
& ~my_umask
);
1774 p
= fdopen(pfd
, "w+");
1783 static void make_email_file(FILE *p
, char *srcemail
, struct ast_vm_user
*vmu
, int msgnum
, char *context
, char *mailbox
, char *cidnum
, char *cidname
, char *attach
, char *format
, int duration
, int attach_user_voicemail
, struct ast_channel
*chan
, const char *category
, int imap
)
1786 char host
[MAXHOSTNAMELEN
] = "";
1794 size_t len_passdata
;
1801 gethostname(host
, sizeof(host
) - 1);
1802 if (strchr(srcemail
, '@'))
1803 ast_copy_string(who
, srcemail
, sizeof(who
));
1805 snprintf(who
, sizeof(who
), "%s@%s", srcemail
, host
);
1807 snprintf(dur
, sizeof(dur
), "%d:%02d", duration
/ 60, duration
% 60);
1808 strftime(date
, sizeof(date
), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu
, &tm
));
1809 fprintf(p
, "Date: %s" ENDL
, date
);
1811 /* Set date format for voicemail mail */
1812 strftime(date
, sizeof(date
), emaildateformat
, &tm
);
1815 struct ast_channel
*ast
;
1816 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1818 int vmlen
= strlen(fromstring
)*3 + 200;
1819 if ((passdata
= alloca(vmlen
))) {
1820 memset(passdata
, 0, vmlen
);
1821 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1822 pbx_substitute_variables_helper(ast
, fromstring
, passdata
, vmlen
);
1823 len_passdata
= strlen(passdata
) * 2 + 3;
1824 passdata2
= alloca(len_passdata
);
1825 fprintf(p
, "From: %s <%s>" ENDL
, quote(passdata
, passdata2
, len_passdata
), who
);
1827 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1828 ast_channel_free(ast
);
1830 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1832 fprintf(p
, "From: Asterisk PBX <%s>" ENDL
, who
);
1833 len_passdata
= strlen(vmu
->fullname
) * 2 + 3;
1834 passdata2
= alloca(len_passdata
);
1835 fprintf(p
, "To: %s <%s>" ENDL
, quote(vmu
->fullname
, passdata2
, len_passdata
), vmu
->email
);
1837 struct ast_channel
*ast
;
1838 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1840 int vmlen
= strlen(emailsubject
)*3 + 200;
1841 if ((passdata
= alloca(vmlen
))) {
1842 memset(passdata
, 0, vmlen
);
1843 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1844 pbx_substitute_variables_helper(ast
, emailsubject
, passdata
, vmlen
);
1845 fprintf(p
, "Subject: %s" ENDL
, passdata
);
1847 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1848 ast_channel_free(ast
);
1850 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1851 } else if (*emailtitle
) {
1852 fprintf(p
, emailtitle
, msgnum
+ 1, mailbox
) ;
1854 } else if (ast_test_flag((&globalflags
), VM_PBXSKIP
))
1855 fprintf(p
, "Subject: New message %d in mailbox %s" ENDL
, msgnum
+ 1, mailbox
);
1857 fprintf(p
, "Subject: [PBX]: New message %d in mailbox %s" ENDL
, msgnum
+ 1, mailbox
);
1858 fprintf(p
, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL
, msgnum
+ 1, (unsigned int)ast_random(), mailbox
, (int)getpid(), host
);
1860 /* additional information needed for IMAP searching */
1861 fprintf(p
, "X-Asterisk-VM-Message-Num: %d" ENDL
, msgnum
+ 1);
1862 /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
1863 fprintf(p
, "X-Asterisk-VM-Server-Name: %s" ENDL
, fromstring
);
1864 fprintf(p
, "X-Asterisk-VM-Context: %s" ENDL
, context
);
1865 fprintf(p
, "X-Asterisk-VM-Extension: %s" ENDL
, mailbox
);
1866 fprintf(p
, "X-Asterisk-VM-Priority: %d" ENDL
, chan
->priority
);
1867 fprintf(p
, "X-Asterisk-VM-Caller-channel: %s" ENDL
, chan
->name
);
1868 fprintf(p
, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL
, cidnum
);
1869 fprintf(p
, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL
, cidname
);
1870 fprintf(p
, "X-Asterisk-VM-Duration: %d" ENDL
, duration
);
1871 if (!ast_strlen_zero(category
))
1872 fprintf(p
, "X-Asterisk-VM-Category: %s" ENDL
, category
);
1873 fprintf(p
, "X-Asterisk-VM-Orig-date: %s" ENDL
, date
);
1874 fprintf(p
, "X-Asterisk-VM-Orig-time: %ld" ENDL
, (long)time(NULL
));
1876 if (!ast_strlen_zero(cidnum
))
1877 fprintf(p
, "X-Asterisk-CallerID: %s" ENDL
, cidnum
);
1878 if (!ast_strlen_zero(cidname
))
1879 fprintf(p
, "X-Asterisk-CallerIDName: %s" ENDL
, cidname
);
1880 fprintf(p
, "MIME-Version: 1.0" ENDL
);
1881 if (attach_user_voicemail
) {
1882 /* Something unique. */
1883 snprintf(bound
, sizeof(bound
), "----voicemail_%d%s%d%d", msgnum
+ 1, mailbox
, (int)getpid(), (unsigned int)ast_random());
1885 fprintf(p
, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL
, bound
);
1886 fprintf(p
, ENDL ENDL
"This is a multi-part message in MIME format." ENDL ENDL
);
1887 fprintf(p
, "--%s" ENDL
, bound
);
1889 fprintf(p
, "Content-Type: text/plain; charset=%s" ENDL
"Content-Transfer-Encoding: 8bit" ENDL ENDL
, charset
);
1891 struct ast_channel
*ast
;
1892 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1894 int vmlen
= strlen(emailbody
)*3 + 200;
1895 if ((passdata
= alloca(vmlen
))) {
1896 memset(passdata
, 0, vmlen
);
1897 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1898 pbx_substitute_variables_helper(ast
, emailbody
, passdata
, vmlen
);
1899 fprintf(p
, "%s" ENDL
, passdata
);
1901 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1902 ast_channel_free(ast
);
1904 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1906 fprintf(p
, "Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
1908 "in mailbox %s from %s, on %s so you might" ENDL
1909 "want to check it when you get a chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk" ENDL ENDL
, vmu
->fullname
,
1910 dur
, msgnum
+ 1, mailbox
, (cidname
? cidname
: (cidnum
? cidnum
: "an unknown caller")), date
);
1912 if (attach_user_voicemail
) {
1913 /* Eww. We want formats to tell us their own MIME type */
1914 char *ctype
= (!strcasecmp(format
, "ogg")) ? "application/" : "audio/x-";
1915 char tmpdir
[256], newtmp
[256];
1918 if (vmu
->volgain
< -.001 || vmu
->volgain
> .001) {
1919 create_dirpath(tmpdir
, sizeof(tmpdir
), vmu
->context
, vmu
->mailbox
, "tmp");
1920 snprintf(newtmp
, sizeof(newtmp
), "%s/XXXXXX", tmpdir
);
1921 tmpfd
= mkstemp(newtmp
);
1922 chmod(newtmp
, VOICEMAIL_FILE_MODE
& ~my_umask
);
1923 if (option_debug
> 2)
1924 ast_log(LOG_DEBUG
, "newtmp: %s\n", newtmp
);
1926 snprintf(tmpcmd
, sizeof(tmpcmd
), "sox -v %.4f %s.%s %s.%s", vmu
->volgain
, attach
, format
, newtmp
, format
);
1927 ast_safe_system(tmpcmd
);
1929 if (option_debug
> 2)
1930 ast_log(LOG_DEBUG
, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach
, format
, vmu
->volgain
, mailbox
);
1933 fprintf(p
, "--%s" ENDL
, bound
);
1934 fprintf(p
, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL
, ctype
, format
, msgnum
+ 1, format
);
1935 fprintf(p
, "Content-Transfer-Encoding: base64" ENDL
);
1936 fprintf(p
, "Content-Description: Voicemail sound attachment." ENDL
);
1937 fprintf(p
, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL
, msgnum
+ 1, format
);
1938 snprintf(fname
, sizeof(fname
), "%s.%s", attach
, format
);
1939 base_encode(fname
, p
);
1940 fprintf(p
, ENDL
"--%s--" ENDL
"." ENDL
, bound
);
1949 static int sendmail(char *srcemail
, struct ast_vm_user
*vmu
, int msgnum
, char *context
, char *mailbox
, char *cidnum
, char *cidname
, char *attach
, char *format
, int duration
, int attach_user_voicemail
, struct ast_channel
*chan
, const char *category
)
1952 char tmp
[80] = "/tmp/astmail-XXXXXX";
1955 if (vmu
&& ast_strlen_zero(vmu
->email
)) {
1956 ast_log(LOG_WARNING
, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu
->mailbox
);
1959 if (!strcmp(format
, "wav49"))
1961 if (option_debug
> 2)
1962 ast_log(LOG_DEBUG
, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach
, format
, attach_user_voicemail
, ast_test_flag((&globalflags
), VM_ATTACH
));
1963 /* Make a temporary file instead of piping directly to sendmail, in case the mail
1965 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
1966 ast_log(LOG_WARNING
, "Unable to launch '%s' (can't create temporary file)\n", mailcmd
);
1969 make_email_file(p
, srcemail
, vmu
, msgnum
, context
, mailbox
, cidnum
, cidname
, attach
, format
, duration
, attach_user_voicemail
, chan
, category
, 0);
1971 snprintf(tmp2
, sizeof(tmp2
), "( %s < %s ; rm -f %s ) &", mailcmd
, tmp
, tmp
);
1972 ast_safe_system(tmp2
);
1973 if (option_debug
> 2)
1974 ast_log(LOG_DEBUG
, "Sent mail to %s with command '%s'\n", vmu
->email
, mailcmd
);
1979 static int sendpage(char *srcemail
, char *pager
, int msgnum
, char *context
, char *mailbox
, char *cidnum
, char *cidname
, int duration
, struct ast_vm_user
*vmu
, const char *category
)
1982 char host
[MAXHOSTNAMELEN
] = "";
1985 char tmp
[80] = "/tmp/astmail-XXXXXX";
1986 char tmp2
[PATH_MAX
];
1990 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
1991 ast_log(LOG_WARNING
, "Unable to launch '%s' (can't create temporary file)\n", mailcmd
);
1994 gethostname(host
, sizeof(host
)-1);
1995 if (strchr(srcemail
, '@'))
1996 ast_copy_string(who
, srcemail
, sizeof(who
));
1998 snprintf(who
, sizeof(who
), "%s@%s", srcemail
, host
);
2000 snprintf(dur
, sizeof(dur
), "%d:%02d", duration
/ 60, duration
% 60);
2001 strftime(date
, sizeof(date
), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu
, &tm
));
2002 fprintf(p
, "Date: %s\n", date
);
2004 if (*pagerfromstring
) {
2005 struct ast_channel
*ast
;
2006 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
2008 int vmlen
= strlen(fromstring
)*3 + 200;
2009 if ((passdata
= alloca(vmlen
))) {
2010 memset(passdata
, 0, vmlen
);
2011 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
2012 pbx_substitute_variables_helper(ast
, pagerfromstring
, passdata
, vmlen
);
2013 fprintf(p
, "From: %s <%s>\n", passdata
, who
);
2015 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
2016 ast_channel_free(ast
);
2017 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2019 fprintf(p
, "From: Asterisk PBX <%s>\n", who
);
2020 fprintf(p
, "To: %s\n", pager
);
2022 struct ast_channel
*ast
;
2023 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
2025 int vmlen
= strlen(pagersubject
) * 3 + 200;
2026 if ((passdata
= alloca(vmlen
))) {
2027 memset(passdata
, 0, vmlen
);
2028 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
2029 pbx_substitute_variables_helper(ast
, pagersubject
, passdata
, vmlen
);
2030 fprintf(p
, "Subject: %s\n\n", passdata
);
2031 } else ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
2032 ast_channel_free(ast
);
2033 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2035 fprintf(p
, "Subject: New VM\n\n");
2036 strftime(date
, sizeof(date
), "%A, %B %d, %Y at %r", &tm
);
2038 struct ast_channel
*ast
;
2039 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
2041 int vmlen
= strlen(pagerbody
)*3 + 200;
2042 if ((passdata
= alloca(vmlen
))) {
2043 memset(passdata
, 0, vmlen
);
2044 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
2045 pbx_substitute_variables_helper(ast
, pagerbody
, passdata
, vmlen
);
2046 fprintf(p
, "%s\n", passdata
);
2047 } else ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
2048 ast_channel_free(ast
);
2049 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2051 fprintf(p
, "New %s long msg in box %s\n"
2052 "from %s, on %s", dur
, mailbox
, (cidname
? cidname
: (cidnum
? cidnum
: "unknown")), date
);
2055 snprintf(tmp2
, sizeof(tmp2
), "( %s < %s ; rm -f %s ) &", mailcmd
, tmp
, tmp
);
2056 ast_safe_system(tmp2
);
2057 if (option_debug
> 2)
2058 ast_log(LOG_DEBUG
, "Sent page to %s with command '%s'\n", pager
, mailcmd
);
2063 static int get_date(char *s
, int len
)
2070 ast_localtime(&t
, &tm
, NULL
);
2072 return strftime(s
, len
, "%a %b %e %r %Z %Y", &tm
);
2075 static int play_greeting(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *filename
, char *ecodes
)
2082 RETRIEVE(filename
, -1);
2083 if (ast_fileexists(filename
, NULL
, NULL
) > 0) {
2084 res
= ast_streamfile(chan
, filename
, chan
->language
);
2086 res
= ast_waitstream(chan
, ecodes
);
2088 if (success
== -1) {
2089 /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
2091 ast_log(LOG_DEBUG
, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
2092 store_file(filename
, vmu
->mailbox
, vmu
->context
, -1);
2096 DISPOSE(filename
, -1);
2101 static int invent_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *ext
, int busy
, char *ecodes
)
2105 char dest
[PATH_MAX
];
2107 snprintf(fn
, sizeof(fn
), "%s%s/%s/greet", VM_SPOOL_DIR
, vmu
->context
, ext
);
2109 if ((res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "greet"))) {
2110 ast_log(LOG_WARNING
, "Failed to make directory(%s)\n", fn
);
2114 res
= play_greeting(chan
, vmu
, fn
, ecodes
);
2116 /* File did not exist */
2117 res
= ast_stream_and_wait(chan
, "vm-theperson", chan
->language
, ecodes
);
2120 res
= ast_say_digit_str(chan
, ext
, ecodes
, chan
->language
);
2126 res
= ast_stream_and_wait(chan
, busy
? "vm-isonphone" : "vm-isunavail", chan
->language
, ecodes
);
2130 static void free_user(struct ast_vm_user
*vmu
)
2132 if (ast_test_flag(vmu
, VM_ALLOCED
))
2136 static void free_zone(struct vm_zone
*z
)
2141 static const char *mbox(int id
)
2143 static const char *msgs
[] = {
2155 return (id
>= 0 && id
< (sizeof(msgs
)/sizeof(msgs
[0]))) ? msgs
[id
] : "tmp";
2158 static int folder_int(const char *folder
)
2160 /*assume a NULL folder means INBOX*/
2163 if (!strcasecmp(folder
, "INBOX"))
2165 else if (!strcasecmp(folder
, "Old"))
2167 else if (!strcasecmp(folder
, "Work"))
2169 else if (!strcasecmp(folder
, "Family"))
2171 else if (!strcasecmp(folder
, "Friends"))
2173 else if (!strcasecmp(folder
, "Cust1"))
2175 else if (!strcasecmp(folder
, "Cust2"))
2177 else if (!strcasecmp(folder
, "Cust3"))
2179 else if (!strcasecmp(folder
, "Cust4"))
2181 else if (!strcasecmp(folder
, "Cust5"))
2183 else /*assume they meant INBOX if folder is not found otherwise*/
2189 /*! XXX \todo Fix this function to support multiple mailboxes in the intput string */
2190 static int inboxcount(const char *mailbox
, int *newmsgs
, int *oldmsgs
)
2197 char tmp
[PATH_MAX
] = "";
2198 struct odbc_obj
*obj
;
2200 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 0 };
2207 /* If no mailbox, return immediately */
2208 if (ast_strlen_zero(mailbox
))
2211 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2213 context
= strchr(tmp
, '@');
2218 context
= "default";
2220 obj
= ast_odbc_request_obj(odbc_database
, 0);
2222 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, tmp
, "INBOX");
2223 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2225 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2226 ast_odbc_release_obj(obj
);
2229 res
= SQLFetch(stmt
);
2230 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2231 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2232 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2233 ast_odbc_release_obj(obj
);
2236 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2237 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2238 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2239 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2240 ast_odbc_release_obj(obj
);
2243 *newmsgs
= atoi(rowdata
);
2244 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2246 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, tmp
, "Old");
2247 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2249 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2250 ast_odbc_release_obj(obj
);
2253 res
= SQLFetch(stmt
);
2254 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2255 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2256 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2257 ast_odbc_release_obj(obj
);
2260 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2261 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2262 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2263 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2264 ast_odbc_release_obj(obj
);
2267 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2268 ast_odbc_release_obj(obj
);
2269 *oldmsgs
= atoi(rowdata
);
2272 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
2278 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2280 struct odbc_obj
*obj
= NULL
;
2283 SQLHSTMT stmt
= NULL
;
2286 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 0 };
2289 /* If no mailbox, return immediately */
2290 if (ast_strlen_zero(mailbox
))
2293 obj
= ast_odbc_request_obj(odbc_database
, 0);
2295 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, mailbox
, folder
);
2296 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2298 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2301 res
= SQLFetch(stmt
);
2302 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2303 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2304 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2307 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2308 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2309 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2310 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2313 nummsgs
= atoi(rowdata
);
2314 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2316 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
2320 ast_odbc_release_obj(obj
);
2324 static int has_voicemail(const char *mailbox
, const char *folder
)
2326 char tmp
[256], *tmp2
= tmp
, *mbox
, *context
;
2327 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2328 while ((context
= mbox
= strsep(&tmp2
, ","))) {
2329 strsep(&context
, "@");
2330 if (ast_strlen_zero(context
))
2331 context
= "default";
2332 if (messagecount(context
, mbox
, folder
))
2338 #elif defined(IMAP_STORAGE)
2340 static int imap_store_file(char *dir
, char *mailboxuser
, char *mailboxcontext
, int msgnum
, struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *fmt
, int duration
, struct vm_state
*vms
)
2342 char *myserveremail
= serveremail
;
2347 char tmp
[80] = "/tmp/astmail-XXXXXX";
2353 /*Greetings are not retrieved from IMAP, so there is no reason to attempt storing them there either*/
2357 /* Attach only the first format */
2358 fmt
= ast_strdupa(fmt
);
2360 strsep(&stringp
, "|");
2362 if (!ast_strlen_zero(vmu
->serveremail
))
2363 myserveremail
= vmu
->serveremail
;
2365 make_file(fn
, sizeof(fn
), dir
, msgnum
);
2367 if (ast_strlen_zero(vmu
->email
)) {
2368 /*we need the vmu->email to be set when we call make_email_file, but if we keep it set,
2369 * a duplicate e-mail will be created. So at the end of this function, we will revert back to an empty
2370 * string if tempcopy is 1
2372 ast_copy_string(vmu
->email
, vmu
->imapuser
, sizeof(vmu
->email
));
2376 if (!strcmp(fmt
, "wav49"))
2378 if (option_debug
> 2)
2379 ast_log(LOG_DEBUG
, "Storing file '%s', format '%s'\n", fn
, fmt
);
2380 /* Make a temporary file instead of piping directly to sendmail, in case the mail
2382 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
2383 ast_log(LOG_WARNING
, "Unable to store '%s' (can't create temporary file)\n", fn
);
2385 *(vmu
->email
) = '\0';
2388 make_email_file(p
, myserveremail
, vmu
, msgnum
, vmu
->context
, vmu
->mailbox
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
), fn
, fmt
, duration
, 1, chan
, NULL
, 1);
2389 /* read mail file to memory */
2392 if ((buf
= ast_malloc(len
+1)) == NIL
) {
2393 ast_log(LOG_ERROR
, "Can't allocate %ld bytes to read message\n", len
+1);
2397 fread(buf
, len
, 1, p
);
2398 ((char *)buf
)[len
] = '\0';
2399 INIT(&str
, mail_string
, buf
, len
);
2400 init_mailstream(vms
, 0);
2401 imap_mailbox_name(mailbox
, sizeof(mailbox
), vms
, 0, 1);
2402 if (!mail_append(vms
->mailstream
, mailbox
, &str
))
2403 ast_log(LOG_ERROR
, "Error while sending the message to %s\n", mailbox
);
2407 if (option_debug
> 2)
2408 ast_log(LOG_DEBUG
, "%s stored\n", fn
);
2411 *(vmu
->email
) = '\0';
2416 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2421 struct ast_vm_user
*vmu
, vmus
;
2422 struct vm_state
*vms_p
;
2424 int fold
= folder_int(folder
);
2426 if (ast_strlen_zero(mailbox
))
2429 /* We have to get the user before we can open the stream! */
2430 /* ast_log (LOG_DEBUG,"Before find_user, context is %s and mailbox is %s\n",context,mailbox); */
2431 vmu
= find_user(&vmus
, context
, mailbox
);
2433 ast_log (LOG_ERROR
,"Couldn't find mailbox %s in context %s\n",mailbox
,context
);
2436 /* No IMAP account available */
2437 if (vmu
->imapuser
[0] == '\0') {
2438 ast_log (LOG_WARNING
,"IMAP user not set for mailbox %s\n",vmu
->mailbox
);
2443 /* check if someone is accessing this box right now... */
2444 vms_p
= get_vm_state_by_imapuser(vmu
->imapuser
,1);
2446 vms_p
= get_vm_state_by_mailbox(mailbox
,1);
2449 if (option_debug
> 2)
2450 ast_log (LOG_DEBUG
,"Returning before search - user is logged in\n");
2451 if (fold
== 0) {/*INBOX*/
2452 return vms_p
->newmessages
;
2454 if (fold
== 1) {/*Old messages*/
2455 return vms_p
->oldmessages
;
2459 /* add one if not there... */
2460 vms_p
= get_vm_state_by_imapuser(vmu
->imapuser
,0);
2462 vms_p
= get_vm_state_by_mailbox(mailbox
,0);
2466 if (option_debug
> 2)
2467 ast_log (LOG_DEBUG
,"Adding new vmstate for %s\n",vmu
->imapuser
);
2468 if (!(vms_p
= ast_calloc(1, sizeof(*vms_p
)))) {
2471 ast_copy_string(vms_p
->imapuser
,vmu
->imapuser
, sizeof(vms_p
->imapuser
));
2472 ast_copy_string(vms_p
->username
, mailbox
, sizeof(vms_p
->username
)); /* save for access from interactive entry point */
2473 vms_p
->mailstream
= NIL
; /* save for access from interactive entry point */
2474 if (option_debug
> 2)
2475 ast_log (LOG_DEBUG
,"Copied %s to %s\n",vmu
->imapuser
,vms_p
->imapuser
);
2477 /* set mailbox to INBOX! */
2478 ast_copy_string(vms_p
->curbox
, mbox(fold
), sizeof(vms_p
->curbox
));
2479 init_vm_state(vms_p
);
2480 vmstate_insert(vms_p
);
2482 ret
= init_mailstream(vms_p
, fold
);
2483 if (!vms_p
->mailstream
) {
2484 ast_log (LOG_ERROR
,"IMAP mailstream is NULL\n");
2488 pgm
= mail_newsearchpgm ();
2489 hdr
= mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox
);
2495 /* In the special case where fold is 1 (old messages) we have to do things a bit
2496 * differently. Old messages are stored in the INBOX but are marked as "seen"
2505 vms_p
->vmArrayIndex
= 0;
2506 mail_search_full (vms_p
->mailstream
, NULL
, pgm
, NIL
);
2508 vms_p
->newmessages
= vms_p
->vmArrayIndex
;
2510 vms_p
->oldmessages
= vms_p
->vmArrayIndex
;
2511 /*Freeing the searchpgm also frees the searchhdr*/
2512 mail_free_searchpgm(&pgm
);
2514 return vms_p
->vmArrayIndex
;
2516 mail_ping(vms_p
->mailstream
);
2520 static int inboxcount(const char *mailbox_context
, int *newmsgs
, int *oldmsgs
)
2522 char tmp
[PATH_MAX
] = "";
2532 if (option_debug
> 2)
2533 ast_log (LOG_DEBUG
,"Mailbox is set to %s\n",mailbox_context
);
2534 /* If no mailbox, return immediately */
2535 if (ast_strlen_zero(mailbox_context
))
2538 ast_copy_string(tmp
, mailbox_context
, sizeof(tmp
));
2539 context
= strchr(tmp
, '@');
2540 if (strchr(mailbox_context
, ',')) {
2542 ast_copy_string(tmp
, mailbox_context
, sizeof(tmp
));
2544 while ((cur
= strsep(&mb
, ", "))) {
2545 if (!ast_strlen_zero(cur
)) {
2546 if (inboxcount(cur
, newmsgs
? &tmpnew
: NULL
, oldmsgs
? &tmpold
: NULL
))
2563 context
= "default";
2564 mailboxnc
= (char *)mailbox_context
;
2567 if ((*newmsgs
= messagecount(context
, mailboxnc
, "INBOX")) < 0)
2571 if ((*oldmsgs
= messagecount(context
, mailboxnc
, "Old")) < 0)
2578 static int has_voicemail(const char *mailbox
, const char *folder
)
2580 char tmp
[256], *tmp2
, *mbox
, *context
;
2581 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2583 if (strchr(tmp2
, ',')) {
2584 while ((mbox
= strsep(&tmp2
, ","))) {
2585 if (!ast_strlen_zero(mbox
)) {
2586 if (has_voicemail(mbox
, folder
))
2591 if ((context
= strchr(tmp
, '@')))
2594 context
= "default";
2595 return messagecount(context
, tmp
, folder
) ? 1 : 0;
2598 static int copy_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int imbox
, int msgnum
, long duration
, struct ast_vm_user
*recip
, char *fmt
, char *dir
)
2600 struct vm_state
*sendvms
= NULL
, *destvms
= NULL
;
2601 char messagestring
[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
2602 if (msgnum
>= recip
->maxmsg
) {
2603 ast_log(LOG_WARNING
, "Unable to copy mail, mailbox %s is full\n", recip
->mailbox
);
2606 if (!(sendvms
= get_vm_state_by_imapuser(vmu
->imapuser
, 0))) {
2607 ast_log(LOG_ERROR
, "Couldn't get vm_state for originator's mailbox!!\n");
2610 if (!(destvms
= get_vm_state_by_imapuser(recip
->imapuser
, 0))) {
2611 ast_log(LOG_ERROR
, "Couldn't get vm_state for destination mailbox!\n");
2614 snprintf(messagestring
, sizeof(messagestring
), "%ld", sendvms
->msgArray
[msgnum
]);
2615 if ((mail_copy(sendvms
->mailstream
, messagestring
, (char *) mbox(imbox
)) == T
))
2617 ast_log(LOG_WARNING
, "Unable to copy message from mailbox %s to mailbox %s\n", vmu
->mailbox
, recip
->mailbox
);
2622 #ifndef IMAP_STORAGE
2623 /* copy message only used by file storage */
2624 static int copy_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int imbox
, int msgnum
, long duration
, struct ast_vm_user
*recip
, char *fmt
, char *dir
)
2626 char fromdir
[PATH_MAX
], todir
[PATH_MAX
], frompath
[PATH_MAX
], topath
[PATH_MAX
];
2627 const char *frombox
= mbox(imbox
);
2630 ast_log(LOG_NOTICE
, "Copying message from %s@%s to %s@%s\n", vmu
->mailbox
, vmu
->context
, recip
->mailbox
, recip
->context
);
2632 create_dirpath(todir
, sizeof(todir
), recip
->context
, recip
->mailbox
, "INBOX");
2635 make_dir(fromdir
, sizeof(fromdir
), vmu
->context
, vmu
->mailbox
, frombox
);
2637 ast_copy_string(fromdir
, dir
, sizeof(fromdir
));
2639 make_file(frompath
, sizeof(frompath
), fromdir
, msgnum
);
2641 if (vm_lock_path(todir
))
2642 return ERROR_LOCK_PATH
;
2646 make_file(topath
, sizeof(topath
), todir
, recipmsgnum
);
2647 if (!EXISTS(todir
, recipmsgnum
, topath
, chan
->language
))
2650 } while (recipmsgnum
< recip
->maxmsg
);
2651 if (recipmsgnum
< recip
->maxmsg
) {
2652 COPY(fromdir
, msgnum
, todir
, recipmsgnum
, recip
->mailbox
, recip
->context
, frompath
, topath
);
2654 ast_log(LOG_ERROR
, "Recipient mailbox %s@%s is full\n", recip
->mailbox
, recip
->context
);
2656 ast_unlock_path(todir
);
2657 notify_new_message(chan
, recip
, recipmsgnum
, duration
, fmt
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
));
2662 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
2663 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2665 return __has_voicemail(context
, mailbox
, folder
, 0);
2669 static int __has_voicemail(const char *context
, const char *mailbox
, const char *folder
, int shortcircuit
)
2677 /* If no mailbox, return immediately */
2678 if (ast_strlen_zero(mailbox
))
2681 context
= "default";
2682 snprintf(fn
, sizeof(fn
), "%s%s/%s/%s", VM_SPOOL_DIR
, context
, mailbox
, folder
);
2686 while ((de
= readdir(dir
))) {
2687 if (!strncasecmp(de
->d_name
, "msg", 3)) {
2691 } else if (!strncasecmp(de
->d_name
+ 8, "txt", 3))
2700 static int has_voicemail(const char *mailbox
, const char *folder
)
2702 char tmp
[256], *tmp2
= tmp
, *mbox
, *context
;
2703 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2704 while ((mbox
= strsep(&tmp2
, ","))) {
2705 if ((context
= strchr(mbox
, '@')))
2708 context
= "default";
2709 if (__has_voicemail(context
, mbox
, folder
, 1))
2716 static int inboxcount(const char *mailbox
, int *newmsgs
, int *oldmsgs
)
2725 /* If no mailbox, return immediately */
2726 if (ast_strlen_zero(mailbox
))
2728 if (strchr(mailbox
, ',')) {
2732 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2734 while ((cur
= strsep(&mb
, ", "))) {
2735 if (!ast_strlen_zero(cur
)) {
2736 if (inboxcount(cur
, newmsgs
? &tmpnew
: NULL
, oldmsgs
? &tmpold
: NULL
))
2748 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2749 context
= strchr(tmp
, '@');
2754 context
= "default";
2756 *newmsgs
= __has_voicemail(context
, tmp
, "INBOX", 0);
2758 *oldmsgs
= __has_voicemail(context
, tmp
, "Old", 0);
2764 static void run_externnotify(char *context
, char *extension
)
2766 char arguments
[255];
2767 char ext_context
[256] = "";
2768 int newvoicemails
= 0, oldvoicemails
= 0;
2769 struct ast_smdi_mwi_message
*mwi_msg
;
2771 if (!ast_strlen_zero(context
))
2772 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", extension
, context
);
2774 ast_copy_string(ext_context
, extension
, sizeof(ext_context
));
2776 if (!strcasecmp(externnotify
, "smdi")) {
2777 if (ast_app_has_voicemail(ext_context
, NULL
))
2778 ast_smdi_mwi_set(smdi_iface
, extension
);
2780 ast_smdi_mwi_unset(smdi_iface
, extension
);
2782 if ((mwi_msg
= ast_smdi_mwi_message_wait_station(smdi_iface
, SMDI_MWI_WAIT_TIMEOUT
, extension
))) {
2783 ast_log(LOG_ERROR
, "Error executing SMDI MWI change for %s\n", extension
);
2784 if (!strncmp(mwi_msg
->cause
, "INV", 3))
2785 ast_log(LOG_ERROR
, "Invalid MWI extension: %s\n", mwi_msg
->fwd_st
);
2786 else if (!strncmp(mwi_msg
->cause
, "BLK", 3))
2787 ast_log(LOG_WARNING
, "MWI light was already on or off for %s\n", mwi_msg
->fwd_st
);
2788 ast_log(LOG_WARNING
, "The switch reported '%s'\n", mwi_msg
->cause
);
2789 ASTOBJ_UNREF(mwi_msg
, ast_smdi_mwi_message_destroy
);
2792 ast_log(LOG_DEBUG
, "Successfully executed SMDI MWI change for %s\n", extension
);
2794 } else if (!ast_strlen_zero(externnotify
)) {
2795 if (inboxcount(ext_context
, &newvoicemails
, &oldvoicemails
)) {
2796 ast_log(LOG_ERROR
, "Problem in calculating number of voicemail messages available for extension %s\n", extension
);
2798 snprintf(arguments
, sizeof(arguments
), "%s %s %s %d&", externnotify
, context
, extension
, newvoicemails
);
2800 ast_log(LOG_DEBUG
, "Executing %s\n", arguments
);
2801 ast_safe_system(arguments
);
2806 struct leave_vm_options
{
2808 signed char record_gain
;
2811 static int leave_voicemail(struct ast_channel
*chan
, char *ext
, struct leave_vm_options
*options
)
2814 int newmsgs
, oldmsgs
;
2815 struct vm_state
*vms
= NULL
;
2817 char txtfile
[PATH_MAX
], tmptxtfile
[PATH_MAX
];
2828 char dir
[PATH_MAX
], tmpdir
[PATH_MAX
];
2829 char dest
[PATH_MAX
];
2831 char prefile
[PATH_MAX
] = "";
2832 char tempfile
[PATH_MAX
] = "";
2833 char ext_context
[256] = "";
2836 char ecodes
[16] = "#";
2837 char tmp
[1024] = "", *tmpptr
;
2838 struct ast_vm_user
*vmu
;
2839 struct ast_vm_user svm
;
2840 const char *category
= NULL
;
2842 ast_copy_string(tmp
, ext
, sizeof(tmp
));
2844 context
= strchr(tmp
, '@');
2847 tmpptr
= strchr(context
, '&');
2849 tmpptr
= strchr(ext
, '&');
2855 category
= pbx_builtin_getvar_helper(chan
, "VM_CATEGORY");
2857 if (option_debug
> 2)
2858 ast_log(LOG_DEBUG
, "Before find_user\n");
2859 if (!(vmu
= find_user(&svm
, context
, ext
))) {
2860 ast_log(LOG_WARNING
, "No entry in voicemail config file for '%s'\n", ext
);
2861 if (ast_test_flag(options
, OPT_PRIORITY_JUMP
) || ast_opt_priority_jumping
)
2862 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
2863 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2866 /* Setup pre-file if appropriate */
2867 if (strcmp(vmu
->context
, "default"))
2868 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", ext
, vmu
->context
);
2870 ast_copy_string(ext_context
, vmu
->mailbox
, sizeof(ext_context
));
2871 if (ast_test_flag(options
, OPT_BUSY_GREETING
)) {
2872 res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "busy");
2873 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, ext
);
2874 } else if (ast_test_flag(options
, OPT_UNAVAIL_GREETING
)) {
2875 res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "unavail");
2876 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, ext
);
2878 snprintf(tempfile
, sizeof(tempfile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, ext
);
2879 if ((res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "temp"))) {
2880 ast_log(LOG_WARNING
, "Failed to make directory (%s)\n", tempfile
);
2883 RETRIEVE(tempfile
, -1);
2884 if (ast_fileexists(tempfile
, NULL
, NULL
) > 0)
2885 ast_copy_string(prefile
, tempfile
, sizeof(prefile
));
2886 DISPOSE(tempfile
, -1);
2887 /* It's easier just to try to make it than to check for its existence */
2888 create_dirpath(dir
, sizeof(dir
), vmu
->context
, ext
, "INBOX");
2889 create_dirpath(tmpdir
, sizeof(tmpdir
), vmu
->context
, ext
, "tmp");
2891 /* Check current or macro-calling context for special extensions */
2892 if (ast_test_flag(vmu
, VM_OPERATOR
)) {
2893 if (!ast_strlen_zero(vmu
->exit
)) {
2894 if (ast_exists_extension(chan
, vmu
->exit
, "o", 1, chan
->cid
.cid_num
)) {
2895 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2898 } else if (ast_exists_extension(chan
, chan
->context
, "o", 1, chan
->cid
.cid_num
)) {
2899 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2902 else if (!ast_strlen_zero(chan
->macrocontext
) && ast_exists_extension(chan
, chan
->macrocontext
, "o", 1, chan
->cid
.cid_num
)) {
2903 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2908 if (!ast_strlen_zero(vmu
->exit
)) {
2909 if (ast_exists_extension(chan
, vmu
->exit
, "a", 1, chan
->cid
.cid_num
))
2910 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2911 } else if (ast_exists_extension(chan
, chan
->context
, "a", 1, chan
->cid
.cid_num
))
2912 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2913 else if (!ast_strlen_zero(chan
->macrocontext
) && ast_exists_extension(chan
, chan
->macrocontext
, "a", 1, chan
->cid
.cid_num
)) {
2914 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2918 /* Play the beginning intro if desired */
2919 if (!ast_strlen_zero(prefile
)) {
2920 res
= play_greeting(chan
, vmu
, prefile
, ecodes
);
2922 /* The file did not exist */
2924 ast_log(LOG_DEBUG
, "%s doesn't exist, doing what we can\n", prefile
);
2925 res
= invent_message(chan
, vmu
, ext
, ast_test_flag(options
, OPT_BUSY_GREETING
), ecodes
);
2929 ast_log(LOG_DEBUG
, "Hang up during prefile playback\n");
2931 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2936 /* On a '#' we skip the instructions */
2937 ast_set_flag(options
, OPT_SILENT
);
2940 if (!res
&& !ast_test_flag(options
, OPT_SILENT
)) {
2941 res
= ast_stream_and_wait(chan
, INTRO
, chan
->language
, ecodes
);
2943 ast_set_flag(options
, OPT_SILENT
);
2948 ast_stopstream(chan
);
2949 /* Check for a '*' here in case the caller wants to escape from voicemail to something
2950 other than the operator -- an automated attendant or mailbox login for example */
2952 chan
->exten
[0] = 'a';
2953 chan
->exten
[1] = '\0';
2954 if (!ast_strlen_zero(vmu
->exit
)) {
2955 ast_copy_string(chan
->context
, vmu
->exit
, sizeof(chan
->context
));
2956 } else if (ausemacro
&& !ast_strlen_zero(chan
->macrocontext
)) {
2957 ast_copy_string(chan
->context
, chan
->macrocontext
, sizeof(chan
->context
));
2961 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "USEREXIT");
2965 /* Check for a '0' here */
2968 if (ouseexten
|| ousemacro
) {
2969 chan
->exten
[0] = 'o';
2970 chan
->exten
[1] = '\0';
2971 if (!ast_strlen_zero(vmu
->exit
)) {
2972 ast_copy_string(chan
->context
, vmu
->exit
, sizeof(chan
->context
));
2973 } else if (ousemacro
&& !ast_strlen_zero(chan
->macrocontext
)) {
2974 ast_copy_string(chan
->context
, chan
->macrocontext
, sizeof(chan
->context
));
2976 ast_play_and_wait(chan
, "transfer");
2979 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "USEREXIT");
2985 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2988 /* The meat of recording the message... All the announcements and beeps have been played*/
2989 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
2990 if (!ast_strlen_zero(fmt
)) {
2994 /* Is ext a mailbox? */
2995 /* must open stream for this user to get info! */
2996 res
= inboxcount(ext_context
, &newmsgs
, &oldmsgs
);
2998 ast_log(LOG_NOTICE
,"Can not leave voicemail, unable to count messages\n");
3001 if (!(vms
= get_vm_state_by_mailbox(ext
,0))) {
3002 /*It is possible under certain circumstances that inboxcount did not create a vm_state when it was needed. This is a catchall which will
3004 if (!(vms
= ast_calloc(1, sizeof(*vms
)))) {
3005 ast_log(LOG_ERROR
, "Couldn't allocate necessary space\n");
3008 ast_copy_string(vms
->imapuser
, vmu
->imapuser
, sizeof(vms
->imapuser
));
3009 ast_copy_string(vms
->username
, ext
, sizeof(vms
->username
));
3010 vms
->mailstream
= NIL
;
3011 if (option_debug
> 2)
3012 ast_log(LOG_DEBUG
, "Copied %s to %s\n", vmu
->imapuser
, vms
->imapuser
);
3014 ast_copy_string(vms
->curbox
, mbox(0), sizeof(vms
->curbox
));
3016 vmstate_insert(vms
);
3017 vms
= get_vm_state_by_mailbox(ext
,0);
3020 /* here is a big difference! We add one to it later */
3021 msgnum
= newmsgs
+ oldmsgs
;
3022 if (option_debug
> 2)
3023 ast_log(LOG_DEBUG
, "Messagecount set to %d\n",msgnum
);
3024 snprintf(fn
, sizeof(fn
), "%s/imap/msg%s%04d", VM_SPOOL_DIR
, vmu
->mailbox
, msgnum
);
3025 /* set variable for compatability */
3026 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", "IMAP_STORAGE");
3028 /* Check if mailbox is full */
3029 check_quota(vms
, imapfolder
);
3030 if (vms
->quota_limit
&& vms
->quota_usage
>= vms
->quota_limit
) {
3032 ast_log(LOG_DEBUG
, "*** QUOTA EXCEEDED!! %u >= %u\n", vms
->quota_usage
, vms
->quota_limit
);
3033 ast_play_and_wait(chan
, "vm-mailboxfull");
3036 if (option_debug
> 2)
3037 ast_log(LOG_DEBUG
, "Checking message number quota - mailbox has %d messages, maximum is set to %d\n",msgnum
,vmu
->maxmsg
);
3038 if (msgnum
>= vmu
->maxmsg
) {
3039 res
= ast_streamfile(chan
, "vm-mailboxfull", chan
->language
);
3041 res
= ast_waitstream(chan
, "");
3042 ast_log(LOG_WARNING
, "No more messages possible\n");
3043 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3047 /* Check if we have exceeded maxmsg */
3048 if (msgnum
>= vmu
->maxmsg
) {
3049 ast_log(LOG_WARNING
, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum
, vmu
->maxmsg
);
3050 ast_play_and_wait(chan
, "vm-mailboxfull");
3053 /* here is a big difference! We add one to it later */
3054 if (option_debug
> 2)
3055 ast_log(LOG_DEBUG
, "Messagecount set to %d\n",msgnum
);
3057 if (count_messages(vmu
, dir
) >= vmu
->maxmsg
) {
3058 res
= ast_streamfile(chan
, "vm-mailboxfull", chan
->language
);
3060 res
= ast_waitstream(chan
, "");
3061 ast_log(LOG_WARNING
, "No more messages possible\n");
3062 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3067 snprintf(tmptxtfile
, sizeof(tmptxtfile
), "%s/XXXXXX", tmpdir
);
3068 txtdes
= mkstemp(tmptxtfile
);
3069 chmod(tmptxtfile
, VOICEMAIL_FILE_MODE
& ~my_umask
);
3071 res
= ast_streamfile(chan
, "vm-mailboxfull", chan
->language
);
3073 res
= ast_waitstream(chan
, "");
3074 ast_log(LOG_ERROR
, "Unable to create message file: %s\n", strerror(errno
));
3075 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3079 /* Now play the beep once we have the message number for our next message. */
3081 /* Unless we're *really* silent, try to send the beep */
3082 res
= ast_stream_and_wait(chan
, "beep", chan
->language
, "");
3085 /* Store information */
3086 txt
= fdopen(txtdes
, "w+");
3088 get_date(date
, sizeof(date
));
3091 "; Message Information file\n"
3110 ast_callerid_merge(callerid
, sizeof(callerid
), S_OR(chan
->cid
.cid_name
, NULL
), S_OR(chan
->cid
.cid_num
, NULL
), "Unknown"),
3111 date
, (long)time(NULL
),
3112 category
? category
: "");
3114 ast_log(LOG_WARNING
, "Error opening text file for output\n");
3116 res
= play_record_review(chan
, NULL
, tmptxtfile
, vmmaxmessage
, fmt
, 1, vmu
, &duration
, NULL
, options
->record_gain
, vms
);
3118 res
= play_record_review(chan
, NULL
, tmptxtfile
, vmmaxmessage
, fmt
, 1, vmu
, &duration
, NULL
, options
->record_gain
, NULL
);
3122 if (duration
< vmminmessage
) {
3124 if (option_verbose
> 2)
3125 ast_verbose( VERBOSE_PREFIX_3
"Recording was %d seconds long but needs to be at least %d - abandoning\n", duration
, vmminmessage
);
3126 ast_filedelete(tmptxtfile
, NULL
);
3129 fprintf(txt
, "duration=%d\n", duration
);
3131 if (vm_lock_path(dir
)) {
3132 ast_log(LOG_ERROR
, "Couldn't lock directory %s. Voicemail will be lost.\n", dir
);
3134 ast_filedelete(tmptxtfile
, NULL
);
3136 } else if (ast_fileexists(tmptxtfile
, NULL
, NULL
) <= 0) {
3138 ast_log(LOG_DEBUG
, "The recorded media file is gone, so we should remove the .txt file too!\n");
3140 ast_unlock_path(dir
);
3143 make_file(fn
, sizeof(fn
), dir
, msgnum
);
3144 if (!EXISTS(dir
, msgnum
, fn
, NULL
))
3149 /* assign a variable with the name of the voicemail file */
3150 #ifndef IMAP_STORAGE
3151 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", fn
);
3153 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", "IMAP_STORAGE");
3156 snprintf(txtfile
, sizeof(txtfile
), "%s.txt", fn
);
3157 ast_filerename(tmptxtfile
, fn
, NULL
);
3158 rename(tmptxtfile
, txtfile
);
3160 ast_unlock_path(dir
);
3161 /* We must store the file first, before copying the message, because
3162 * ODBC storage does the entire copy with SQL.
3164 if (ast_fileexists(fn
, NULL
, NULL
) > 0) {
3165 STORE(dir
, vmu
->mailbox
, vmu
->context
, msgnum
, chan
, vmu
, fmt
, duration
, vms
);
3168 /* Are there to be more recipients of this message? */
3170 struct ast_vm_user recipu
, *recip
;
3171 char *exten
, *context
;
3173 exten
= strsep(&tmpptr
, "&");
3174 context
= strchr(exten
, '@');
3179 if ((recip
= find_user(&recipu
, context
, exten
))) {
3180 copy_message(chan
, vmu
, 0, msgnum
, duration
, recip
, fmt
, dir
);
3184 /* Notification and disposal needs to happen after the copy, though. */
3185 if (ast_fileexists(fn
, NULL
, NULL
)) {
3186 notify_new_message(chan
, vmu
, msgnum
, duration
, fmt
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
));
3187 DISPOSE(dir
, msgnum
);
3197 if (duration
< vmminmessage
)
3198 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
3199 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3201 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "SUCCESS");
3203 ast_log(LOG_WARNING
, "No format for saving voicemail?\n");
3210 #ifndef IMAP_STORAGE
3211 static int resequence_mailbox(struct ast_vm_user
*vmu
, char *dir
)
3213 /* we know max messages, so stop process when number is hit */
3219 if (vm_lock_path(dir
))
3220 return ERROR_LOCK_PATH
;
3222 for (x
= 0, dest
= 0; x
< vmu
->maxmsg
; x
++) {
3223 make_file(sfn
, sizeof(sfn
), dir
, x
);
3224 if (EXISTS(dir
, x
, sfn
, NULL
)) {
3227 make_file(dfn
, sizeof(dfn
), dir
, dest
);
3228 RENAME(dir
, x
, vmu
->mailbox
, vmu
->context
, dir
, dest
, sfn
, dfn
);
3234 ast_unlock_path(dir
);
3240 static int say_and_wait(struct ast_channel
*chan
, int num
, const char *language
)
3243 d
= ast_say_number(chan
, num
, AST_DIGIT_ANY
, language
, (char *) NULL
);
3247 static int save_to_folder(struct ast_vm_user
*vmu
, struct vm_state
*vms
, int msg
, int box
)
3250 /* we must use mbox(x) folder names, and copy the message there */
3255 /* if save to Old folder, just leave in INBOX */
3256 if (box
== 1) return 10;
3257 /* get the real IMAP message number for this message */
3258 snprintf(sequence
, sizeof(sequence
), "%ld", vms
->msgArray
[msg
]);
3259 if (option_debug
> 2)
3260 ast_log(LOG_DEBUG
, "Copying sequence %s to mailbox %s\n",sequence
,(char *) mbox(box
));
3261 res
= mail_copy(vms
->mailstream
,sequence
,(char *) mbox(box
));
3262 if (res
== 1) return 0;
3265 char *dir
= vms
->curdir
;
3266 char *username
= vms
->username
;
3267 char *context
= vmu
->context
;
3270 char ddir
[PATH_MAX
];
3271 const char *dbox
= mbox(box
);
3273 make_file(sfn
, sizeof(sfn
), dir
, msg
);
3274 create_dirpath(ddir
, sizeof(ddir
), context
, username
, dbox
);
3276 if (vm_lock_path(ddir
))
3277 return ERROR_LOCK_PATH
;
3279 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
3280 make_file(dfn
, sizeof(dfn
), ddir
, x
);
3281 if (!EXISTS(ddir
, x
, dfn
, NULL
))
3284 if (x
>= vmu
->maxmsg
) {
3285 ast_unlock_path(ddir
);
3286 return ERROR_MAILBOX_FULL
;
3288 if (strcmp(sfn
, dfn
)) {
3289 COPY(dir
, msg
, ddir
, x
, username
, context
, sfn
, dfn
);
3291 ast_unlock_path(ddir
);
3296 static int adsi_logo(unsigned char *buf
)
3299 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_CENT
, 0, "Comedian Mail", "");
3300 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_CENT
, 0, "(C)2002-2006 Digium, Inc.", "");
3304 static int adsi_load_vmail(struct ast_channel
*chan
, int *useadsi
)
3306 unsigned char buf
[256];
3312 bytes
+= ast_adsi_data_mode(buf
+ bytes
);
3313 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3316 bytes
+= adsi_logo(buf
);
3317 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Downloading Scripts", "");
3319 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " .", "");
3321 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3322 bytes
+= ast_adsi_data_mode(buf
+ bytes
);
3323 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3325 if (ast_adsi_begin_download(chan
, addesc
, adsifdn
, adsisec
, adsiver
)) {
3327 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Load Cancelled.", "");
3328 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "ADSI Unavailable", "");
3329 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3330 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3331 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3338 bytes
+= ast_adsi_logo(buf
);
3339 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Downloading Scripts", "");
3340 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ..", "");
3341 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3342 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3345 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 0, "Listen", "Listen", "1", 1);
3346 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 1, "Folder", "Folder", "2", 1);
3347 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 2, "Advanced", "Advnced", "3", 1);
3348 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 3, "Options", "Options", "0", 1);
3349 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 4, "Help", "Help", "*", 1);
3350 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 5, "Exit", "Exit", "#", 1);
3351 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3354 /* Add another dot */
3356 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ...", "");
3357 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3359 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3360 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3364 /* These buttons we load but don't use yet */
3365 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 6, "Previous", "Prev", "4", 1);
3366 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 8, "Repeat", "Repeat", "5", 1);
3367 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 7, "Delete", "Delete", "7", 1);
3368 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 9, "Next", "Next", "6", 1);
3369 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 10, "Save", "Save", "9", 1);
3370 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 11, "Undelete", "Restore", "7", 1);
3371 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3374 /* Add another dot */
3376 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ....", "");
3377 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3378 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3383 snprintf(num
, sizeof(num
), "%d", x
);
3384 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 12 + x
, mbox(x
), mbox(x
), num
, 1);
3386 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 12 + 5, "Cancel", "Cancel", "#", 1);
3387 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3390 /* Add another dot */
3392 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " .....", "");
3393 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3394 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3397 if (ast_adsi_end_download(chan
)) {
3399 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Download Unsuccessful.", "");
3400 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "ADSI Unavailable", "");
3401 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3402 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3403 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3407 bytes
+= ast_adsi_download_disconnect(buf
+ bytes
);
3408 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3409 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3412 ast_log(LOG_DEBUG
, "Done downloading scripts...\n");
3417 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, " ......", "");
3418 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3421 ast_log(LOG_DEBUG
, "Restarting session...\n");
3424 /* Load the session now */
3425 if (ast_adsi_load_session(chan
, adsifdn
, adsiver
, 1) == 1) {
3427 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Scripts Loaded!", "");
3429 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Load Failed!", "");
3431 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3435 static void adsi_begin(struct ast_channel
*chan
, int *useadsi
)
3438 if (!ast_adsi_available(chan
))
3440 x
= ast_adsi_load_session(chan
, adsifdn
, adsiver
, 1);
3444 if (adsi_load_vmail(chan
, useadsi
)) {
3445 ast_log(LOG_WARNING
, "Unable to upload voicemail scripts\n");
3452 static void adsi_login(struct ast_channel
*chan
)
3454 unsigned char buf
[256];
3456 unsigned char keys
[8];
3458 if (!ast_adsi_available(chan
))
3463 /* Set one key for next */
3464 keys
[3] = ADSI_KEY_APPS
+ 3;
3466 bytes
+= adsi_logo(buf
+ bytes
);
3467 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, " ", "");
3468 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, " ", "");
3469 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3470 bytes
+= ast_adsi_input_format(buf
+ bytes
, 1, ADSI_DIR_FROM_LEFT
, 0, "Mailbox: ******", "");
3471 bytes
+= ast_adsi_input_control(buf
+ bytes
, ADSI_COMM_PAGE
, 4, 1, 1, ADSI_JUST_LEFT
);
3472 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 3, "Enter", "Enter", "#", 1);
3473 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3474 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3475 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3478 static void adsi_password(struct ast_channel
*chan
)
3480 unsigned char buf
[256];
3482 unsigned char keys
[8];
3484 if (!ast_adsi_available(chan
))
3489 /* Set one key for next */
3490 keys
[3] = ADSI_KEY_APPS
+ 3;
3492 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3493 bytes
+= ast_adsi_input_format(buf
+ bytes
, 1, ADSI_DIR_FROM_LEFT
, 0, "Password: ******", "");
3494 bytes
+= ast_adsi_input_control(buf
+ bytes
, ADSI_COMM_PAGE
, 4, 0, 1, ADSI_JUST_LEFT
);
3495 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3496 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3497 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3500 static void adsi_folders(struct ast_channel
*chan
, int start
, char *label
)
3502 unsigned char buf
[256];
3504 unsigned char keys
[8];
3507 if (!ast_adsi_available(chan
))
3511 y
= ADSI_KEY_APPS
+ 12 + start
+ x
;
3512 if (y
> ADSI_KEY_APPS
+ 12 + 4)
3514 keys
[x
] = ADSI_KEY_SKT
| y
;
3516 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 17);
3520 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_CENT
, 0, label
, "");
3521 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_CENT
, 0, " ", "");
3522 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3523 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3524 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3526 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3529 static void adsi_message(struct ast_channel
*chan
, struct vm_state
*vms
)
3532 unsigned char buf
[256];
3533 char buf1
[256], buf2
[256];
3539 char datetime
[21]="";
3542 unsigned char keys
[8];
3546 if (!ast_adsi_available(chan
))
3549 /* Retrieve important info */
3550 snprintf(fn2
, sizeof(fn2
), "%s.txt", vms
->fn
);
3551 f
= fopen(fn2
, "r");
3554 fgets((char *)buf
, sizeof(buf
), f
);
3557 stringp
= (char *)buf
;
3558 strsep(&stringp
, "=");
3559 val
= strsep(&stringp
, "=");
3560 if (!ast_strlen_zero(val
)) {
3561 if (!strcmp((char *)buf
, "callerid"))
3562 ast_copy_string(cid
, val
, sizeof(cid
));
3563 if (!strcmp((char *)buf
, "origdate"))
3564 ast_copy_string(datetime
, val
, sizeof(datetime
));
3570 /* New meaning for keys */
3572 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 6 + x
);
3577 /* No prev key, provide "Folder" instead */
3578 keys
[0] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3580 if (vms
->curmsg
>= vms
->lastmsg
) {
3581 /* If last message ... */
3583 /* but not only message, provide "Folder" instead */
3584 keys
[3] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3585 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3588 /* Otherwise if only message, leave blank */
3593 if (!ast_strlen_zero(cid
)) {
3594 ast_callerid_parse(cid
, &name
, &num
);
3598 name
= "Unknown Caller";
3600 /* If deleted, show "undeleted" */
3602 if (vms
->deleted
[vms
->curmsg
])
3603 keys
[1] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 11);
3606 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 5);
3607 snprintf(buf1
, sizeof(buf1
), "%s%s", vms
->curbox
,
3608 strcasecmp(vms
->curbox
, "INBOX") ? " Messages" : "");
3609 snprintf(buf2
, sizeof(buf2
), "Message %d of %d", vms
->curmsg
+ 1, vms
->lastmsg
+ 1);
3611 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3612 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3613 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, name
, "");
3614 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, datetime
, "");
3615 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3616 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3617 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3619 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3622 static void adsi_delete(struct ast_channel
*chan
, struct vm_state
*vms
)
3625 unsigned char buf
[256];
3626 unsigned char keys
[8];
3630 if (!ast_adsi_available(chan
))
3633 /* New meaning for keys */
3635 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 6 + x
);
3641 /* No prev key, provide "Folder" instead */
3642 keys
[0] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3644 if (vms
->curmsg
>= vms
->lastmsg
) {
3645 /* If last message ... */
3647 /* but not only message, provide "Folder" instead */
3648 keys
[3] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3650 /* Otherwise if only message, leave blank */
3655 /* If deleted, show "undeleted" */
3656 if (vms
->deleted
[vms
->curmsg
])
3657 keys
[1] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 11);
3660 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 5);
3661 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3662 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3664 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3667 static void adsi_status(struct ast_channel
*chan
, struct vm_state
*vms
)
3669 unsigned char buf
[256] = "";
3670 char buf1
[256] = "", buf2
[256] = "";
3672 unsigned char keys
[8];
3675 char *newm
= (vms
->newmessages
== 1) ? "message" : "messages";
3676 char *oldm
= (vms
->oldmessages
== 1) ? "message" : "messages";
3677 if (!ast_adsi_available(chan
))
3679 if (vms
->newmessages
) {
3680 snprintf(buf1
, sizeof(buf1
), "You have %d new", vms
->newmessages
);
3681 if (vms
->oldmessages
) {
3682 strncat(buf1
, " and", sizeof(buf1
) - strlen(buf1
) - 1);
3683 snprintf(buf2
, sizeof(buf2
), "%d old %s.", vms
->oldmessages
, oldm
);
3685 snprintf(buf2
, sizeof(buf2
), "%s.", newm
);
3687 } else if (vms
->oldmessages
) {
3688 snprintf(buf1
, sizeof(buf1
), "You have %d old", vms
->oldmessages
);
3689 snprintf(buf2
, sizeof(buf2
), "%s.", oldm
);
3691 strcpy(buf1
, "You have no messages.");
3695 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3696 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3697 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3700 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ x
);
3704 /* Don't let them listen if there are none */
3705 if (vms
->lastmsg
< 0)
3707 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3709 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3711 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3714 static void adsi_status2(struct ast_channel
*chan
, struct vm_state
*vms
)
3716 unsigned char buf
[256] = "";
3717 char buf1
[256] = "", buf2
[256] = "";
3719 unsigned char keys
[8];
3722 char *mess
= (vms
->lastmsg
== 0) ? "message" : "messages";
3724 if (!ast_adsi_available(chan
))
3727 /* Original command keys */
3729 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ x
);
3734 if ((vms
->lastmsg
+ 1) < 1)
3737 snprintf(buf1
, sizeof(buf1
), "%s%s has", vms
->curbox
,
3738 strcasecmp(vms
->curbox
, "INBOX") ? " folder" : "");
3740 if (vms
->lastmsg
+ 1)
3741 snprintf(buf2
, sizeof(buf2
), "%d %s.", vms
->lastmsg
+ 1, mess
);
3743 strcpy(buf2
, "no messages.");
3744 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3745 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3746 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, "", "");
3747 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3748 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3750 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3752 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3757 static void adsi_clear(struct ast_channel *chan)
3761 if (!ast_adsi_available(chan))
3763 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3764 bytes += ast_adsi_voice_mode(buf + bytes, 0);
3766 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3770 static void adsi_goodbye(struct ast_channel
*chan
)
3772 unsigned char buf
[256];
3775 if (!ast_adsi_available(chan
))
3777 bytes
+= adsi_logo(buf
+ bytes
);
3778 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, " ", "");
3779 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Goodbye", "");
3780 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3781 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3783 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3786 /*--- get_folder: Folder menu ---*/
3787 /* Plays "press 1 for INBOX messages" etc
3788 Should possibly be internationalized
3790 static int get_folder(struct ast_channel
*chan
, int start
)
3795 d
= ast_play_and_wait(chan
, "vm-press"); /* "Press" */
3798 for (x
= start
; x
< 5; x
++) { /* For all folders */
3799 if ((d
= ast_say_number(chan
, x
, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
)))
3801 d
= ast_play_and_wait(chan
, "vm-for"); /* "for" */
3804 snprintf(fn
, sizeof(fn
), "vm-%s", mbox(x
)); /* Folder name */
3805 d
= vm_play_folder_name(chan
, fn
);
3808 d
= ast_waitfordigit(chan
, 500);
3812 d
= ast_play_and_wait(chan
, "vm-tocancel"); /* "or pound to cancel" */
3815 d
= ast_waitfordigit(chan
, 4000);
3819 static int get_folder2(struct ast_channel
*chan
, char *fn
, int start
)
3822 res
= ast_play_and_wait(chan
, fn
); /* Folder name */
3823 while (((res
< '0') || (res
> '9')) &&
3824 (res
!= '#') && (res
>= 0)) {
3825 res
= get_folder(chan
, 0);
3830 static int vm_forwardoptions(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *curdir
, int curmsg
, char *vmfmts
,
3831 char *context
, signed char record_gain
, long *duration
, struct vm_state
*vms
)
3834 int retries
= 0, prepend_duration
= 0, already_recorded
= 0;
3835 signed char zero_gain
= 0;
3836 struct ast_config
*msg_cfg
;
3837 const char *duration_str
;
3838 char msgfile
[PATH_MAX
], backup
[PATH_MAX
];
3839 char textfile
[PATH_MAX
];
3841 /* Must always populate duration correctly */
3842 make_file(msgfile
, sizeof(msgfile
), curdir
, curmsg
);
3843 strcpy(textfile
, msgfile
);
3844 strcpy(backup
, msgfile
);
3845 strncat(textfile
, ".txt", sizeof(textfile
) - strlen(textfile
) - 1);
3846 strncat(backup
, "-bak", sizeof(backup
) - strlen(backup
) - 1);
3848 if (!(msg_cfg
= ast_config_load(textfile
))) {
3853 if ((duration_str
= ast_variable_retrieve(msg_cfg
, "message", "duration")))
3854 *duration
= atoi(duration_str
);
3856 while ((cmd
>= 0) && (cmd
!= 't') && (cmd
!= '*')) {
3861 /* prepend a message to the current message, update the metadata and return */
3863 prepend_duration
= 0;
3865 /* if we can't read the message metadata, stop now */
3871 /* Back up the original file, so we can retry the prepend */
3872 if (already_recorded
)
3873 ast_filecopy(backup
, msgfile
, NULL
);
3875 ast_filecopy(msgfile
, backup
, NULL
);
3876 already_recorded
= 1;
3879 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &record_gain
, sizeof(record_gain
), 0);
3881 cmd
= ast_play_and_prepend(chan
, NULL
, msgfile
, 0, vmfmts
, &prepend_duration
, 1, silencethreshold
, maxsilence
);
3883 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &zero_gain
, sizeof(zero_gain
), 0);
3885 if (prepend_duration
) {
3886 struct ast_category
*msg_cat
;
3887 /* need enough space for a maximum-length message duration */
3888 char duration_str
[12];
3890 prepend_duration
+= *duration
;
3891 msg_cat
= ast_category_get(msg_cfg
, "message");
3892 snprintf(duration_str
, 11, "%d", prepend_duration
);
3893 if (!ast_variable_update(msg_cat
, "duration", duration_str
, NULL
, 0)) {
3894 config_text_file_save(textfile
, msg_cfg
, "app_voicemail");
3895 STORE(curdir
, vmu
->mailbox
, context
, curmsg
, chan
, vmu
, vmfmts
, prepend_duration
, vms
);
3908 cmd
= ast_play_and_wait(chan
,"vm-forwardoptions");
3909 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
3911 cmd
= ast_play_and_wait(chan
,"vm-starmain");
3912 /* "press star to return to the main menu" */
3914 cmd
= ast_waitfordigit(chan
,6000);
3922 ast_config_destroy(msg_cfg
);
3923 if (already_recorded
)
3924 ast_filedelete(backup
, NULL
);
3925 if (prepend_duration
)
3926 *duration
= prepend_duration
;
3928 if (cmd
== 't' || cmd
== 'S')
3933 static int notify_new_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int msgnum
, long duration
, char *fmt
, char *cidnum
, char *cidname
)
3935 char todir
[PATH_MAX
], fn
[PATH_MAX
], ext_context
[PATH_MAX
], *stringp
;
3936 int newmsgs
= 0, oldmsgs
= 0;
3937 const char *category
= pbx_builtin_getvar_helper(chan
, "VM_CATEGORY");
3939 make_dir(todir
, sizeof(todir
), vmu
->context
, vmu
->mailbox
, "INBOX");
3940 make_file(fn
, sizeof(fn
), todir
, msgnum
);
3941 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", vmu
->mailbox
, vmu
->context
);
3943 if (!ast_strlen_zero(vmu
->attachfmt
)) {
3944 if (strstr(fmt
, vmu
->attachfmt
)) {
3945 fmt
= vmu
->attachfmt
;
3947 ast_log(LOG_WARNING
, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu
->attachfmt
, fmt
, vmu
->mailbox
, vmu
->context
);
3951 /* Attach only the first format */
3952 fmt
= ast_strdupa(fmt
);
3954 strsep(&stringp
, "|");
3956 if (!ast_strlen_zero(vmu
->email
)) {
3957 int attach_user_voicemail
= ast_test_flag((&globalflags
), VM_ATTACH
);
3958 char *myserveremail
= serveremail
;
3959 attach_user_voicemail
= ast_test_flag(vmu
, VM_ATTACH
);
3960 if (!ast_strlen_zero(vmu
->serveremail
))
3961 myserveremail
= vmu
->serveremail
;
3963 if (attach_user_voicemail
)
3964 RETRIEVE(todir
, msgnum
);
3966 /*XXX possible imap issue, should category be NULL XXX*/
3967 sendmail(myserveremail
, vmu
, msgnum
, vmu
->context
, vmu
->mailbox
, cidnum
, cidname
, fn
, fmt
, duration
, attach_user_voicemail
, chan
, category
);
3969 if (attach_user_voicemail
)
3970 DISPOSE(todir
, msgnum
);
3973 if (!ast_strlen_zero(vmu
->pager
)) {
3974 char *myserveremail
= serveremail
;
3975 if (!ast_strlen_zero(vmu
->serveremail
))
3976 myserveremail
= vmu
->serveremail
;
3977 sendpage(myserveremail
, vmu
->pager
, msgnum
, vmu
->context
, vmu
->mailbox
, cidnum
, cidname
, duration
, vmu
, category
);
3980 if (ast_test_flag(vmu
, VM_DELETE
)) {
3981 DELETE(todir
, msgnum
, fn
);
3985 DELETE(todir
, msgnum
, fn
);
3987 /* Leave voicemail for someone */
3988 if (ast_app_has_voicemail(ext_context
, NULL
)) {
3989 ast_app_inboxcount(ext_context
, &newmsgs
, &oldmsgs
);
3991 manager_event(EVENT_FLAG_CALL
, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu
->mailbox
, vmu
->context
, ast_app_has_voicemail(ext_context
, NULL
), newmsgs
, oldmsgs
);
3992 run_externnotify(vmu
->context
, vmu
->mailbox
);
3996 static int forward_message(struct ast_channel
*chan
, char *context
, struct vm_state
*vms
, struct ast_vm_user
*sender
, char *fmt
, int flag
, signed char record_gain
)
4000 char *header_content
;
4004 struct vm_state
*dstvms
;
4006 char username
[70]="";
4007 int res
= 0, cmd
= 0;
4008 struct ast_vm_user
*receiver
= NULL
, *vmtmp
;
4009 AST_LIST_HEAD_NOLOCK_STATIC(extensions
, ast_vm_user
);
4012 int saved_messages
= 0, found
= 0;
4013 int valid_extensions
= 0;
4017 if (vms
== NULL
) return -1;
4019 curmsg
= vms
->curmsg
;
4021 while (!res
&& !valid_extensions
) {
4022 int use_directory
= 0;
4023 if (ast_test_flag((&globalflags
), VM_DIRECFORWARD
)) {
4027 while ((cmd
>= 0) && !done
){
4044 /* Press 1 to enter an extension press 2 to use the directory */
4045 cmd
= ast_play_and_wait(chan
,"vm-forward");
4047 cmd
= ast_waitfordigit(chan
,3000);
4058 if (cmd
< 0 || cmd
== 't')
4062 if (use_directory
) {
4063 /* use app_directory */
4065 char old_context
[sizeof(chan
->context
)];
4066 char old_exten
[sizeof(chan
->exten
)];
4068 struct ast_app
* app
;
4071 app
= pbx_findapp("Directory");
4073 char vmcontext
[256];
4074 /* make backup copies */
4075 memcpy(old_context
, chan
->context
, sizeof(chan
->context
));
4076 memcpy(old_exten
, chan
->exten
, sizeof(chan
->exten
));
4077 old_priority
= chan
->priority
;
4079 /* call the the Directory, changes the channel */
4080 snprintf(vmcontext
, sizeof(vmcontext
), "%s||v", context
? context
: "default");
4081 res
= pbx_exec(chan
, app
, vmcontext
);
4083 ast_copy_string(username
, chan
->exten
, sizeof(username
));
4085 /* restore the old context, exten, and priority */
4086 memcpy(chan
->context
, old_context
, sizeof(chan
->context
));
4087 memcpy(chan
->exten
, old_exten
, sizeof(chan
->exten
));
4088 chan
->priority
= old_priority
;
4091 ast_log(LOG_WARNING
, "Could not find the Directory application, disabling directory_forward\n");
4092 ast_clear_flag((&globalflags
), VM_DIRECFORWARD
);
4095 /* Ask for an extension */
4096 res
= ast_streamfile(chan
, "vm-extension", chan
->language
); /* "extension" */
4099 if ((res
= ast_readstring(chan
, username
, sizeof(username
) - 1, 2000, 10000, "#") < 0))
4103 /* start all over if no username */
4104 if (ast_strlen_zero(username
))
4107 s
= strsep(&stringp
, "*");
4108 /* start optimistic */
4109 valid_extensions
= 1;
4111 /* Don't forward to ourselves but allow leaving a message for ourselves (flag == 1). find_user is going to malloc since we have a NULL as first argument */
4112 if ((flag
== 1 || strcmp(s
,sender
->mailbox
)) && (receiver
= find_user(NULL
, context
, s
))) {
4113 AST_LIST_INSERT_HEAD(&extensions
, receiver
, list
);
4116 valid_extensions
= 0;
4119 s
= strsep(&stringp
, "*");
4121 /* break from the loop of reading the extensions */
4122 if (valid_extensions
)
4124 /* "I am sorry, that's not a valid extension. Please try again." */
4125 res
= ast_play_and_wait(chan
, "pbx-invalid");
4127 /* check if we're clear to proceed */
4128 if (AST_LIST_EMPTY(&extensions
) || !valid_extensions
)
4131 struct leave_vm_options leave_options
;
4132 char mailbox
[AST_MAX_EXTENSION
* 2 + 2];
4133 /* Make sure that context doesn't get set as a literal "(null)" (or else find_user won't find it) */
4135 snprintf(mailbox
, sizeof(mailbox
), "%s@%s", username
, context
);
4137 ast_copy_string(mailbox
, username
, sizeof(mailbox
));
4139 /* Send VoiceMail */
4140 memset(&leave_options
, 0, sizeof(leave_options
));
4141 leave_options
.record_gain
= record_gain
;
4142 cmd
= leave_voicemail(chan
, mailbox
, &leave_options
);
4144 /* Forward VoiceMail */
4146 char origmsgfile
[PATH_MAX
], msgfile
[PATH_MAX
];
4147 struct vm_state vmstmp
;
4149 memcpy(&vmstmp
, vms
, sizeof(vmstmp
));
4151 make_file(origmsgfile
, sizeof(origmsgfile
), dir
, curmsg
);
4152 create_dirpath(vmstmp
.curdir
, sizeof(vmstmp
.curdir
), sender
->context
, vmstmp
.username
, "tmp");
4153 make_file(msgfile
, sizeof(msgfile
), vmstmp
.curdir
, curmsg
);
4155 RETRIEVE(dir
, curmsg
);
4157 /* Alter a surrogate file, only */
4158 copy_plain_file(origmsgfile
, msgfile
);
4160 cmd
= vm_forwardoptions(chan
, sender
, vmstmp
.curdir
, curmsg
, vmfmts
, S_OR(context
, "default"), record_gain
, &duration
, &vmstmp
);
4162 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions
, vmtmp
, list
) {
4164 char *myserveremail
;
4165 int attach_user_voicemail
;
4166 /* Need to get message content */
4167 if (option_debug
> 2)
4168 ast_log (LOG_DEBUG
, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
4169 if (vms
->msgArray
[vms
->curmsg
] == 0) {
4170 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
4174 /* This will only work for new messages... */
4175 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
4176 /* empty string means no valid header */
4177 if (ast_strlen_zero(header_content
)) {
4178 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
4181 /* Get header info needed by sendmail */
4182 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Duration:");
4184 duration
= atoi(temp
);
4188 /* Attach only the first format */
4189 fmt
= ast_strdupa(fmt
);
4192 strsep(&stringp
, "|");
4194 ast_log (LOG_ERROR
,"audio format not set. Default to WAV\n");
4197 if (!strcasecmp(fmt
, "wav49"))
4199 if (option_debug
> 2)
4200 ast_log (LOG_DEBUG
,"**** format set to %s, vmfmts set to %s\n",fmt
,vmfmts
);
4201 /* ast_copy_string(fmt, vmfmts, sizeof(fmt));*/
4202 /* if (!ast_strlen_zero(fmt)) { */
4203 snprintf(todir
, sizeof(todir
), "%s%s/%s/tmp", VM_SPOOL_DIR
, vmtmp
->context
, vmtmp
->mailbox
);
4204 make_gsm_file(vms
->fn
, sizeof(vms
->fn
), vms
->imapuser
, todir
, vms
->curmsg
);
4205 if (option_debug
> 2)
4206 ast_log (LOG_DEBUG
,"Before mail_fetchstructure, message number is %ld, filename is:%s\n",vms
->msgArray
[vms
->curmsg
], vms
->fn
);
4207 /*mail_fetchstructure (mailstream, vmArray[0], &body); */
4208 mail_fetchstructure (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
], &body
);
4209 save_body(body
,vms
,"3","gsm");
4210 /* should not assume "fmt" here! */
4211 save_body(body
,vms
,"2",fmt
);
4213 /* get destination mailbox */
4214 dstvms
= get_vm_state_by_mailbox(vmtmp
->mailbox
,0);
4216 init_mailstream(dstvms
, 0);
4217 if (!dstvms
->mailstream
) {
4218 ast_log (LOG_ERROR
,"IMAP mailstream for %s is NULL\n",vmtmp
->mailbox
);
4220 STORE(todir
, vmtmp
->mailbox
, vmtmp
->context
, dstvms
->curmsg
, chan
, vmtmp
, fmt
, duration
, dstvms
);
4221 run_externnotify(vmtmp
->context
, vmtmp
->mailbox
);
4224 ast_log (LOG_ERROR
,"Could not find state information for mailbox %s\n",vmtmp
->mailbox
);
4227 myserveremail
= serveremail
;
4228 if (!ast_strlen_zero(vmtmp
->serveremail
))
4229 myserveremail
= vmtmp
->serveremail
;
4230 attach_user_voicemail
= ast_test_flag((&globalflags
), VM_ATTACH
);
4231 attach_user_voicemail
= ast_test_flag(vmtmp
, VM_ATTACH
);
4232 /* NULL category for IMAP storage */
4233 sendmail(myserveremail
, vmtmp
, todircount
, vmtmp
->context
, vmtmp
->mailbox
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
), vms
->fn
, fmt
, duration
, attach_user_voicemail
, chan
, NULL
);
4235 copy_message(chan
, sender
, -1, curmsg
, duration
, vmtmp
, fmt
, vmstmp
.curdir
);
4238 AST_LIST_REMOVE_CURRENT(&extensions
, list
);
4243 AST_LIST_TRAVERSE_SAFE_END
;
4244 if (saved_messages
> 0) {
4245 /* give confirmation that the message was saved */
4246 /* commented out since we can't forward batches yet
4247 if (saved_messages == 1)
4248 res = ast_play_and_wait(chan, "vm-message");
4250 res = ast_play_and_wait(chan, "vm-messages");
4252 res = ast_play_and_wait(chan, "vm-saved"); */
4253 res
= ast_play_and_wait(chan
, "vm-msgsaved");
4257 /* Remove surrogate file */
4261 /* If anything failed above, we still have this list to free */
4262 while ((vmtmp
= AST_LIST_REMOVE_HEAD(&extensions
, list
)))
4264 return res
? res
: cmd
;
4267 static int wait_file2(struct ast_channel
*chan
, struct vm_state
*vms
, char *file
)
4270 if ((res
= ast_stream_and_wait(chan
, file
, chan
->language
, AST_DIGIT_ANY
)) < 0)
4271 ast_log(LOG_WARNING
, "Unable to play message %s\n", file
);
4275 static int wait_file(struct ast_channel
*chan
, struct vm_state
*vms
, char *file
)
4277 return ast_control_streamfile(chan
, file
, "#", "*", "1456789", "0", "2", skipms
);
4280 static int play_message_category(struct ast_channel
*chan
, const char *category
)
4284 if (!ast_strlen_zero(category
))
4285 res
= ast_play_and_wait(chan
, category
);
4288 ast_log(LOG_WARNING
, "No sound file for category '%s' was found.\n", category
);
4295 static int play_message_datetime(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, const char *origtime
, const char *filename
)
4298 struct vm_zone
*the_zone
= NULL
;
4301 if (ast_get_time_t(origtime
, &t
, 0, NULL
)) {
4302 ast_log(LOG_WARNING
, "Couldn't find origtime in %s\n", filename
);
4306 /* Does this user have a timezone specified? */
4307 if (!ast_strlen_zero(vmu
->zonetag
)) {
4308 /* Find the zone in the list */
4310 AST_LIST_LOCK(&zones
);
4311 AST_LIST_TRAVERSE(&zones
, z
, list
) {
4312 if (!strcmp(z
->name
, vmu
->zonetag
)) {
4317 AST_LIST_UNLOCK(&zones
);
4320 /* No internal variable parsing for now, so we'll comment it out for the time being */
4322 /* Set the DIFF_* variables */
4323 ast_localtime(&t
, &time_now
, NULL
);
4324 tv_now
= ast_tvnow();
4325 tnow
= tv_now
.tv_sec
;
4326 ast_localtime(&tnow
, &time_then
, NULL
);
4328 /* Day difference */
4329 if (time_now
.tm_year
== time_then
.tm_year
)
4330 snprintf(temp
,sizeof(temp
),"%d",time_now
.tm_yday
);
4332 snprintf(temp
,sizeof(temp
),"%d",(time_now
.tm_year
- time_then
.tm_year
) * 365 + (time_now
.tm_yday
- time_then
.tm_yday
));
4333 pbx_builtin_setvar_helper(chan
, "DIFF_DAY", temp
);
4335 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
4338 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, the_zone
->msg_format
, the_zone
->timezone
);
4339 else if (!strcasecmp(chan
->language
,"pl")) /* POLISH syntax */
4340 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q HM", NULL
);
4341 else if (!strcasecmp(chan
->language
,"se")) /* SWEDISH syntax */
4342 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' dB 'digits/at' k 'and' M", NULL
);
4343 else if (!strcasecmp(chan
->language
,"no")) /* NORWEGIAN syntax */
4344 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q 'digits/at' HM", NULL
);
4345 else if (!strcasecmp(chan
->language
,"de")) /* GERMAN syntax */
4346 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q 'digits/at' HM", NULL
);
4347 else if (!strcasecmp(chan
->language
,"nl")) /* DUTCH syntax */
4348 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q 'digits/nl-om' HM", NULL
);
4349 else if (!strcasecmp(chan
->language
,"it")) /* ITALIAN syntax */
4350 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL
);
4351 else if (!strcasecmp(chan
->language
,"gr"))
4352 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q H 'digits/kai' M ", NULL
);
4353 else if (!strcasecmp(chan
->language
,"pt_BR"))
4354 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL
);
4356 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q 'digits/at' IMp", NULL
);
4358 pbx_builtin_setvar_helper(chan
, "DIFF_DAY", NULL
);
4365 static int play_message_callerid(struct ast_channel
*chan
, struct vm_state
*vms
, char *cid
, const char *context
, int callback
)
4369 char *callerid
, *name
;
4370 char prefile
[PATH_MAX
] = "";
4373 /* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
4374 /* BB: Still need to change this so that if this function is called by the message envelope (and someone is explicitly requesting to hear the CID), it does not check to see if CID is enabled in the config file */
4375 if ((cid
== NULL
)||(context
== NULL
))
4378 /* Strip off caller ID number from name */
4379 if (option_debug
> 2)
4380 ast_log(LOG_DEBUG
, "VM-CID: composite caller ID received: %s, context: %s\n", cid
, context
);
4381 ast_callerid_parse(cid
, &name
, &callerid
);
4382 if ((!ast_strlen_zero(callerid
)) && strcmp(callerid
, "Unknown")) {
4383 /* Check for internal contexts and only */
4384 /* say extension when the call didn't come from an internal context in the list */
4385 for (i
= 0 ; i
< MAX_NUM_CID_CONTEXTS
; i
++){
4386 if (option_debug
> 2)
4387 ast_log(LOG_DEBUG
, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts
[i
]);
4388 if ((strcmp(cidinternalcontexts
[i
], context
) == 0))
4391 if (i
!= MAX_NUM_CID_CONTEXTS
){ /* internal context? */
4393 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, context
, callerid
);
4394 if (!ast_strlen_zero(prefile
)) {
4395 /* See if we can find a recorded name for this person instead of their extension number */
4396 if (ast_fileexists(prefile
, NULL
, NULL
) > 0) {
4397 if (option_verbose
> 2)
4398 ast_verbose(VERBOSE_PREFIX_3
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid
);
4400 res
= wait_file2(chan
, vms
, "vm-from");
4401 res
= ast_stream_and_wait(chan
, prefile
, chan
->language
, "");
4403 if (option_verbose
> 2)
4404 ast_verbose(VERBOSE_PREFIX_3
"Playing envelope info: message from '%s'\n", callerid
);
4405 /* BB: Say "from extension" as one saying to sound smoother */
4407 res
= wait_file2(chan
, vms
, "vm-from-extension");
4408 res
= ast_say_digit_str(chan
, callerid
, "", chan
->language
);
4415 if (option_debug
> 2)
4416 ast_log(LOG_DEBUG
, "VM-CID: Numeric caller id: (%s)\n",callerid
);
4417 /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
4419 res
= wait_file2(chan
, vms
, "vm-from-phonenumber");
4420 res
= ast_say_digit_str(chan
, callerid
, AST_DIGIT_ANY
, chan
->language
);
4423 /* Number unknown */
4425 ast_log(LOG_DEBUG
, "VM-CID: From an unknown number\n");
4426 /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
4427 res
= wait_file2(chan
, vms
, "vm-unknown-caller");
4432 static int play_message_duration(struct ast_channel
*chan
, struct vm_state
*vms
, const char *duration
, int minduration
)
4437 /* Verify that we have a duration for the message */
4438 if (duration
== NULL
)
4441 /* Convert from seconds to minutes */
4442 durations
=atoi(duration
);
4443 durationm
=(durations
/ 60);
4445 if (option_debug
> 2)
4446 ast_log(LOG_DEBUG
, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations
, durationm
);
4448 if ((!res
) && (durationm
>= minduration
)) {
4449 res
= wait_file2(chan
, vms
, "vm-duration");
4452 if (!strcasecmp(chan
->language
, "pl")) {
4453 div_t num
= div(durationm
, 10);
4455 if (durationm
== 1) {
4456 res
= ast_play_and_wait(chan
, "digits/1z");
4457 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-ta");
4458 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
4461 res
= ast_play_and_wait(chan
, "digits/2-ie");
4463 res
= say_and_wait(chan
, durationm
- 2 , chan
->language
);
4464 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
4467 res
= say_and_wait(chan
, durationm
, chan
->language
);
4469 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-ty");
4471 res
= say_and_wait(chan
, durationm
, chan
->language
);
4472 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-t");
4474 /* DEFAULT syntax */
4476 res
= ast_say_number(chan
, durationm
, AST_DIGIT_ANY
, chan
->language
, NULL
);
4477 res
= wait_file2(chan
, vms
, "vm-minutes");
4484 static int play_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
4487 char *header_content
;
4493 char todir
[PATH_MAX
];
4495 char *attachedfilefmt
;
4499 if (option_debug
> 2)
4500 ast_log (LOG_DEBUG
,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
4501 if (vms
->msgArray
[vms
->curmsg
] == 0) {
4502 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
4506 /* This will only work for new messages... */
4507 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
4508 /* empty string means no valid header */
4509 if (ast_strlen_zero(header_content
)) {
4510 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
4513 snprintf(todir
, sizeof(todir
), "%s%s/%s/tmp", VM_SPOOL_DIR
, vmu
->context
, vmu
->mailbox
);
4514 make_gsm_file(vms
->fn
, sizeof(vms
->fn
), vms
->imapuser
, todir
, vms
->curmsg
);
4516 mail_fetchstructure (vms
->mailstream
,vms
->msgArray
[vms
->curmsg
],&body
);
4518 /* We have the body, now we extract the file name of the first attachment. */
4519 if (body
->nested
.part
&& body
->nested
.part
->next
&& body
->nested
.part
->next
->body
.parameter
->value
) {
4520 attachedfilefmt
= ast_strdupa(body
->nested
.part
->next
->body
.parameter
->value
);
4522 ast_log(LOG_ERROR
, "There is no file attached to this IMAP message.\n");
4526 /* Find the format of the attached file */
4528 strsep(&attachedfilefmt
, ".");
4529 if (!attachedfilefmt
) {
4530 ast_log(LOG_ERROR
, "File format could not be obtained from IMAP message attachment\n");
4533 save_body(body
, vms
, "2", attachedfilefmt
);
4535 adsi_message(chan
, vms
);
4537 res
= wait_file2(chan
, vms
, "vm-first"); /* "First" */
4538 else if (vms
->curmsg
== vms
->lastmsg
)
4539 res
= wait_file2(chan
, vms
, "vm-last"); /* "last" */
4541 res
= wait_file2(chan
, vms
, "vm-message"); /* "message" */
4542 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4544 res
= ast_say_number(chan
, vms
->curmsg
+ 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
4548 /* Get info from headers!! */
4549 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Caller-ID-Num:");
4552 ast_copy_string(cid
, temp
, sizeof(cid
));
4556 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Context:");
4559 ast_copy_string(context
, temp
, sizeof(context
));
4563 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Orig-time:");
4566 ast_copy_string(origtime
, temp
, sizeof(origtime
));
4570 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Duration:");
4573 ast_copy_string(duration
,temp
, sizeof(duration
));
4577 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Category:");
4580 ast_copy_string(category
,temp
, sizeof(category
));
4584 /*if (!strncasecmp("macro",context,5)) Macro names in contexts are useless for our needs */
4585 /* context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); */
4589 if ((!res
) && !ast_strlen_zero(category
)) {
4590 res
= play_message_category(chan
, category
);
4593 if ((!res
) && (ast_test_flag(vmu
, VM_ENVELOPE
)) && origtime
[0] != '\0')
4594 res
= play_message_datetime(chan
, vmu
, origtime
, "IMAP_STORAGE");
4595 if ((!res
) && (ast_test_flag(vmu
, VM_SAYCID
)) && cid
[0] !='\0' && context
[0] !='\0')
4596 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
4598 if ((!res
) && (ast_test_flag(vmu
, VM_SAYDURATION
)) && duration
[0] != '\0')
4599 res
= play_message_duration(chan
, vms
, duration
, vmu
->saydurationm
);
4601 /* Allow pressing '1' to skip envelope / callerid */
4605 /*ast_config_destroy(msg_cfg);*/
4609 vms
->heard
[vms
->curmsg
] = 1;
4610 res
= wait_file(chan
, vms
, vms
->fn
);
4612 DISPOSE(vms
->curdir
, vms
->curmsg
);
4613 DELETE(0, 0, vms
->fn
);
4617 static int play_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
4620 char filename
[256], *cid
;
4621 const char *origtime
, *context
, *category
, *duration
;
4622 struct ast_config
*msg_cfg
;
4625 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, vms
->curmsg
);
4626 adsi_message(chan
, vms
);
4628 res
= wait_file2(chan
, vms
, "vm-first"); /* "First" */
4629 else if (vms
->curmsg
== vms
->lastmsg
)
4630 res
= wait_file2(chan
, vms
, "vm-last"); /* "last" */
4633 if (!strcasecmp(chan
->language
, "pl")) {
4634 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4637 ten
= (vms
->curmsg
+ 1) / 10;
4638 one
= (vms
->curmsg
+ 1) % 10;
4640 if (vms
->curmsg
< 20) {
4641 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", vms
->curmsg
+ 1);
4642 res
= wait_file2(chan
, vms
, nextmsg
);
4644 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", ten
* 10);
4645 res
= wait_file2(chan
, vms
, nextmsg
);
4648 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", one
);
4649 res
= wait_file2(chan
, vms
, nextmsg
);
4655 res
= wait_file2(chan
, vms
, "vm-message");
4657 if (!strcasecmp(chan
->language
, "se")) /* SWEDISH syntax */
4658 res
= wait_file2(chan
, vms
, "vm-meddelandet"); /* "message" */
4659 else /* DEFAULT syntax */
4660 res
= wait_file2(chan
, vms
, "vm-message");
4661 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4663 res
= ast_say_number(chan
, vms
->curmsg
+ 1, AST_DIGIT_ANY
, chan
->language
, NULL
);
4668 /* Retrieve info from VM attribute file */
4669 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
4670 snprintf(filename
, sizeof(filename
), "%s.txt", vms
->fn2
);
4671 RETRIEVE(vms
->curdir
, vms
->curmsg
);
4672 msg_cfg
= ast_config_load(filename
);
4674 ast_log(LOG_WARNING
, "No message attribute file?!! (%s)\n", filename
);
4678 if (!(origtime
= ast_variable_retrieve(msg_cfg
, "message", "origtime"))) {
4679 ast_log(LOG_WARNING
, "No origtime?!\n");
4680 DISPOSE(vms
->curdir
, vms
->curmsg
);
4681 ast_config_destroy(msg_cfg
);
4685 cid
= ast_strdupa(ast_variable_retrieve(msg_cfg
, "message", "callerid"));
4686 duration
= ast_variable_retrieve(msg_cfg
, "message", "duration");
4687 category
= ast_variable_retrieve(msg_cfg
, "message", "category");
4689 context
= ast_variable_retrieve(msg_cfg
, "message", "context");
4690 if (!strncasecmp("macro",context
,5)) /* Macro names in contexts are useless for our needs */
4691 context
= ast_variable_retrieve(msg_cfg
, "message","macrocontext");
4693 res
= play_message_category(chan
, category
);
4694 if ((!res
) && (ast_test_flag(vmu
, VM_ENVELOPE
)))
4695 res
= play_message_datetime(chan
, vmu
, origtime
, filename
);
4696 if ((!res
) && (ast_test_flag(vmu
, VM_SAYCID
)))
4697 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
4698 if ((!res
) && (ast_test_flag(vmu
, VM_SAYDURATION
)))
4699 res
= play_message_duration(chan
, vms
, duration
, vmu
->saydurationm
);
4700 /* Allow pressing '1' to skip envelope / callerid */
4703 ast_config_destroy(msg_cfg
);
4706 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, vms
->curmsg
);
4707 vms
->heard
[vms
->curmsg
] = 1;
4708 if ((res
= wait_file(chan
, vms
, vms
->fn
)) < 0) {
4709 ast_log(LOG_WARNING
, "Playback of message %s failed\n", vms
->fn
);
4713 DISPOSE(vms
->curdir
, vms
->curmsg
);
4719 static void imap_mailbox_name(char *spec
, size_t len
, struct vm_state
*vms
, int box
, int use_folder
)
4721 char tmp
[256], *t
= tmp
;
4722 size_t left
= sizeof(tmp
);
4725 ast_copy_string(vms
->curbox
, mbox(0), sizeof(vms
->curbox
));
4726 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", mbox(1));
4728 ast_copy_string(vms
->curbox
, mbox(box
), sizeof(vms
->curbox
));
4729 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", vms
->curbox
);
4732 /* Build up server information */
4733 ast_build_string(&t
, &left
, "{%s:%s/imap", imapserver
, imapport
);
4735 /* Add authentication user if present */
4736 if (!ast_strlen_zero(authuser
))
4737 ast_build_string(&t
, &left
, "/authuser=%s", authuser
);
4739 /* Add flags if present */
4740 if (!ast_strlen_zero(imapflags
))
4741 ast_build_string(&t
, &left
, "/%s", imapflags
);
4743 /* End with username */
4744 ast_build_string(&t
, &left
, "/user=%s}", vms
->imapuser
);
4746 if (box
== 0 || box
== 1)
4747 snprintf(spec
, len
, "%s%s", tmp
, use_folder
? imapfolder
: "INBOX");
4749 snprintf(spec
, len
, "%s%s%c%s", tmp
, imapfolder
, delimiter
, mbox(box
));
4752 static int init_mailstream(struct vm_state
*vms
, int box
)
4754 MAILSTREAM
*stream
= NIL
;
4759 ast_log (LOG_ERROR
,"vm_state is NULL!\n");
4762 if (option_debug
> 2)
4763 ast_log (LOG_DEBUG
,"vm_state user is:%s\n",vms
->imapuser
);
4764 if (vms
->mailstream
== NIL
|| !vms
->mailstream
) {
4766 ast_log (LOG_DEBUG
,"mailstream not set.\n");
4768 stream
= vms
->mailstream
;
4770 /* debug = T; user wants protocol telemetry? */
4771 debug
= NIL
; /* NO protocol telemetry? */
4773 if (delimiter
== '\0') { /* did not probe the server yet */
4775 #ifdef USE_SYSTEM_IMAP
4776 #include <imap/linkage.c>
4777 #elif defined(USE_SYSTEM_CCLIENT)
4778 #include <c-client/linkage.c>
4780 #include "linkage.c"
4782 /* Connect to INBOX first to get folders delimiter */
4783 imap_mailbox_name(tmp
, sizeof(tmp
), vms
, 0, 1);
4784 stream
= mail_open (stream
, tmp
, debug
? OP_DEBUG
: NIL
);
4785 if (stream
== NIL
) {
4786 ast_log (LOG_ERROR
, "Can't connect to imap server %s\n", tmp
);
4789 get_mailbox_delimiter(stream
);
4790 /* update delimiter in imapfolder */
4791 for (cp
= imapfolder
; *cp
; cp
++)
4795 /* Now connect to the target folder */
4796 imap_mailbox_name(tmp
, sizeof(tmp
), vms
, box
, 1);
4797 if (option_debug
> 2)
4798 ast_log (LOG_DEBUG
,"Before mail_open, server: %s, box:%d\n", tmp
, box
);
4799 vms
->mailstream
= mail_open (stream
, tmp
, debug
? OP_DEBUG
: NIL
);
4800 if (vms
->mailstream
== NIL
) {
4807 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
, int box
)
4813 ast_copy_string(vms
->imapuser
,vmu
->imapuser
, sizeof(vms
->imapuser
));
4814 if (option_debug
> 2)
4815 ast_log(LOG_DEBUG
,"Before init_mailstream, user is %s\n",vmu
->imapuser
);
4816 ret
= init_mailstream(vms
, box
);
4817 if (ret
!= 0 || !vms
->mailstream
) {
4818 ast_log (LOG_ERROR
,"Could not initialize mailstream\n");
4824 if (option_debug
> 2)
4825 ast_log(LOG_DEBUG
, "Mailbox name set to: %s, about to check quotas\n", mbox(box
));
4826 check_quota(vms
,(char *)mbox(box
));
4829 pgm
= mail_newsearchpgm();
4831 /* Check IMAP folder for Asterisk messages only... */
4832 hdr
= mail_newsearchheader ("X-Asterisk-VM-Extension", vmu
->mailbox
);
4837 /* if box = 0, check for new, if box = 1, check for read */
4841 } else if (box
== 1) {
4846 vms
->vmArrayIndex
= 0;
4847 if (option_debug
> 2)
4848 ast_log(LOG_DEBUG
,"Before mail_search_full, user is %s\n",vmu
->imapuser
);
4849 mail_search_full (vms
->mailstream
, NULL
, pgm
, NIL
);
4852 vms
->lastmsg
= vms
->vmArrayIndex
- 1;
4854 mail_free_searchpgm(&pgm
);
4858 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
,int box
)
4861 int count_msg
, last_msg
;
4863 ast_copy_string(vms
->curbox
, mbox(box
), sizeof(vms
->curbox
));
4865 /* Rename the member vmbox HERE so that we don't try to return before
4866 * we know what's going on.
4868 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", vms
->curbox
);
4870 /* Faster to make the directory than to check if it exists. */
4871 create_dirpath(vms
->curdir
, sizeof(vms
->curdir
), vmu
->context
, vms
->username
, vms
->curbox
);
4873 count_msg
= count_messages(vmu
, vms
->curdir
);
4877 vms
->lastmsg
= count_msg
- 1;
4880 The following test is needed in case sequencing gets messed up.
4881 There appears to be more than one way to mess up sequence, so
4882 we will not try to find all of the root causes--just fix it when
4886 last_msg
= last_message_index(vmu
, vms
->curdir
);
4889 else if (vms
->lastmsg
!= last_msg
)
4891 ast_log(LOG_NOTICE
, "Resequencing Mailbox: %s\n", vms
->curdir
);
4892 res
= resequence_mailbox(vmu
, vms
->curdir
);
4901 static int close_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
)
4904 #ifndef IMAP_STORAGE
4905 int res
= 0, nummsg
;
4908 if (vms
->lastmsg
<= -1)
4912 #ifndef IMAP_STORAGE
4913 /* Get the deleted messages fixed */
4914 if (vm_lock_path(vms
->curdir
))
4915 return ERROR_LOCK_PATH
;
4917 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
4918 if (!vms
->deleted
[x
] && (strcasecmp(vms
->curbox
, "INBOX") || !vms
->heard
[x
])) {
4919 /* Save this message. It's not in INBOX or hasn't been heard */
4920 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, x
);
4921 if (!EXISTS(vms
->curdir
, x
, vms
->fn
, NULL
))
4924 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
4925 if (strcmp(vms
->fn
, vms
->fn2
)) {
4926 RENAME(vms
->curdir
, x
, vmu
->mailbox
,vmu
->context
, vms
->curdir
, vms
->curmsg
, vms
->fn
, vms
->fn2
);
4928 } else if (!strcasecmp(vms
->curbox
, "INBOX") && vms
->heard
[x
] && !vms
->deleted
[x
]) {
4929 /* Move to old folder before deleting */
4930 res
= save_to_folder(vmu
, vms
, x
, 1);
4931 if (res
== ERROR_LOCK_PATH
|| res
== ERROR_MAILBOX_FULL
) {
4932 /* If save failed do not delete the message */
4933 ast_log(LOG_WARNING
, "Save failed. Not moving message: %s.\n", res
== ERROR_LOCK_PATH
? "unable to lock path" : "destination folder full");
4934 vms
->deleted
[x
] = 0;
4941 /* Delete ALL remaining messages */
4943 for (x
= vms
->curmsg
+ 1; x
<= nummsg
; x
++) {
4944 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, x
);
4945 if (EXISTS(vms
->curdir
, x
, vms
->fn
, NULL
))
4946 DELETE(vms
->curdir
, x
, vms
->fn
);
4948 ast_unlock_path(vms
->curdir
);
4951 for (x
=0;x
< vmu
->maxmsg
;x
++) {
4952 if (vms
->deleted
[x
]) {
4953 if (option_debug
> 2)
4954 ast_log(LOG_DEBUG
,"IMAP delete of %d\n",x
);
4955 IMAP_DELETE(vms
->curdir
, x
, vms
->fn
, vms
);
4963 memset(vms
->deleted
, 0, vmu
->maxmsg
* sizeof(int));
4965 memset(vms
->heard
, 0, vmu
->maxmsg
* sizeof(int));
4970 /* In Greek even though we CAN use a syntax like "friends messages"
4971 * ("filika mynhmata") it is not elegant. This also goes for "work/family messages"
4972 * ("ergasiaka/oikogeniaka mynhmata"). Therefore it is better to use a reversed
4973 * syntax for the above three categories which is more elegant.
4976 static int vm_play_folder_name_gr(struct ast_channel
*chan
, char *mbox
)
4981 buf
= alloca(strlen(mbox
)+2);
4985 if (!strcasecmp(mbox
, "vm-INBOX") || !strcasecmp(mbox
, "vm-Old")){
4986 cmd
= ast_play_and_wait(chan
, buf
); /* "NEA / PALIA" */
4987 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages"); /* "messages" -> "MYNHMATA" */
4989 cmd
= ast_play_and_wait(chan
, "vm-messages"); /* "messages" -> "MYNHMATA" */
4990 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
4994 static int vm_play_folder_name_pl(struct ast_channel
*chan
, char *mbox
)
4998 if (!strcasecmp(mbox
, "vm-INBOX") || !strcasecmp(mbox
, "vm-Old")) {
4999 if (!strcasecmp(mbox
, "vm-INBOX"))
5000 cmd
= ast_play_and_wait(chan
, "vm-new-e");
5002 cmd
= ast_play_and_wait(chan
, "vm-old-e");
5003 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages");
5005 cmd
= ast_play_and_wait(chan
, "vm-messages");
5006 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
5010 static int vm_play_folder_name_ua(struct ast_channel
*chan
, char *mbox
)
5014 if (!strcasecmp(mbox
, "vm-Family") || !strcasecmp(mbox
, "vm-Friends") || !strcasecmp(mbox
, "vm-Work")){
5015 cmd
= ast_play_and_wait(chan
, "vm-messages");
5016 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
5018 cmd
= ast_play_and_wait(chan
, mbox
);
5019 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages");
5023 static int vm_play_folder_name(struct ast_channel
*chan
, char *mbox
)
5027 if (!strcasecmp(chan
->language
, "it") || !strcasecmp(chan
->language
, "es") || !strcasecmp(chan
->language
, "pt") || !strcasecmp(chan
->language
, "pt_BR")) { /* Italian, Spanish, French or Portuguese syntax */
5028 cmd
= ast_play_and_wait(chan
, "vm-messages"); /* "messages */
5029 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
5030 } else if (!strcasecmp(chan
->language
, "gr")){
5031 return vm_play_folder_name_gr(chan
, mbox
);
5032 } else if (!strcasecmp(chan
->language
, "pl")){
5033 return vm_play_folder_name_pl(chan
, mbox
);
5034 } else if (!strcasecmp(chan
->language
, "ua")){ /* Ukrainian syntax */
5035 return vm_play_folder_name_ua(chan
, mbox
);
5036 } else { /* Default English */
5037 cmd
= ast_play_and_wait(chan
, mbox
);
5038 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages"); /* "messages */
5043 In greek the plural for old/new is
5044 different so we need the following files
5045 We also need vm-denExeteMynhmata because
5046 this syntax is different.
5048 -> vm-Olds.wav : "Palia"
5049 -> vm-INBOXs.wav : "Nea"
5050 -> vm-denExeteMynhmata : "den exete mynhmata"
5054 static int vm_intro_gr(struct ast_channel
*chan
, struct vm_state
*vms
)
5058 if (vms
->newmessages
) {
5059 res
= ast_play_and_wait(chan
, "vm-youhave");
5061 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, NULL
);
5063 if ((vms
->newmessages
== 1)) {
5064 res
= ast_play_and_wait(chan
, "vm-INBOX");
5066 res
= ast_play_and_wait(chan
, "vm-message");
5068 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5070 res
= ast_play_and_wait(chan
, "vm-messages");
5073 } else if (vms
->oldmessages
){
5074 res
= ast_play_and_wait(chan
, "vm-youhave");
5076 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, NULL
);
5077 if ((vms
->oldmessages
== 1)){
5078 res
= ast_play_and_wait(chan
, "vm-Old");
5080 res
= ast_play_and_wait(chan
, "vm-message");
5082 res
= ast_play_and_wait(chan
, "vm-Olds");
5084 res
= ast_play_and_wait(chan
, "vm-messages");
5086 } else if (!vms
->oldmessages
&& !vms
->newmessages
)
5087 res
= ast_play_and_wait(chan
, "vm-denExeteMynhmata");
5091 /* Default English syntax */
5092 static int vm_intro_en(struct ast_channel
*chan
, struct vm_state
*vms
)
5096 /* Introduce messages they have */
5097 res
= ast_play_and_wait(chan
, "vm-youhave");
5099 if (vms
->newmessages
) {
5100 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5102 res
= ast_play_and_wait(chan
, "vm-INBOX");
5103 if (vms
->oldmessages
&& !res
)
5104 res
= ast_play_and_wait(chan
, "vm-and");
5106 if ((vms
->newmessages
== 1))
5107 res
= ast_play_and_wait(chan
, "vm-message");
5109 res
= ast_play_and_wait(chan
, "vm-messages");
5113 if (!res
&& vms
->oldmessages
) {
5114 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5116 res
= ast_play_and_wait(chan
, "vm-Old");
5118 if (vms
->oldmessages
== 1)
5119 res
= ast_play_and_wait(chan
, "vm-message");
5121 res
= ast_play_and_wait(chan
, "vm-messages");
5125 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5126 res
= ast_play_and_wait(chan
, "vm-no");
5128 res
= ast_play_and_wait(chan
, "vm-messages");
5135 /* ITALIAN syntax */
5136 static int vm_intro_it(struct ast_channel
*chan
, struct vm_state
*vms
)
5138 /* Introduce messages they have */
5140 if (!vms
->oldmessages
&& !vms
->newmessages
)
5141 res
= ast_play_and_wait(chan
, "vm-no") ||
5142 ast_play_and_wait(chan
, "vm-message");
5144 res
= ast_play_and_wait(chan
, "vm-youhave");
5145 if (!res
&& vms
->newmessages
) {
5146 res
= (vms
->newmessages
== 1) ?
5147 ast_play_and_wait(chan
, "digits/un") ||
5148 ast_play_and_wait(chan
, "vm-nuovo") ||
5149 ast_play_and_wait(chan
, "vm-message") :
5150 /* 2 or more new messages */
5151 say_and_wait(chan
, vms
->newmessages
, chan
->language
) ||
5152 ast_play_and_wait(chan
, "vm-nuovi") ||
5153 ast_play_and_wait(chan
, "vm-messages");
5154 if (!res
&& vms
->oldmessages
)
5155 res
= ast_play_and_wait(chan
, "vm-and");
5157 if (!res
&& vms
->oldmessages
) {
5158 res
= (vms
->oldmessages
== 1) ?
5159 ast_play_and_wait(chan
, "digits/un") ||
5160 ast_play_and_wait(chan
, "vm-vecchio") ||
5161 ast_play_and_wait(chan
, "vm-message") :
5162 /* 2 or more old messages */
5163 say_and_wait(chan
, vms
->oldmessages
, chan
->language
) ||
5164 ast_play_and_wait(chan
, "vm-vecchi") ||
5165 ast_play_and_wait(chan
, "vm-messages");
5167 return res
? -1 : 0;
5171 static int vm_intro_pl(struct ast_channel
*chan
, struct vm_state
*vms
)
5173 /* Introduce messages they have */
5177 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5178 res
= ast_play_and_wait(chan
, "vm-no");
5179 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5182 res
= ast_play_and_wait(chan
, "vm-youhave");
5185 if (vms
->newmessages
) {
5186 num
= div(vms
->newmessages
, 10);
5187 if (vms
->newmessages
== 1) {
5188 res
= ast_play_and_wait(chan
, "digits/1-a");
5189 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-a");
5190 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5191 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
5194 res
= ast_play_and_wait(chan
, "digits/2-ie");
5196 res
= say_and_wait(chan
, vms
->newmessages
- 2 , chan
->language
);
5197 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
5200 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5202 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-e");
5203 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5205 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5206 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-ych");
5207 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5209 if (!res
&& vms
->oldmessages
)
5210 res
= ast_play_and_wait(chan
, "vm-and");
5212 if (!res
&& vms
->oldmessages
) {
5213 num
= div(vms
->oldmessages
, 10);
5214 if (vms
->oldmessages
== 1) {
5215 res
= ast_play_and_wait(chan
, "digits/1-a");
5216 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-a");
5217 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5218 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
5221 res
= ast_play_and_wait(chan
, "digits/2-ie");
5223 res
= say_and_wait(chan
, vms
->oldmessages
- 2 , chan
->language
);
5224 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
5227 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5229 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-e");
5230 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5232 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5233 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-ych");
5234 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5241 /* SWEDISH syntax */
5242 static int vm_intro_se(struct ast_channel
*chan
, struct vm_state
*vms
)
5244 /* Introduce messages they have */
5247 res
= ast_play_and_wait(chan
, "vm-youhave");
5251 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5252 res
= ast_play_and_wait(chan
, "vm-no");
5253 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5257 if (vms
->newmessages
) {
5258 if ((vms
->newmessages
== 1)) {
5259 res
= ast_play_and_wait(chan
, "digits/ett");
5260 res
= res
? res
: ast_play_and_wait(chan
, "vm-nytt");
5261 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5263 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5264 res
= res
? res
: ast_play_and_wait(chan
, "vm-nya");
5265 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5267 if (!res
&& vms
->oldmessages
)
5268 res
= ast_play_and_wait(chan
, "vm-and");
5270 if (!res
&& vms
->oldmessages
) {
5271 if (vms
->oldmessages
== 1) {
5272 res
= ast_play_and_wait(chan
, "digits/ett");
5273 res
= res
? res
: ast_play_and_wait(chan
, "vm-gammalt");
5274 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5276 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5277 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamla");
5278 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5285 /* NORWEGIAN syntax */
5286 static int vm_intro_no(struct ast_channel
*chan
,struct vm_state
*vms
)
5288 /* Introduce messages they have */
5291 res
= ast_play_and_wait(chan
, "vm-youhave");
5295 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5296 res
= ast_play_and_wait(chan
, "vm-no");
5297 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5301 if (vms
->newmessages
) {
5302 if ((vms
->newmessages
== 1)) {
5303 res
= ast_play_and_wait(chan
, "digits/1");
5304 res
= res
? res
: ast_play_and_wait(chan
, "vm-ny");
5305 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5307 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5308 res
= res
? res
: ast_play_and_wait(chan
, "vm-nye");
5309 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5311 if (!res
&& vms
->oldmessages
)
5312 res
= ast_play_and_wait(chan
, "vm-and");
5314 if (!res
&& vms
->oldmessages
) {
5315 if (vms
->oldmessages
== 1) {
5316 res
= ast_play_and_wait(chan
, "digits/1");
5317 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamel");
5318 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5320 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5321 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamle");
5322 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5330 static int vm_intro_de(struct ast_channel
*chan
,struct vm_state
*vms
)
5332 /* Introduce messages they have */
5334 res
= ast_play_and_wait(chan
, "vm-youhave");
5336 if (vms
->newmessages
) {
5337 if ((vms
->newmessages
== 1))
5338 res
= ast_play_and_wait(chan
, "digits/1F");
5340 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5342 res
= ast_play_and_wait(chan
, "vm-INBOX");
5343 if (vms
->oldmessages
&& !res
)
5344 res
= ast_play_and_wait(chan
, "vm-and");
5346 if ((vms
->newmessages
== 1))
5347 res
= ast_play_and_wait(chan
, "vm-message");
5349 res
= ast_play_and_wait(chan
, "vm-messages");
5353 if (!res
&& vms
->oldmessages
) {
5354 if (vms
->oldmessages
== 1)
5355 res
= ast_play_and_wait(chan
, "digits/1F");
5357 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5359 res
= ast_play_and_wait(chan
, "vm-Old");
5361 if (vms
->oldmessages
== 1)
5362 res
= ast_play_and_wait(chan
, "vm-message");
5364 res
= ast_play_and_wait(chan
, "vm-messages");
5368 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5369 res
= ast_play_and_wait(chan
, "vm-no");
5371 res
= ast_play_and_wait(chan
, "vm-messages");
5378 /* SPANISH syntax */
5379 static int vm_intro_es(struct ast_channel
*chan
,struct vm_state
*vms
)
5381 /* Introduce messages they have */
5383 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5384 res
= ast_play_and_wait(chan
, "vm-youhaveno");
5386 res
= ast_play_and_wait(chan
, "vm-messages");
5388 res
= ast_play_and_wait(chan
, "vm-youhave");
5391 if (vms
->newmessages
) {
5393 if ((vms
->newmessages
== 1)) {
5394 res
= ast_play_and_wait(chan
, "digits/1M");
5396 res
= ast_play_and_wait(chan
, "vm-message");
5398 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5400 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5402 res
= ast_play_and_wait(chan
, "vm-messages");
5404 res
= ast_play_and_wait(chan
, "vm-INBOX");
5407 if (vms
->oldmessages
&& !res
)
5408 res
= ast_play_and_wait(chan
, "vm-and");
5410 if (vms
->oldmessages
) {
5412 if (vms
->oldmessages
== 1) {
5413 res
= ast_play_and_wait(chan
, "digits/1M");
5415 res
= ast_play_and_wait(chan
, "vm-message");
5417 res
= ast_play_and_wait(chan
, "vm-Olds");
5419 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5421 res
= ast_play_and_wait(chan
, "vm-messages");
5423 res
= ast_play_and_wait(chan
, "vm-Old");
5431 /* BRAZILIAN PORTUGUESE syntax */
5432 static int vm_intro_pt_BR(struct ast_channel
*chan
,struct vm_state
*vms
) {
5433 /* Introduce messages they have */
5435 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5436 res
= ast_play_and_wait(chan
, "vm-nomessages");
5440 res
= ast_play_and_wait(chan
, "vm-youhave");
5442 if (vms
->newmessages
) {
5444 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5445 if ((vms
->newmessages
== 1)) {
5447 res
= ast_play_and_wait(chan
, "vm-message");
5449 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5453 res
= ast_play_and_wait(chan
, "vm-messages");
5455 res
= ast_play_and_wait(chan
, "vm-INBOX");
5457 if (vms
->oldmessages
&& !res
)
5458 res
= ast_play_and_wait(chan
, "vm-and");
5460 if (vms
->oldmessages
) {
5462 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5463 if (vms
->oldmessages
== 1) {
5465 res
= ast_play_and_wait(chan
, "vm-message");
5467 res
= ast_play_and_wait(chan
, "vm-Olds");
5471 res
= ast_play_and_wait(chan
, "vm-messages");
5473 res
= ast_play_and_wait(chan
, "vm-Old");
5480 static int vm_intro_fr(struct ast_channel
*chan
,struct vm_state
*vms
)
5482 /* Introduce messages they have */
5484 res
= ast_play_and_wait(chan
, "vm-youhave");
5486 if (vms
->newmessages
) {
5487 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5489 res
= ast_play_and_wait(chan
, "vm-INBOX");
5490 if (vms
->oldmessages
&& !res
)
5491 res
= ast_play_and_wait(chan
, "vm-and");
5493 if ((vms
->newmessages
== 1))
5494 res
= ast_play_and_wait(chan
, "vm-message");
5496 res
= ast_play_and_wait(chan
, "vm-messages");
5500 if (!res
&& vms
->oldmessages
) {
5501 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5503 res
= ast_play_and_wait(chan
, "vm-Old");
5505 if (vms
->oldmessages
== 1)
5506 res
= ast_play_and_wait(chan
, "vm-message");
5508 res
= ast_play_and_wait(chan
, "vm-messages");
5512 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5513 res
= ast_play_and_wait(chan
, "vm-no");
5515 res
= ast_play_and_wait(chan
, "vm-messages");
5523 static int vm_intro_nl(struct ast_channel
*chan
,struct vm_state
*vms
)
5525 /* Introduce messages they have */
5527 res
= ast_play_and_wait(chan
, "vm-youhave");
5529 if (vms
->newmessages
) {
5530 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5532 if (vms
->newmessages
== 1)
5533 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5535 res
= ast_play_and_wait(chan
, "vm-INBOX");
5537 if (vms
->oldmessages
&& !res
)
5538 res
= ast_play_and_wait(chan
, "vm-and");
5540 if ((vms
->newmessages
== 1))
5541 res
= ast_play_and_wait(chan
, "vm-message");
5543 res
= ast_play_and_wait(chan
, "vm-messages");
5547 if (!res
&& vms
->oldmessages
) {
5548 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5550 if (vms
->oldmessages
== 1)
5551 res
= ast_play_and_wait(chan
, "vm-Olds");
5553 res
= ast_play_and_wait(chan
, "vm-Old");
5556 if (vms
->oldmessages
== 1)
5557 res
= ast_play_and_wait(chan
, "vm-message");
5559 res
= ast_play_and_wait(chan
, "vm-messages");
5563 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5564 res
= ast_play_and_wait(chan
, "vm-no");
5566 res
= ast_play_and_wait(chan
, "vm-messages");
5573 /* PORTUGUESE syntax */
5574 static int vm_intro_pt(struct ast_channel
*chan
,struct vm_state
*vms
)
5576 /* Introduce messages they have */
5578 res
= ast_play_and_wait(chan
, "vm-youhave");
5580 if (vms
->newmessages
) {
5581 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5583 if ((vms
->newmessages
== 1)) {
5584 res
= ast_play_and_wait(chan
, "vm-message");
5586 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5588 res
= ast_play_and_wait(chan
, "vm-messages");
5590 res
= ast_play_and_wait(chan
, "vm-INBOX");
5593 if (vms
->oldmessages
&& !res
)
5594 res
= ast_play_and_wait(chan
, "vm-and");
5596 if (!res
&& vms
->oldmessages
) {
5597 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5599 if (vms
->oldmessages
== 1) {
5600 res
= ast_play_and_wait(chan
, "vm-message");
5602 res
= ast_play_and_wait(chan
, "vm-Olds");
5604 res
= ast_play_and_wait(chan
, "vm-messages");
5606 res
= ast_play_and_wait(chan
, "vm-Old");
5611 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5612 res
= ast_play_and_wait(chan
, "vm-no");
5614 res
= ast_play_and_wait(chan
, "vm-messages");
5623 /* in czech there must be declension of word new and message
5624 * czech : english : czech : english
5625 * --------------------------------------------------------
5626 * vm-youhave : you have
5627 * vm-novou : one new : vm-zpravu : message
5628 * vm-nove : 2-4 new : vm-zpravy : messages
5629 * vm-novych : 5-infinite new : vm-zprav : messages
5630 * vm-starou : one old
5631 * vm-stare : 2-4 old
5632 * vm-starych : 5-infinite old
5633 * jednu : one - falling 4.
5634 * vm-no : no ( no messages )
5637 static int vm_intro_cz(struct ast_channel
*chan
,struct vm_state
*vms
)
5640 res
= ast_play_and_wait(chan
, "vm-youhave");
5642 if (vms
->newmessages
) {
5643 if (vms
->newmessages
== 1) {
5644 res
= ast_play_and_wait(chan
, "digits/jednu");
5646 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5649 if ((vms
->newmessages
== 1))
5650 res
= ast_play_and_wait(chan
, "vm-novou");
5651 if ((vms
->newmessages
) > 1 && (vms
->newmessages
< 5))
5652 res
= ast_play_and_wait(chan
, "vm-nove");
5653 if (vms
->newmessages
> 4)
5654 res
= ast_play_and_wait(chan
, "vm-novych");
5656 if (vms
->oldmessages
&& !res
)
5657 res
= ast_play_and_wait(chan
, "vm-and");
5659 if ((vms
->newmessages
== 1))
5660 res
= ast_play_and_wait(chan
, "vm-zpravu");
5661 if ((vms
->newmessages
) > 1 && (vms
->newmessages
< 5))
5662 res
= ast_play_and_wait(chan
, "vm-zpravy");
5663 if (vms
->newmessages
> 4)
5664 res
= ast_play_and_wait(chan
, "vm-zprav");
5667 if (!res
&& vms
->oldmessages
) {
5668 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5670 if ((vms
->oldmessages
== 1))
5671 res
= ast_play_and_wait(chan
, "vm-starou");
5672 if ((vms
->oldmessages
) > 1 && (vms
->oldmessages
< 5))
5673 res
= ast_play_and_wait(chan
, "vm-stare");
5674 if (vms
->oldmessages
> 4)
5675 res
= ast_play_and_wait(chan
, "vm-starych");
5678 if ((vms
->oldmessages
== 1))
5679 res
= ast_play_and_wait(chan
, "vm-zpravu");
5680 if ((vms
->oldmessages
) > 1 && (vms
->oldmessages
< 5))
5681 res
= ast_play_and_wait(chan
, "vm-zpravy");
5682 if (vms
->oldmessages
> 4)
5683 res
= ast_play_and_wait(chan
, "vm-zprav");
5687 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5688 res
= ast_play_and_wait(chan
, "vm-no");
5690 res
= ast_play_and_wait(chan
, "vm-zpravy");
5697 static int get_lastdigits(int num
)
5700 return (num
< 20) ? num
: num
% 10;
5703 static int vm_intro_ru(struct ast_channel
*chan
,struct vm_state
*vms
)
5709 res
= ast_play_and_wait(chan
, "vm-youhave");
5710 if (!res
&& vms
->newmessages
) {
5711 lastnum
= get_lastdigits(vms
->newmessages
);
5712 dcnum
= vms
->newmessages
- lastnum
;
5714 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5715 if (!res
&& lastnum
) {
5717 res
= ast_play_and_wait(chan
, "digits/ru/odno");
5719 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5723 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-novoe" : "vm-novyh");
5725 if (!res
&& vms
->oldmessages
)
5726 res
= ast_play_and_wait(chan
, "vm-and");
5729 if (!res
&& vms
->oldmessages
) {
5730 lastnum
= get_lastdigits(vms
->oldmessages
);
5731 dcnum
= vms
->oldmessages
- lastnum
;
5733 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5734 if (!res
&& lastnum
) {
5736 res
= ast_play_and_wait(chan
, "digits/ru/odno");
5738 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5742 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-staroe" : "vm-staryh");
5745 if (!res
&& !vms
->newmessages
&& !vms
->oldmessages
) {
5747 res
= ast_play_and_wait(chan
, "vm-no");
5753 res
= ast_play_and_wait(chan
, "vm-soobshenie");
5758 res
= ast_play_and_wait(chan
, "vm-soobsheniya");
5761 res
= ast_play_and_wait(chan
, "vm-soobsheniy");
5769 /* UKRAINIAN syntax */
5770 /* in ukrainian the syntax is different so we need the following files
5771 * --------------------------------------------------------
5772 * /digits/ua/1e 'odne'
5777 static int vm_intro_ua(struct ast_channel
*chan
,struct vm_state
*vms
)
5783 res
= ast_play_and_wait(chan
, "vm-youhave");
5784 if (!res
&& vms
->newmessages
) {
5785 lastnum
= get_lastdigits(vms
->newmessages
);
5786 dcnum
= vms
->newmessages
- lastnum
;
5788 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5789 if (!res
&& lastnum
) {
5791 res
= ast_play_and_wait(chan
, "digits/ua/1e");
5793 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5797 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-nove" : "vm-INBOX");
5799 if (!res
&& vms
->oldmessages
)
5800 res
= ast_play_and_wait(chan
, "vm-and");
5803 if (!res
&& vms
->oldmessages
) {
5804 lastnum
= get_lastdigits(vms
->oldmessages
);
5805 dcnum
= vms
->oldmessages
- lastnum
;
5807 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5808 if (!res
&& lastnum
) {
5810 res
= ast_play_and_wait(chan
, "digits/ua/1e");
5812 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5816 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-stare" : "vm-Old");
5819 if (!res
&& !vms
->newmessages
&& !vms
->oldmessages
) {
5821 res
= ast_play_and_wait(chan
, "vm-no");
5830 res
= ast_play_and_wait(chan
, "vm-message");
5833 res
= ast_play_and_wait(chan
, "vm-messages");
5842 static int vm_intro(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
5846 /* Notify the user that the temp greeting is set and give them the option to remove it */
5847 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5848 if (ast_test_flag(vmu
, VM_TEMPGREETWARN
)) {
5849 if (ast_fileexists(prefile
, NULL
, NULL
) > 0)
5850 ast_play_and_wait(chan
, "vm-tempgreetactive");
5853 /* Play voicemail intro - syntax is different for different languages */
5854 if (!strcasecmp(chan
->language
, "de")) { /* GERMAN syntax */
5855 return vm_intro_de(chan
, vms
);
5856 } else if (!strcasecmp(chan
->language
, "es")) { /* SPANISH syntax */
5857 return vm_intro_es(chan
, vms
);
5858 } else if (!strcasecmp(chan
->language
, "it")) { /* ITALIAN syntax */
5859 return vm_intro_it(chan
, vms
);
5860 } else if (!strcasecmp(chan
->language
, "fr")) { /* FRENCH syntax */
5861 return vm_intro_fr(chan
, vms
);
5862 } else if (!strcasecmp(chan
->language
, "nl")) { /* DUTCH syntax */
5863 return vm_intro_nl(chan
, vms
);
5864 } else if (!strcasecmp(chan
->language
, "pt")) { /* PORTUGUESE syntax */
5865 return vm_intro_pt(chan
, vms
);
5866 } else if (!strcasecmp(chan
->language
, "pt_BR")) { /* BRAZILIAN PORTUGUESE syntax */
5867 return vm_intro_pt_BR(chan
, vms
);
5868 } else if (!strcasecmp(chan
->language
, "cz")) { /* CZECH syntax */
5869 return vm_intro_cz(chan
, vms
);
5870 } else if (!strcasecmp(chan
->language
, "gr")) { /* GREEK syntax */
5871 return vm_intro_gr(chan
, vms
);
5872 } else if (!strcasecmp(chan
->language
, "pl")) { /* POLISH syntax */
5873 return vm_intro_pl(chan
, vms
);
5874 } else if (!strcasecmp(chan
->language
, "se")) { /* SWEDISH syntax */
5875 return vm_intro_se(chan
, vms
);
5876 } else if (!strcasecmp(chan
->language
, "no")) { /* NORWEGIAN syntax */
5877 return vm_intro_no(chan
, vms
);
5878 } else if (!strcasecmp(chan
->language
, "ru")) { /* RUSSIAN syntax */
5879 return vm_intro_ru(chan
, vms
);
5880 } else if (!strcasecmp(chan
->language
, "ua")) { /* UKRAINIAN syntax */
5881 return vm_intro_ua(chan
, vms
);
5882 } else { /* Default to ENGLISH */
5883 return vm_intro_en(chan
, vms
);
5887 static int vm_instructions(struct ast_channel
*chan
, struct vm_state
*vms
, int skipadvanced
)
5890 /* Play instructions and wait for new command */
5892 if (vms
->starting
) {
5893 if (vms
->lastmsg
> -1) {
5894 res
= ast_play_and_wait(chan
, "vm-onefor");
5896 res
= vm_play_folder_name(chan
, vms
->vmbox
);
5899 res
= ast_play_and_wait(chan
, "vm-opts");
5902 res
= ast_play_and_wait(chan
, "vm-prev");
5903 if (!res
&& !skipadvanced
)
5904 res
= ast_play_and_wait(chan
, "vm-advopts");
5906 res
= ast_play_and_wait(chan
, "vm-repeat");
5907 if (!res
&& (vms
->curmsg
!= vms
->lastmsg
))
5908 res
= ast_play_and_wait(chan
, "vm-next");
5910 if (!vms
->deleted
[vms
->curmsg
])
5911 res
= ast_play_and_wait(chan
, "vm-delete");
5913 res
= ast_play_and_wait(chan
, "vm-undelete");
5915 res
= ast_play_and_wait(chan
, "vm-toforward");
5917 res
= ast_play_and_wait(chan
, "vm-savemessage");
5921 res
= ast_play_and_wait(chan
, "vm-helpexit");
5923 res
= ast_waitfordigit(chan
, 6000);
5926 if (vms
->repeats
> 2) {
5934 static int vm_newuser(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
5939 char newpassword
[80] = "";
5940 char newpassword2
[80] = "";
5941 char prefile
[PATH_MAX
] = "";
5942 unsigned char buf
[256];
5945 if (ast_adsi_available(chan
)) {
5946 bytes
+= adsi_logo(buf
+ bytes
);
5947 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "New User Setup", "");
5948 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
5949 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
5950 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
5951 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
5954 /* First, have the user change their password
5955 so they won't get here again */
5957 newpassword
[1] = '\0';
5958 newpassword
[0] = cmd
= ast_play_and_wait(chan
,"vm-newpassword");
5960 newpassword
[0] = '\0';
5961 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5963 cmd
= ast_readstring(chan
,newpassword
+ strlen(newpassword
),sizeof(newpassword
)-1,2000,10000,"#");
5964 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5966 newpassword2
[1] = '\0';
5967 newpassword2
[0] = cmd
= ast_play_and_wait(chan
,"vm-reenterpassword");
5969 newpassword2
[0] = '\0';
5970 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5972 cmd
= ast_readstring(chan
,newpassword2
+ strlen(newpassword2
),sizeof(newpassword2
)-1,2000,10000,"#");
5973 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5975 if (!strcmp(newpassword
, newpassword2
))
5977 ast_log(LOG_NOTICE
,"Password mismatch for user %s (%s != %s)\n", vms
->username
, newpassword
, newpassword2
);
5978 cmd
= ast_play_and_wait(chan
, "vm-mismatch");
5982 if (ast_strlen_zero(ext_pass_cmd
))
5983 vm_change_password(vmu
,newpassword
);
5985 vm_change_password_shell(vmu
,newpassword
);
5986 if (option_debug
> 2)
5987 ast_log(LOG_DEBUG
,"User %s set password to %s of length %d\n",vms
->username
,newpassword
,(int)strlen(newpassword
));
5988 cmd
= ast_play_and_wait(chan
,"vm-passchanged");
5990 /* If forcename is set, have the user record their name */
5991 if (ast_test_flag(vmu
, VM_FORCENAME
)) {
5992 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5993 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
5994 #ifndef IMAP_STORAGE
5995 cmd
= play_record_review(chan
, "vm-rec-name", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5997 cmd
= play_record_review(chan
, "vm-rec-name", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5999 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
6004 /* If forcegreetings is set, have the user record their greetings */
6005 if (ast_test_flag(vmu
, VM_FORCEGREET
)) {
6006 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6007 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
6008 #ifndef IMAP_STORAGE
6009 cmd
= play_record_review(chan
, "vm-rec-unv", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6011 cmd
= play_record_review(chan
, "vm-rec-unv", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6013 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
6017 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6018 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
6019 #ifndef IMAP_STORAGE
6020 cmd
= play_record_review(chan
, "vm-rec-busy", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6022 cmd
= play_record_review(chan
, "vm-rec-busy", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6024 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
6032 static int vm_options(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
6037 char newpassword
[80] = "";
6038 char newpassword2
[80] = "";
6039 char prefile
[PATH_MAX
] = "";
6040 unsigned char buf
[256];
6043 if (ast_adsi_available(chan
))
6045 bytes
+= adsi_logo(buf
+ bytes
);
6046 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Options Menu", "");
6047 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
6048 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
6049 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
6050 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
6052 while ((cmd
>= 0) && (cmd
!= 't')) {
6057 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6058 #ifndef IMAP_STORAGE
6059 cmd
= play_record_review(chan
,"vm-rec-unv",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6061 cmd
= play_record_review(chan
,"vm-rec-unv",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6065 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6066 #ifndef IMAP_STORAGE
6067 cmd
= play_record_review(chan
,"vm-rec-busy",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6069 cmd
= play_record_review(chan
,"vm-rec-busy",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6073 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6074 #ifndef IMAP_STORAGE
6075 cmd
= play_record_review(chan
,"vm-rec-name",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6077 cmd
= play_record_review(chan
,"vm-rec-name",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6081 cmd
= vm_tempgreeting(chan
, vmu
, vms
, fmtc
, record_gain
);
6084 if (vmu
->password
[0] == '-') {
6085 cmd
= ast_play_and_wait(chan
, "vm-no");
6088 newpassword
[1] = '\0';
6089 newpassword
[0] = cmd
= ast_play_and_wait(chan
,"vm-newpassword");
6091 newpassword
[0] = '\0';
6095 if ((cmd
= ast_readstring(chan
,newpassword
+ strlen(newpassword
),sizeof(newpassword
)-1,2000,10000,"#")) < 0) {
6099 newpassword2
[1] = '\0';
6100 newpassword2
[0] = cmd
= ast_play_and_wait(chan
,"vm-reenterpassword");
6102 newpassword2
[0] = '\0';
6107 if ((cmd
= ast_readstring(chan
,newpassword2
+ strlen(newpassword2
),sizeof(newpassword2
)-1,2000,10000,"#"))) {
6111 if (strcmp(newpassword
, newpassword2
)) {
6112 ast_log(LOG_NOTICE
,"Password mismatch for user %s (%s != %s)\n", vms
->username
, newpassword
, newpassword2
);
6113 cmd
= ast_play_and_wait(chan
, "vm-mismatch");
6116 if (ast_strlen_zero(ext_pass_cmd
))
6117 vm_change_password(vmu
,newpassword
);
6119 vm_change_password_shell(vmu
,newpassword
);
6120 if (option_debug
> 2)
6121 ast_log(LOG_DEBUG
,"User %s set password to %s of length %d\n",vms
->username
,newpassword
,(int)strlen(newpassword
));
6122 cmd
= ast_play_and_wait(chan
,"vm-passchanged");
6128 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6129 if (ast_fileexists(prefile
, NULL
, NULL
))
6130 cmd
= ast_play_and_wait(chan
, "vm-tmpexists");
6132 cmd
= ast_play_and_wait(chan
, "vm-options");
6134 cmd
= ast_waitfordigit(chan
,6000);
6146 static int vm_tempgreeting(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
6152 char prefile
[PATH_MAX
] = "";
6153 unsigned char buf
[256];
6154 char dest
[PATH_MAX
];
6157 if (ast_adsi_available(chan
)) {
6158 bytes
+= adsi_logo(buf
+ bytes
);
6159 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Temp Greeting Menu", "");
6160 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
6161 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
6162 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
6163 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
6166 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6167 if ((res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, vms
->username
, "temp"))) {
6168 ast_log(LOG_WARNING
, "Failed to create directory (%s).\n", prefile
);
6171 while ((cmd
>= 0) && (cmd
!= 't')) {
6174 RETRIEVE(prefile
, -1);
6175 if (ast_fileexists(prefile
, NULL
, NULL
) <= 0) {
6176 #ifndef IMAP_STORAGE
6177 play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6179 play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6185 #ifndef IMAP_STORAGE
6186 cmd
= play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6188 cmd
= play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6192 DELETE(prefile
, -1, prefile
);
6193 ast_play_and_wait(chan
, "vm-tempremoved");
6200 cmd
= ast_play_and_wait(chan
,
6201 ast_fileexists(prefile
, NULL
, NULL
) > 0 ? /* XXX always true ? */
6202 "vm-tempgreeting2" : "vm-tempgreeting");
6204 cmd
= ast_waitfordigit(chan
,6000);
6211 DISPOSE(prefile
, -1);
6220 static int vm_browse_messages_gr(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6224 if (vms
->lastmsg
> -1) {
6225 cmd
= play_message(chan
, vmu
, vms
);
6227 cmd
= ast_play_and_wait(chan
, "vm-youhaveno");
6228 if (!strcasecmp(vms
->vmbox
, "vm-INBOX") ||!strcasecmp(vms
->vmbox
, "vm-Old")){
6230 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%ss", vms
->curbox
);
6231 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6234 cmd
= ast_play_and_wait(chan
, "vm-messages");
6237 cmd
= ast_play_and_wait(chan
, "vm-messages");
6239 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6240 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6247 /* Default English syntax */
6248 static int vm_browse_messages_en(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6252 if (vms
->lastmsg
> -1) {
6253 cmd
= play_message(chan
, vmu
, vms
);
6255 cmd
= ast_play_and_wait(chan
, "vm-youhave");
6257 cmd
= ast_play_and_wait(chan
, "vm-no");
6259 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6260 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6263 cmd
= ast_play_and_wait(chan
, "vm-messages");
6268 /* ITALIAN syntax */
6269 static int vm_browse_messages_it(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6273 if (vms
->lastmsg
> -1) {
6274 cmd
= play_message(chan
, vmu
, vms
);
6276 cmd
= ast_play_and_wait(chan
, "vm-no");
6278 cmd
= ast_play_and_wait(chan
, "vm-message");
6280 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6281 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6287 /* SPANISH syntax */
6288 static int vm_browse_messages_es(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6292 if (vms
->lastmsg
> -1) {
6293 cmd
= play_message(chan
, vmu
, vms
);
6295 cmd
= ast_play_and_wait(chan
, "vm-youhaveno");
6297 cmd
= ast_play_and_wait(chan
, "vm-messages");
6299 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6300 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6306 /* PORTUGUESE syntax */
6307 static int vm_browse_messages_pt(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6311 if (vms
->lastmsg
> -1) {
6312 cmd
= play_message(chan
, vmu
, vms
);
6314 cmd
= ast_play_and_wait(chan
, "vm-no");
6316 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6317 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6320 cmd
= ast_play_and_wait(chan
, "vm-messages");
6325 static int vm_browse_messages(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6327 if (!strcasecmp(chan
->language
, "es")) { /* SPANISH */
6328 return vm_browse_messages_es(chan
, vms
, vmu
);
6329 } else if (!strcasecmp(chan
->language
, "it")) { /* ITALIAN */
6330 return vm_browse_messages_it(chan
, vms
, vmu
);
6331 } else if (!strcasecmp(chan
->language
, "pt") || !strcasecmp(chan
->language
, "pt_BR")) { /* PORTUGUESE */
6332 return vm_browse_messages_pt(chan
, vms
, vmu
);
6333 } else if (!strcasecmp(chan
->language
, "gr")){
6334 return vm_browse_messages_gr(chan
, vms
, vmu
); /* GREEK */
6335 } else { /* Default to English syntax */
6336 return vm_browse_messages_en(chan
, vms
, vmu
);
6340 static int vm_authenticate(struct ast_channel
*chan
, char *mailbox
, int mailbox_size
,
6341 struct ast_vm_user
*res_vmu
, const char *context
, const char *prefix
,
6342 int skipuser
, int maxlogins
, int silent
)
6344 int useadsi
=0, valid
=0, logretries
=0;
6345 char password
[AST_MAX_EXTENSION
]="", *passptr
;
6346 struct ast_vm_user vmus
, *vmu
= NULL
;
6348 /* If ADSI is supported, setup login screen */
6349 adsi_begin(chan
, &useadsi
);
6350 if (!skipuser
&& useadsi
)
6352 if (!silent
&& !skipuser
&& ast_streamfile(chan
, "vm-login", chan
->language
)) {
6353 ast_log(LOG_WARNING
, "Couldn't stream login file\n");
6357 /* Authenticate them and get their mailbox/password */
6359 while (!valid
&& (logretries
< maxlogins
)) {
6360 /* Prompt for, and read in the username */
6361 if (!skipuser
&& ast_readstring(chan
, mailbox
, mailbox_size
- 1, 2000, 10000, "#") < 0) {
6362 ast_log(LOG_WARNING
, "Couldn't read username\n");
6365 if (ast_strlen_zero(mailbox
)) {
6366 if (chan
->cid
.cid_num
) {
6367 ast_copy_string(mailbox
, chan
->cid
.cid_num
, mailbox_size
);
6369 if (option_verbose
> 2)
6370 ast_verbose(VERBOSE_PREFIX_3
"Username not entered\n");
6375 adsi_password(chan
);
6377 if (!ast_strlen_zero(prefix
)) {
6378 char fullusername
[80] = "";
6379 ast_copy_string(fullusername
, prefix
, sizeof(fullusername
));
6380 strncat(fullusername
, mailbox
, sizeof(fullusername
) - 1 - strlen(fullusername
));
6381 ast_copy_string(mailbox
, fullusername
, mailbox_size
);
6385 ast_log(LOG_DEBUG
, "Before find user for mailbox %s\n",mailbox
);
6386 vmu
= find_user(&vmus
, context
, mailbox
);
6387 if (vmu
&& (vmu
->password
[0] == '\0' || (vmu
->password
[0] == '-' && vmu
->password
[1] == '\0'))) {
6388 /* saved password is blank, so don't bother asking */
6391 if (ast_streamfile(chan
, "vm-password", chan
->language
)) {
6392 ast_log(LOG_WARNING
, "Unable to stream password file\n");
6395 if (ast_readstring(chan
, password
, sizeof(password
) - 1, 2000, 10000, "#") < 0) {
6396 ast_log(LOG_WARNING
, "Unable to read password\n");
6402 passptr
= vmu
->password
;
6403 if (passptr
[0] == '-') passptr
++;
6405 if (vmu
&& !strcmp(passptr
, password
))
6408 if (option_verbose
> 2)
6409 ast_verbose( VERBOSE_PREFIX_3
"Incorrect password '%s' for user '%s' (context = %s)\n", password
, mailbox
, context
? context
: "default");
6410 if (!ast_strlen_zero(prefix
))
6415 if (skipuser
|| logretries
>= maxlogins
) {
6416 if (ast_streamfile(chan
, "vm-incorrect", chan
->language
)) {
6417 ast_log(LOG_WARNING
, "Unable to stream incorrect message\n");
6423 if (ast_streamfile(chan
, "vm-incorrect-mailbox", chan
->language
)) {
6424 ast_log(LOG_WARNING
, "Unable to stream incorrect mailbox message\n");
6428 if (ast_waitstream(chan
, "")) /* Channel is hung up */
6432 if (!valid
&& (logretries
>= maxlogins
)) {
6433 ast_stopstream(chan
);
6434 ast_play_and_wait(chan
, "vm-goodbye");
6437 if (vmu
&& !skipuser
) {
6438 memcpy(res_vmu
, vmu
, sizeof(struct ast_vm_user
));
6443 static int vm_execmain(struct ast_channel
*chan
, void *data
)
6445 /* XXX This is, admittedly, some pretty horrendus code. For some
6446 reason it just seemed a lot easier to do with GOTO's. I feel
6447 like I'm back in my GWBASIC days. XXX */
6451 struct ast_module_user
*u
;
6452 char prefixstr
[80] ="";
6453 char ext_context
[256]="";
6457 struct vm_state vms
;
6458 struct ast_vm_user
*vmu
= NULL
, vmus
;
6461 struct ast_flags flags
= { 0 };
6462 signed char record_gain
= 0;
6464 int play_folder
= 0;
6468 u
= ast_module_user_add(chan
);
6470 /* Add the vm_state to the active list and keep it active */
6471 memset(&vms
, 0, sizeof(vms
));
6474 memset(&vmus
, 0, sizeof(vmus
));
6476 if (chan
->_state
!= AST_STATE_UP
) {
6478 ast_log(LOG_DEBUG
, "Before ast_answer\n");
6482 if (!ast_strlen_zero(data
)) {
6483 char *opts
[OPT_ARG_ARRAY_SIZE
];
6485 AST_DECLARE_APP_ARGS(args
,
6490 parse
= ast_strdupa(data
);
6492 AST_STANDARD_APP_ARGS(args
, parse
);
6494 if (args
.argc
== 2) {
6495 if (ast_app_parse_options(vm_app_options
, &flags
, opts
, args
.argv1
)) {
6496 ast_module_user_remove(u
);
6499 if (ast_test_flag(&flags
, OPT_RECORDGAIN
)) {
6501 if (!ast_strlen_zero(opts
[OPT_ARG_RECORDGAIN
])) {
6502 if (sscanf(opts
[OPT_ARG_RECORDGAIN
], "%d", &gain
) != 1) {
6503 ast_log(LOG_WARNING
, "Invalid value '%s' provided for record gain option\n", opts
[OPT_ARG_RECORDGAIN
]);
6504 ast_module_user_remove(u
);
6507 record_gain
= (signed char) gain
;
6510 ast_log(LOG_WARNING
, "Invalid Gain level set with option g\n");
6513 if (ast_test_flag(&flags
, OPT_AUTOPLAY
) ) {
6515 if (opts
[OPT_ARG_PLAYFOLDER
]) {
6516 if (sscanf(opts
[OPT_ARG_PLAYFOLDER
], "%d", &play_folder
) != 1) {
6517 ast_log(LOG_WARNING
, "Invalid value '%s' provided for folder autoplay option\n", opts
[OPT_ARG_PLAYFOLDER
]);
6520 ast_log(LOG_WARNING
, "Invalid folder set with option a\n");
6522 if ( play_folder
> 9 || play_folder
< 0) {
6523 ast_log(LOG_WARNING
, "Invalid value '%d' provided for folder autoplay option\n", play_folder
);
6528 /* old style options parsing */
6529 while (*(args
.argv0
)) {
6530 if (*(args
.argv0
) == 's')
6531 ast_set_flag(&flags
, OPT_SILENT
);
6532 else if (*(args
.argv0
) == 'p')
6533 ast_set_flag(&flags
, OPT_PREPEND_MAILBOX
);
6541 valid
= ast_test_flag(&flags
, OPT_SILENT
);
6543 if ((context
= strchr(args
.argv0
, '@')))
6546 if (ast_test_flag(&flags
, OPT_PREPEND_MAILBOX
))
6547 ast_copy_string(prefixstr
, args
.argv0
, sizeof(prefixstr
));
6549 ast_copy_string(vms
.username
, args
.argv0
, sizeof(vms
.username
));
6551 if (!ast_strlen_zero(vms
.username
) && (vmu
= find_user(&vmus
, context
,vms
.username
)))
6558 res
= vm_authenticate(chan
, vms
.username
, sizeof(vms
.username
), &vmus
, context
, prefixstr
, skipuser
, maxlogins
, 0);
6561 ast_log(LOG_DEBUG
, "After vm_authenticate\n");
6570 /* If ADSI is supported, setup login screen */
6571 adsi_begin(chan
, &useadsi
);
6574 vms
.interactive
= 1;
6576 vmstate_insert(&vms
);
6577 init_vm_state(&vms
);
6582 if (!(vms
.deleted
= ast_calloc(vmu
->maxmsg
, sizeof(int)))) {
6583 /* TODO: Handle memory allocation failure */
6585 if (!(vms
.heard
= ast_calloc(vmu
->maxmsg
, sizeof(int)))) {
6586 /* TODO: Handle memory allocation failure */
6589 /* Set language from config to override channel language */
6590 if (!ast_strlen_zero(vmu
->language
))
6591 ast_string_field_set(chan
, language
, vmu
->language
);
6592 create_dirpath(vms
.curdir
, sizeof(vms
.curdir
), vmu
->context
, vms
.username
, "");
6593 /* Retrieve old and new message counts */
6595 ast_log(LOG_DEBUG
, "Before open_mailbox\n");
6596 res
= open_mailbox(&vms
, vmu
, 1);
6597 if (res
== ERROR_LOCK_PATH
)
6599 vms
.oldmessages
= vms
.lastmsg
+ 1;
6600 if (option_debug
> 2)
6601 ast_log(LOG_DEBUG
, "Number of old messages: %d\n",vms
.oldmessages
);
6602 /* Start in INBOX */
6603 res
= open_mailbox(&vms
, vmu
, 0);
6604 if (res
== ERROR_LOCK_PATH
)
6606 vms
.newmessages
= vms
.lastmsg
+ 1;
6607 if (option_debug
> 2)
6608 ast_log(LOG_DEBUG
, "Number of new messages: %d\n",vms
.newmessages
);
6610 /* Select proper mailbox FIRST!! */
6612 res
= open_mailbox(&vms
, vmu
, play_folder
);
6613 if (res
== ERROR_LOCK_PATH
)
6616 /* If there are no new messages, inform the user and hangup */
6617 if (vms
.lastmsg
== -1) {
6618 cmd
= vm_browse_messages(chan
, &vms
, vmu
);
6623 if (!vms
.newmessages
&& vms
.oldmessages
) {
6624 /* If we only have old messages start here */
6625 res
= open_mailbox(&vms
, vmu
, 1);
6627 if (res
== ERROR_LOCK_PATH
)
6633 adsi_status(chan
, &vms
);
6636 /* Check to see if this is a new user */
6637 if (!strcasecmp(vmu
->mailbox
, vmu
->password
) &&
6638 (ast_test_flag(vmu
, VM_FORCENAME
| VM_FORCEGREET
))) {
6639 if (ast_play_and_wait(chan
, "vm-newuser") == -1)
6640 ast_log(LOG_WARNING
, "Couldn't stream new user file\n");
6641 cmd
= vm_newuser(chan
, vmu
, &vms
, vmfmts
, record_gain
);
6642 if ((cmd
== 't') || (cmd
== '#')) {
6646 } else if (cmd
< 0) {
6653 if (option_debug
> 2)
6654 ast_log(LOG_DEBUG
, "Checking quotas: comparing %u to %u\n",vms
.quota_usage
,vms
.quota_limit
);
6655 if (vms
.quota_limit
&& vms
.quota_usage
>= vms
.quota_limit
) {
6657 ast_log(LOG_DEBUG
, "*** QUOTA EXCEEDED!!\n");
6658 cmd
= ast_play_and_wait(chan
, "vm-mailboxfull");
6660 if (option_debug
> 2)
6661 ast_log(LOG_DEBUG
, "Checking quotas: User has %d messages and limit is %d.\n",(vms
.newmessages
+ vms
.oldmessages
),vmu
->maxmsg
);
6662 if ((vms
.newmessages
+ vms
.oldmessages
) >= vmu
->maxmsg
) {
6663 ast_log(LOG_WARNING
, "No more messages possible. User has %d messages and limit is %d.\n",(vms
.newmessages
+ vms
.oldmessages
),vmu
->maxmsg
);
6664 cmd
= ast_play_and_wait(chan
, "vm-mailboxfull");
6670 cmd
= vm_intro(chan
, vmu
, &vms
);
6675 while ((cmd
> -1) && (cmd
!= 't') && (cmd
!= '#')) {
6682 cmd
= vm_browse_messages(chan
, &vms
, vmu
);
6684 case '2': /* Change folders */
6686 adsi_folders(chan
, 0, "Change to folder...");
6687 cmd
= get_folder2(chan
, "vm-changeto", 0);
6690 } else if (cmd
> 0) {
6692 res
= close_mailbox(&vms
, vmu
);
6693 if (res
== ERROR_LOCK_PATH
)
6695 res
= open_mailbox(&vms
, vmu
, cmd
);
6696 if (res
== ERROR_LOCK_PATH
)
6702 adsi_status2(chan
, &vms
);
6705 cmd
= vm_play_folder_name(chan
, vms
.vmbox
);
6709 case '3': /* Advanced options */
6712 while ((cmd
> -1) && (cmd
!= 't') && (cmd
!= '#')) {
6714 case '1': /* Reply */
6715 if (vms
.lastmsg
> -1 && !vms
.starting
) {
6716 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 1, record_gain
);
6717 if (cmd
== ERROR_LOCK_PATH
) {
6722 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6725 case '2': /* Callback */
6726 if (option_verbose
> 2 && !vms
.starting
)
6727 ast_verbose( VERBOSE_PREFIX_3
"Callback Requested\n");
6728 if (!ast_strlen_zero(vmu
->callback
) && vms
.lastmsg
> -1 && !vms
.starting
) {
6729 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 2, record_gain
);
6733 } else if (cmd
== ERROR_LOCK_PATH
) {
6739 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6742 case '3': /* Envelope */
6743 if (vms
.lastmsg
> -1 && !vms
.starting
) {
6744 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 3, record_gain
);
6745 if (cmd
== ERROR_LOCK_PATH
) {
6750 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6753 case '4': /* Dialout */
6754 if (!ast_strlen_zero(vmu
->dialout
)) {
6755 cmd
= dialout(chan
, vmu
, NULL
, vmu
->dialout
);
6762 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6766 case '5': /* Leave VoiceMail */
6767 if (ast_test_flag(vmu
, VM_SVMAIL
)) {
6768 cmd
= forward_message(chan
, context
, &vms
, vmu
, vmfmts
, 1, record_gain
);
6769 if (cmd
== ERROR_LOCK_PATH
) {
6771 ast_log(LOG_WARNING
, "forward_message failed to lock path.\n");
6775 cmd
= ast_play_and_wait(chan
,"vm-sorry");
6779 case '*': /* Return to main menu */
6785 if (!vms
.starting
) {
6786 cmd
= ast_play_and_wait(chan
, "vm-toreply");
6788 if (!ast_strlen_zero(vmu
->callback
) && !vms
.starting
&& !cmd
) {
6789 cmd
= ast_play_and_wait(chan
, "vm-tocallback");
6791 if (!cmd
&& !vms
.starting
) {
6792 cmd
= ast_play_and_wait(chan
, "vm-tohearenv");
6794 if (!ast_strlen_zero(vmu
->dialout
) && !cmd
) {
6795 cmd
= ast_play_and_wait(chan
, "vm-tomakecall");
6797 if (ast_test_flag(vmu
, VM_SVMAIL
) && !cmd
)
6798 cmd
=ast_play_and_wait(chan
, "vm-leavemsg");
6800 cmd
= ast_play_and_wait(chan
, "vm-starmain");
6802 cmd
= ast_waitfordigit(chan
,6000);
6805 if (vms
.repeats
> 3)
6815 if (vms
.curmsg
> 0) {
6817 cmd
= play_message(chan
, vmu
, &vms
);
6819 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6823 if (vms
.curmsg
< vms
.lastmsg
) {
6825 cmd
= play_message(chan
, vmu
, &vms
);
6827 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6831 if (vms
.curmsg
>= 0 && vms
.curmsg
<= vms
.lastmsg
) {
6832 vms
.deleted
[vms
.curmsg
] = !vms
.deleted
[vms
.curmsg
];
6834 adsi_delete(chan
, &vms
);
6835 if (vms
.deleted
[vms
.curmsg
]) {
6836 if (play_folder
== 0)
6838 else if (play_folder
== 1)
6840 cmd
= ast_play_and_wait(chan
, "vm-deleted");
6843 if (play_folder
== 0)
6845 else if (play_folder
== 1)
6847 cmd
= ast_play_and_wait(chan
, "vm-undeleted");
6849 if (ast_test_flag((&globalflags
), VM_SKIPAFTERCMD
)) {
6850 if (vms
.curmsg
< vms
.lastmsg
) {
6852 cmd
= play_message(chan
, vmu
, &vms
);
6854 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6857 } else /* Delete not valid if we haven't selected a message */
6865 if (vms
.lastmsg
> -1) {
6866 cmd
= forward_message(chan
, context
, &vms
, vmu
, vmfmts
, 0, record_gain
);
6867 if (cmd
== ERROR_LOCK_PATH
) {
6872 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6875 if (vms
.curmsg
< 0 || vms
.curmsg
> vms
.lastmsg
) {
6876 /* No message selected */
6881 adsi_folders(chan
, 1, "Save to folder...");
6882 cmd
= get_folder2(chan
, "vm-savefolder", 1);
6883 box
= 0; /* Shut up compiler */
6887 } else if (cmd
> 0) {
6888 box
= cmd
= cmd
- '0';
6889 cmd
= save_to_folder(vmu
, &vms
, vms
.curmsg
, cmd
);
6890 if (cmd
== ERROR_LOCK_PATH
) {
6894 } else if (cmd
== 10) {
6898 vms
.deleted
[vms
.curmsg
] = 1;
6900 vms
.deleted
[vms
.curmsg
] = 0;
6901 vms
.heard
[vms
.curmsg
] = 0;
6904 make_file(vms
.fn
, sizeof(vms
.fn
), vms
.curdir
, vms
.curmsg
);
6906 adsi_message(chan
, &vms
);
6907 snprintf(vms
.fn
, sizeof(vms
.fn
), "vm-%s", mbox(box
));
6909 cmd
= ast_play_and_wait(chan
, "vm-message");
6911 cmd
= say_and_wait(chan
, vms
.curmsg
+ 1, chan
->language
);
6913 cmd
= ast_play_and_wait(chan
, "vm-savedto");
6915 cmd
= vm_play_folder_name(chan
, vms
.fn
);
6917 cmd
= ast_play_and_wait(chan
, "vm-mailboxfull");
6919 if (ast_test_flag((&globalflags
), VM_SKIPAFTERCMD
)) {
6920 if (vms
.curmsg
< vms
.lastmsg
) {
6922 cmd
= play_message(chan
, vmu
, &vms
);
6924 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6929 if (!vms
.starting
) {
6930 cmd
= ast_play_and_wait(chan
, "vm-onefor");
6932 cmd
= vm_play_folder_name(chan
, vms
.vmbox
);
6934 cmd
= ast_play_and_wait(chan
, "vm-opts");
6936 cmd
= vm_instructions(chan
, &vms
, 1);
6941 cmd
= vm_options(chan
, vmu
, &vms
, vmfmts
, record_gain
);
6943 adsi_status(chan
, &vms
);
6945 default: /* Nothing */
6946 cmd
= vm_instructions(chan
, &vms
, 0);
6950 if ((cmd
== 't') || (cmd
== '#')) {
6960 ast_stopstream(chan
);
6964 res
= ast_play_and_wait(chan
, "vm-dialout");
6966 res
= ast_play_and_wait(chan
, "vm-goodbye");
6971 ast_adsi_unload_session(chan
);
6974 close_mailbox(&vms
, vmu
);
6976 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", vms
.username
, vmu
->context
);
6977 manager_event(EVENT_FLAG_CALL
, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context
, has_voicemail(ext_context
, NULL
));
6978 run_externnotify(vmu
->context
, vmu
->mailbox
);
6981 /* expunge message - use UID Expunge if supported on IMAP server*/
6982 if (option_debug
> 2)
6983 ast_log(LOG_DEBUG
, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted
,expungeonhangup
);
6984 if (vmu
&& deleted
== 1 && expungeonhangup
== 1) {
6985 #ifdef HAVE_IMAP_TK2006
6986 if (LEVELUIDPLUS (vms
.mailstream
)) {
6987 mail_expunge_full(vms
.mailstream
,NIL
,EX_UID
);
6990 mail_expunge(vms
.mailstream
);
6992 /* before we delete the state, we should copy pertinent info
6993 * back to the persistent model */
6994 vmstate_delete(&vms
);
7002 ast_module_user_remove(u
);
7007 static int vm_exec(struct ast_channel
*chan
, void *data
)
7010 struct ast_module_user
*u
;
7012 struct leave_vm_options leave_options
;
7013 struct ast_flags flags
= { 0 };
7014 static int deprecate_warning
= 0;
7015 char *opts
[OPT_ARG_ARRAY_SIZE
];
7016 AST_DECLARE_APP_ARGS(args
,
7021 u
= ast_module_user_add(chan
);
7023 memset(&leave_options
, 0, sizeof(leave_options
));
7025 if (chan
->_state
!= AST_STATE_UP
)
7028 if (!ast_strlen_zero(data
)) {
7029 tmp
= ast_strdupa(data
);
7030 AST_STANDARD_APP_ARGS(args
, tmp
);
7031 if (args
.argc
== 2) {
7032 if (ast_app_parse_options(vm_app_options
, &flags
, opts
, args
.argv1
)) {
7033 ast_module_user_remove(u
);
7036 ast_copy_flags(&leave_options
, &flags
, OPT_SILENT
| OPT_BUSY_GREETING
| OPT_UNAVAIL_GREETING
| OPT_PRIORITY_JUMP
);
7037 if (ast_test_flag(&flags
, OPT_RECORDGAIN
)) {
7040 if (sscanf(opts
[OPT_ARG_RECORDGAIN
], "%d", &gain
) != 1) {
7041 ast_log(LOG_WARNING
, "Invalid value '%s' provided for record gain option\n", opts
[OPT_ARG_RECORDGAIN
]);
7042 ast_module_user_remove(u
);
7045 leave_options
.record_gain
= (signed char) gain
;
7049 /* old style options parsing */
7051 char *orig_argv0
= args
.argv0
;
7052 while (*(args
.argv0
)) {
7053 if (*(args
.argv0
) == 's') {
7055 ast_set_flag(&leave_options
, OPT_SILENT
);
7056 } else if (*(args
.argv0
) == 'b') {
7058 ast_set_flag(&leave_options
, OPT_BUSY_GREETING
);
7059 } else if (*(args
.argv0
) == 'u') {
7061 ast_set_flag(&leave_options
, OPT_UNAVAIL_GREETING
);
7062 } else if (*(args
.argv0
) == 'j') {
7064 ast_set_flag(&leave_options
, OPT_PRIORITY_JUMP
);
7069 if (!deprecate_warning
&& old
) {
7070 deprecate_warning
= 1;
7071 ast_log(LOG_WARNING
, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0
);
7072 ast_log(LOG_WARNING
, "Please move all leading options to the second argument.\n");
7077 res
= ast_app_getdata(chan
, "vm-whichbox", tmp
, sizeof(tmp
) - 1, 0);
7079 ast_module_user_remove(u
);
7082 if (ast_strlen_zero(tmp
)) {
7083 ast_module_user_remove(u
);
7086 args
.argv0
= ast_strdupa(tmp
);
7089 res
= leave_voicemail(chan
, args
.argv0
, &leave_options
);
7091 if (res
== ERROR_LOCK_PATH
) {
7092 ast_log(LOG_ERROR
, "Could not leave voicemail. The path is already locked.\n");
7093 /*Send the call to n+101 priority, where n is the current priority*/
7094 if (ast_test_flag(&leave_options
, OPT_PRIORITY_JUMP
) || ast_opt_priority_jumping
)
7095 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101))
7096 ast_log(LOG_WARNING
, "Extension %s, priority %d doesn't exist.\n", chan
->exten
, chan
->priority
+ 101);
7097 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
7101 ast_module_user_remove(u
);
7106 static struct ast_vm_user
*find_or_create(char *context
, char *mbox
)
7108 struct ast_vm_user
*vmu
;
7109 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7110 if (ast_test_flag((&globalflags
), VM_SEARCH
) && !strcasecmp(mbox
, vmu
->mailbox
))
7112 if (context
&& (!strcasecmp(context
, vmu
->context
)) && (!strcasecmp(mbox
, vmu
->mailbox
)))
7117 if ((vmu
= ast_calloc(1, sizeof(*vmu
)))) {
7118 ast_copy_string(vmu
->context
, context
, sizeof(vmu
->context
));
7119 ast_copy_string(vmu
->mailbox
, mbox
, sizeof(vmu
->mailbox
));
7120 AST_LIST_INSERT_TAIL(&users
, vmu
, list
);
7126 static int append_mailbox(char *context
, char *mbox
, char *data
)
7128 /* Assumes lock is already held */
7132 struct ast_vm_user
*vmu
;
7134 tmp
= ast_strdupa(data
);
7136 if ((vmu
= find_or_create(context
, mbox
))) {
7137 populate_defaults(vmu
);
7140 if ((s
= strsep(&stringp
, ",")))
7141 ast_copy_string(vmu
->password
, s
, sizeof(vmu
->password
));
7142 if (stringp
&& (s
= strsep(&stringp
, ",")))
7143 ast_copy_string(vmu
->fullname
, s
, sizeof(vmu
->fullname
));
7144 if (stringp
&& (s
= strsep(&stringp
, ",")))
7145 ast_copy_string(vmu
->email
, s
, sizeof(vmu
->email
));
7146 if (stringp
&& (s
= strsep(&stringp
, ",")))
7147 ast_copy_string(vmu
->pager
, s
, sizeof(vmu
->pager
));
7148 if (stringp
&& (s
= strsep(&stringp
, ",")))
7149 apply_options(vmu
, s
);
7154 static int vm_box_exists(struct ast_channel
*chan
, void *data
)
7156 struct ast_module_user
*u
;
7157 struct ast_vm_user svm
;
7158 char *context
, *box
;
7159 int priority_jump
= 0;
7160 AST_DECLARE_APP_ARGS(args
,
7162 AST_APP_ARG(options
);
7165 if (ast_strlen_zero(data
)) {
7166 ast_log(LOG_ERROR
, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
7170 u
= ast_module_user_add(chan
);
7172 box
= ast_strdupa(data
);
7174 AST_STANDARD_APP_ARGS(args
, box
);
7177 if (strchr(args
.options
, 'j'))
7181 if ((context
= strchr(args
.mbox
, '@'))) {
7186 if (find_user(&svm
, context
, args
.mbox
)) {
7187 pbx_builtin_setvar_helper(chan
, "VMBOXEXISTSSTATUS", "SUCCESS");
7188 if (priority_jump
|| ast_opt_priority_jumping
)
7189 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101))
7190 ast_log(LOG_WARNING
, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box
, context
, chan
->exten
, chan
->priority
+ 101);
7192 pbx_builtin_setvar_helper(chan
, "VMBOXEXISTSSTATUS", "FAILED");
7193 ast_module_user_remove(u
);
7197 static int vmauthenticate(struct ast_channel
*chan
, void *data
)
7199 struct ast_module_user
*u
;
7200 char *s
= data
, *user
=NULL
, *context
=NULL
, mailbox
[AST_MAX_EXTENSION
] = "";
7201 struct ast_vm_user vmus
;
7202 char *options
= NULL
;
7203 int silent
= 0, skipuser
= 0;
7206 u
= ast_module_user_add(chan
);
7210 user
= strsep(&s
, "|");
7211 options
= strsep(&s
, "|");
7214 user
= strsep(&s
, "@");
7215 context
= strsep(&s
, "");
7216 if (!ast_strlen_zero(user
))
7218 ast_copy_string(mailbox
, user
, sizeof(mailbox
));
7223 silent
= (strchr(options
, 's')) != NULL
;
7226 if (!vm_authenticate(chan
, mailbox
, sizeof(mailbox
), &vmus
, context
, NULL
, skipuser
, 3, silent
)) {
7227 pbx_builtin_setvar_helper(chan
, "AUTH_MAILBOX", mailbox
);
7228 pbx_builtin_setvar_helper(chan
, "AUTH_CONTEXT", vmus
.context
);
7229 ast_play_and_wait(chan
, "auth-thankyou");
7233 ast_module_user_remove(u
);
7237 static char voicemail_show_users_help
[] =
7238 "Usage: voicemail show users [for <context>]\n"
7239 " Lists all mailboxes currently set up\n";
7241 static char voicemail_show_zones_help
[] =
7242 "Usage: voicemail show zones\n"
7243 " Lists zone message formats\n";
7245 static int handle_voicemail_show_users(int fd
, int argc
, char *argv
[])
7247 struct ast_vm_user
*vmu
;
7248 char *output_format
= "%-10s %-5s %-25s %-10s %6s\n";
7250 if ((argc
< 3) || (argc
> 5) || (argc
== 4)) return RESULT_SHOWUSAGE
;
7251 else if ((argc
== 5) && strcmp(argv
[3],"for")) return RESULT_SHOWUSAGE
;
7253 AST_LIST_LOCK(&users
);
7254 if (!AST_LIST_EMPTY(&users
)) {
7256 ast_cli(fd
, output_format
, "Context", "Mbox", "User", "Zone", "NewMsg");
7259 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7260 if (!strcmp(argv
[4],vmu
->context
))
7264 ast_cli(fd
, output_format
, "Context", "Mbox", "User", "Zone", "NewMsg");
7266 ast_cli(fd
, "No such voicemail context \"%s\"\n", argv
[4]);
7267 AST_LIST_UNLOCK(&users
);
7268 return RESULT_FAILURE
;
7271 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7272 int newmsgs
= 0, oldmsgs
= 0;
7273 char count
[12], tmp
[256] = "";
7275 if ((argc
== 3) || ((argc
== 5) && !strcmp(argv
[4],vmu
->context
))) {
7276 snprintf(tmp
, sizeof(tmp
), "%s@%s", vmu
->mailbox
, ast_strlen_zero(vmu
->context
) ? "default" : vmu
->context
);
7277 inboxcount(tmp
, &newmsgs
, &oldmsgs
);
7278 snprintf(count
,sizeof(count
),"%d",newmsgs
);
7279 ast_cli(fd
, output_format
, vmu
->context
, vmu
->mailbox
, vmu
->fullname
, vmu
->zonetag
, count
);
7283 ast_cli(fd
, "There are no voicemail users currently defined\n");
7284 AST_LIST_UNLOCK(&users
);
7285 return RESULT_FAILURE
;
7287 AST_LIST_UNLOCK(&users
);
7288 return RESULT_SUCCESS
;
7291 static int handle_voicemail_show_zones(int fd
, int argc
, char *argv
[])
7293 struct vm_zone
*zone
;
7294 char *output_format
= "%-15s %-20s %-45s\n";
7295 int res
= RESULT_SUCCESS
;
7298 return RESULT_SHOWUSAGE
;
7300 AST_LIST_LOCK(&zones
);
7301 if (!AST_LIST_EMPTY(&zones
)) {
7302 ast_cli(fd
, output_format
, "Zone", "Timezone", "Message Format");
7303 AST_LIST_TRAVERSE(&zones
, zone
, list
) {
7304 ast_cli(fd
, output_format
, zone
->name
, zone
->timezone
, zone
->msg_format
);
7307 ast_cli(fd
, "There are no voicemail zones currently defined\n");
7308 res
= RESULT_FAILURE
;
7310 AST_LIST_UNLOCK(&zones
);
7315 static char *complete_voicemail_show_users(const char *line
, const char *word
, int pos
, int state
)
7319 struct ast_vm_user
*vmu
;
7320 const char *context
= "";
7322 /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
7326 return (state
== 0) ? ast_strdup("for") : NULL
;
7327 wordlen
= strlen(word
);
7328 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7329 if (!strncasecmp(word
, vmu
->context
, wordlen
)) {
7330 if (context
&& strcmp(context
, vmu
->context
) && ++which
> state
)
7331 return ast_strdup(vmu
->context
);
7332 /* ignore repeated contexts ? */
7333 context
= vmu
->context
;
7339 static struct ast_cli_entry cli_show_voicemail_users_deprecated
= {
7340 { "show", "voicemail", "users", NULL
},
7341 handle_voicemail_show_users
, NULL
,
7342 NULL
, complete_voicemail_show_users
};
7344 static struct ast_cli_entry cli_show_voicemail_zones_deprecated
= {
7345 { "show", "voicemail", "zones", NULL
},
7346 handle_voicemail_show_zones
, NULL
,
7349 static struct ast_cli_entry cli_voicemail
[] = {
7350 { { "voicemail", "show", "users", NULL
},
7351 handle_voicemail_show_users
, "List defined voicemail boxes",
7352 voicemail_show_users_help
, complete_voicemail_show_users
, &cli_show_voicemail_users_deprecated
},
7354 { { "voicemail", "show", "zones", NULL
},
7355 handle_voicemail_show_zones
, "List zone message formats",
7356 voicemail_show_zones_help
, NULL
, &cli_show_voicemail_zones_deprecated
},
7359 static int load_config(void)
7361 struct ast_vm_user
*cur
;
7362 struct vm_zone
*zcur
;
7363 struct ast_config
*cfg
, *ucfg
;
7365 struct ast_variable
*var
;
7366 const char *notifystr
= NULL
;
7367 const char *smdistr
= NULL
;
7368 const char *astattach
;
7369 const char *astsearch
;
7370 const char *astsaycid
;
7371 const char *send_voicemail
;
7373 const char *imap_server
;
7374 const char *imap_port
;
7375 const char *imap_flags
;
7376 const char *imap_folder
;
7377 const char *auth_user
;
7378 const char *auth_password
;
7379 const char *expunge_on_hangup
;
7381 const char *astcallop
;
7382 const char *astreview
;
7383 const char *asttempgreetwarn
;
7384 const char *astskipcmd
;
7385 const char *asthearenv
;
7386 const char *astsaydurationinfo
;
7387 const char *astsaydurationminfo
;
7388 const char *silencestr
;
7389 const char *maxmsgstr
;
7390 const char *astdirfwd
;
7391 const char *thresholdstr
;
7393 const char *astemail
;
7394 const char *ucontext
;
7395 const char *astmailcmd
= SENDMAIL
;
7396 const char *astforcename
;
7397 const char *astforcegreet
;
7400 const char *dialoutcxt
= NULL
;
7401 const char *callbackcxt
= NULL
;
7402 const char *exitcxt
= NULL
;
7404 const char *emaildateformatstr
;
7405 const char *volgainstr
;
7409 cfg
= ast_config_load(VOICEMAIL_CONFIG
);
7411 AST_LIST_LOCK(&users
);
7412 while ((cur
= AST_LIST_REMOVE_HEAD(&users
, list
))) {
7413 ast_set_flag(cur
, VM_ALLOCED
);
7417 AST_LIST_LOCK(&zones
);
7418 while ((zcur
= AST_LIST_REMOVE_HEAD(&zones
, list
)))
7420 AST_LIST_UNLOCK(&zones
);
7422 memset(ext_pass_cmd
, 0, sizeof(ext_pass_cmd
));
7425 /* General settings */
7427 if (!(ucontext
= ast_variable_retrieve(cfg
, "general", "userscontext")))
7428 ucontext
= "default";
7429 ast_copy_string(userscontext
, ucontext
, sizeof(userscontext
));
7430 /* Attach voice message to mail message ? */
7431 if (!(astattach
= ast_variable_retrieve(cfg
, "general", "attach")))
7433 ast_set2_flag((&globalflags
), ast_true(astattach
), VM_ATTACH
);
7435 if (!(astsearch
= ast_variable_retrieve(cfg
, "general", "searchcontexts")))
7437 ast_set2_flag((&globalflags
), ast_true(astsearch
), VM_SEARCH
);
7440 if ((volgainstr
= ast_variable_retrieve(cfg
, "general", "volgain")))
7441 sscanf(volgainstr
, "%lf", &volgain
);
7444 strcpy(odbc_database
, "asterisk");
7445 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "odbcstorage"))) {
7446 ast_copy_string(odbc_database
, thresholdstr
, sizeof(odbc_database
));
7448 strcpy(odbc_table
, "voicemessages");
7449 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "odbctable"))) {
7450 ast_copy_string(odbc_table
, thresholdstr
, sizeof(odbc_table
));
7454 strcpy(mailcmd
, SENDMAIL
);
7455 if ((astmailcmd
= ast_variable_retrieve(cfg
, "general", "mailcmd")))
7456 ast_copy_string(mailcmd
, astmailcmd
, sizeof(mailcmd
)); /* User setting */
7459 if ((silencestr
= ast_variable_retrieve(cfg
, "general", "maxsilence"))) {
7460 maxsilence
= atoi(silencestr
);
7465 if (!(maxmsgstr
= ast_variable_retrieve(cfg
, "general", "maxmsg"))) {
7468 maxmsg
= atoi(maxmsgstr
);
7470 ast_log(LOG_WARNING
, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr
, MAXMSG
);
7472 } else if (maxmsg
> MAXMSGLIMIT
) {
7473 ast_log(LOG_WARNING
, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT
, maxmsgstr
);
7474 maxmsg
= MAXMSGLIMIT
;
7478 /* Load date format config for voicemail mail */
7479 if ((emaildateformatstr
= ast_variable_retrieve(cfg
, "general", "emaildateformat"))) {
7480 ast_copy_string(emaildateformat
, emaildateformatstr
, sizeof(emaildateformat
));
7483 /* External password changing command */
7484 if ((extpc
= ast_variable_retrieve(cfg
, "general", "externpass"))) {
7485 ast_copy_string(ext_pass_cmd
,extpc
,sizeof(ext_pass_cmd
));
7488 /* IMAP server address */
7489 if ((imap_server
= ast_variable_retrieve(cfg
, "general", "imapserver"))) {
7490 ast_copy_string(imapserver
, imap_server
, sizeof(imapserver
));
7492 ast_copy_string(imapserver
,"localhost", sizeof(imapserver
));
7494 /* IMAP server port */
7495 if ((imap_port
= ast_variable_retrieve(cfg
, "general", "imapport"))) {
7496 ast_copy_string(imapport
, imap_port
, sizeof(imapport
));
7498 ast_copy_string(imapport
,"143", sizeof(imapport
));
7500 /* IMAP server flags */
7501 if ((imap_flags
= ast_variable_retrieve(cfg
, "general", "imapflags"))) {
7502 ast_copy_string(imapflags
, imap_flags
, sizeof(imapflags
));
7504 /* IMAP server master username */
7505 if ((auth_user
= ast_variable_retrieve(cfg
, "general", "authuser"))) {
7506 ast_copy_string(authuser
, auth_user
, sizeof(authuser
));
7508 /* IMAP server master password */
7509 if ((auth_password
= ast_variable_retrieve(cfg
, "general", "authpassword"))) {
7510 ast_copy_string(authpassword
, auth_password
, sizeof(authpassword
));
7512 /* Expunge on exit */
7513 if ((expunge_on_hangup
= ast_variable_retrieve(cfg
, "general", "expungeonhangup"))) {
7514 if (ast_false(expunge_on_hangup
))
7515 expungeonhangup
= 0;
7517 expungeonhangup
= 1;
7519 expungeonhangup
= 1;
7521 /* IMAP voicemail folder */
7522 if ((imap_folder
= ast_variable_retrieve(cfg
, "general", "imapfolder"))) {
7523 ast_copy_string(imapfolder
, imap_folder
, sizeof(imapfolder
));
7525 ast_copy_string(imapfolder
,"INBOX", sizeof(imapfolder
));
7528 /* External voicemail notify application */
7530 if ((notifystr
= ast_variable_retrieve(cfg
, "general", "externnotify"))) {
7531 ast_copy_string(externnotify
, notifystr
, sizeof(externnotify
));
7532 if (option_debug
> 2)
7533 ast_log(LOG_DEBUG
, "found externnotify: %s\n", externnotify
);
7534 if (!strcasecmp(externnotify
, "smdi")) {
7536 ast_log(LOG_DEBUG
, "Using SMDI for external voicemail notification\n");
7537 if ((smdistr
= ast_variable_retrieve(cfg
, "general", "smdiport"))) {
7538 smdi_iface
= ast_smdi_interface_find(smdistr
);
7541 ast_log(LOG_DEBUG
, "No SMDI interface set, trying default (/dev/ttyS0)\n");
7542 smdi_iface
= ast_smdi_interface_find("/dev/ttyS0");
7546 ast_log(LOG_ERROR
, "No valid SMDI interface specfied, disabling external voicemail notification\n");
7547 externnotify
[0] = '\0';
7551 externnotify
[0] = '\0';
7554 /* Silence treshold */
7555 silencethreshold
= 256;
7556 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "silencethreshold")))
7557 silencethreshold
= atoi(thresholdstr
);
7559 if (!(astemail
= ast_variable_retrieve(cfg
, "general", "serveremail")))
7560 astemail
= ASTERISK_USERNAME
;
7561 ast_copy_string(serveremail
, astemail
, sizeof(serveremail
));
7564 if ((s
= ast_variable_retrieve(cfg
, "general", "maxmessage"))) {
7565 if (sscanf(s
, "%d", &x
) == 1) {
7568 ast_log(LOG_WARNING
, "Invalid max message time length\n");
7573 if ((s
= ast_variable_retrieve(cfg
, "general", "minmessage"))) {
7574 if (sscanf(s
, "%d", &x
) == 1) {
7576 if (maxsilence
<= vmminmessage
)
7577 ast_log(LOG_WARNING
, "maxsilence should be less than minmessage or you may get empty messages\n");
7579 ast_log(LOG_WARNING
, "Invalid min message time length\n");
7582 fmt
= ast_variable_retrieve(cfg
, "general", "format");
7585 ast_copy_string(vmfmts
, fmt
, sizeof(vmfmts
));
7588 if ((s
= ast_variable_retrieve(cfg
, "general", "maxgreet"))) {
7589 if (sscanf(s
, "%d", &x
) == 1) {
7592 ast_log(LOG_WARNING
, "Invalid max message greeting length\n");
7596 if ((s
= ast_variable_retrieve(cfg
, "general", "skipms"))) {
7597 if (sscanf(s
, "%d", &x
) == 1) {
7600 ast_log(LOG_WARNING
, "Invalid skipms value\n");
7605 if ((s
= ast_variable_retrieve(cfg
, "general", "maxlogins"))) {
7606 if (sscanf(s
, "%d", &x
) == 1) {
7609 ast_log(LOG_WARNING
, "Invalid max failed login attempts\n");
7613 /* Force new user to record name ? */
7614 if (!(astforcename
= ast_variable_retrieve(cfg
, "general", "forcename")))
7615 astforcename
= "no";
7616 ast_set2_flag((&globalflags
), ast_true(astforcename
), VM_FORCENAME
);
7618 /* Force new user to record greetings ? */
7619 if (!(astforcegreet
= ast_variable_retrieve(cfg
, "general", "forcegreetings")))
7620 astforcegreet
= "no";
7621 ast_set2_flag((&globalflags
), ast_true(astforcegreet
), VM_FORCEGREET
);
7623 if ((s
= ast_variable_retrieve(cfg
, "general", "cidinternalcontexts"))){
7624 if (option_debug
> 2)
7625 ast_log(LOG_DEBUG
,"VM_CID Internal context string: %s\n",s
);
7626 stringp
= ast_strdupa(s
);
7627 for (x
= 0 ; x
< MAX_NUM_CID_CONTEXTS
; x
++){
7628 if (!ast_strlen_zero(stringp
)) {
7629 q
= strsep(&stringp
,",");
7630 while ((*q
== ' ')||(*q
== '\t')) /* Eat white space between contexts */
7632 ast_copy_string(cidinternalcontexts
[x
], q
, sizeof(cidinternalcontexts
[x
]));
7633 if (option_debug
> 2)
7634 ast_log(LOG_DEBUG
,"VM_CID Internal context %d: %s\n", x
, cidinternalcontexts
[x
]);
7636 cidinternalcontexts
[x
][0] = '\0';
7640 if (!(astreview
= ast_variable_retrieve(cfg
, "general", "review"))){
7642 ast_log(LOG_DEBUG
,"VM Review Option disabled globally\n");
7645 ast_set2_flag((&globalflags
), ast_true(astreview
), VM_REVIEW
);
7647 /*Temperary greeting reminder */
7648 if (!(asttempgreetwarn
= ast_variable_retrieve(cfg
, "general", "tempgreetwarn"))) {
7650 ast_log(LOG_DEBUG
, "VM Temperary Greeting Reminder Option disabled globally\n");
7651 asttempgreetwarn
= "no";
7654 ast_log(LOG_DEBUG
, "VM Temperary Greeting Reminder Option enabled globally\n");
7656 ast_set2_flag((&globalflags
), ast_true(asttempgreetwarn
), VM_TEMPGREETWARN
);
7658 if (!(astcallop
= ast_variable_retrieve(cfg
, "general", "operator"))){
7660 ast_log(LOG_DEBUG
,"VM Operator break disabled globally\n");
7663 ast_set2_flag((&globalflags
), ast_true(astcallop
), VM_OPERATOR
);
7665 if (!(astsaycid
= ast_variable_retrieve(cfg
, "general", "saycid"))) {
7667 ast_log(LOG_DEBUG
,"VM CID Info before msg disabled globally\n");
7670 ast_set2_flag((&globalflags
), ast_true(astsaycid
), VM_SAYCID
);
7672 if (!(send_voicemail
= ast_variable_retrieve(cfg
,"general", "sendvoicemail"))){
7674 ast_log(LOG_DEBUG
,"Send Voicemail msg disabled globally\n");
7675 send_voicemail
= "no";
7677 ast_set2_flag((&globalflags
), ast_true(send_voicemail
), VM_SVMAIL
);
7679 if (!(asthearenv
= ast_variable_retrieve(cfg
, "general", "envelope"))) {
7681 ast_log(LOG_DEBUG
,"ENVELOPE before msg enabled globally\n");
7684 ast_set2_flag((&globalflags
), ast_true(asthearenv
), VM_ENVELOPE
);
7686 if (!(astsaydurationinfo
= ast_variable_retrieve(cfg
, "general", "sayduration"))) {
7688 ast_log(LOG_DEBUG
,"Duration info before msg enabled globally\n");
7689 astsaydurationinfo
= "yes";
7691 ast_set2_flag((&globalflags
), ast_true(astsaydurationinfo
), VM_SAYDURATION
);
7693 saydurationminfo
= 2;
7694 if ((astsaydurationminfo
= ast_variable_retrieve(cfg
, "general", "saydurationm"))) {
7695 if (sscanf(astsaydurationminfo
, "%d", &x
) == 1) {
7696 saydurationminfo
= x
;
7698 ast_log(LOG_WARNING
, "Invalid min duration for say duration\n");
7702 if (!(astskipcmd
= ast_variable_retrieve(cfg
, "general", "nextaftercmd"))) {
7704 ast_log(LOG_DEBUG
,"We are not going to skip to the next msg after save/delete\n");
7707 ast_set2_flag((&globalflags
), ast_true(astskipcmd
), VM_SKIPAFTERCMD
);
7709 if ((dialoutcxt
= ast_variable_retrieve(cfg
, "general", "dialout"))) {
7710 ast_copy_string(dialcontext
, dialoutcxt
, sizeof(dialcontext
));
7712 ast_log(LOG_DEBUG
, "found dialout context: %s\n", dialcontext
);
7714 dialcontext
[0] = '\0';
7717 if ((callbackcxt
= ast_variable_retrieve(cfg
, "general", "callback"))) {
7718 ast_copy_string(callcontext
, callbackcxt
, sizeof(callcontext
));
7720 ast_log(LOG_DEBUG
, "found callback context: %s\n", callcontext
);
7722 callcontext
[0] = '\0';
7725 if ((exitcxt
= ast_variable_retrieve(cfg
, "general", "exitcontext"))) {
7726 ast_copy_string(exitcontext
, exitcxt
, sizeof(exitcontext
));
7728 ast_log(LOG_DEBUG
, "found operator context: %s\n", exitcontext
);
7730 exitcontext
[0] = '\0';
7733 if (!(astdirfwd
= ast_variable_retrieve(cfg
, "general", "usedirectory")))
7735 ast_set2_flag((&globalflags
), ast_true(astdirfwd
), VM_DIRECFORWARD
);
7736 if ((ucfg
= ast_config_load("users.conf"))) {
7737 for (cat
= ast_category_browse(ucfg
, NULL
); cat
; cat
= ast_category_browse(ucfg
, cat
)) {
7738 if (!ast_true(ast_config_option(ucfg
, cat
, "hasvoicemail")))
7740 if ((cur
= find_or_create(userscontext
, cat
))) {
7741 populate_defaults(cur
);
7742 apply_options_full(cur
, ast_variable_browse(ucfg
, cat
));
7743 ast_copy_string(cur
->context
, userscontext
, sizeof(cur
->context
));
7746 ast_config_destroy(ucfg
);
7748 cat
= ast_category_browse(cfg
, NULL
);
7750 if (strcasecmp(cat
, "general")) {
7751 var
= ast_variable_browse(cfg
, cat
);
7752 if (strcasecmp(cat
, "zonemessages")) {
7753 /* Process mailboxes in this context */
7755 append_mailbox(cat
, var
->name
, var
->value
);
7759 /* Timezones in this context */
7762 if ((z
= ast_malloc(sizeof(*z
)))) {
7763 char *msg_format
, *timezone
;
7764 msg_format
= ast_strdupa(var
->value
);
7765 timezone
= strsep(&msg_format
, "|");
7767 ast_copy_string(z
->name
, var
->name
, sizeof(z
->name
));
7768 ast_copy_string(z
->timezone
, timezone
, sizeof(z
->timezone
));
7769 ast_copy_string(z
->msg_format
, msg_format
, sizeof(z
->msg_format
));
7770 AST_LIST_LOCK(&zones
);
7771 AST_LIST_INSERT_HEAD(&zones
, z
, list
);
7772 AST_LIST_UNLOCK(&zones
);
7774 ast_log(LOG_WARNING
, "Invalid timezone definition at line %d\n", var
->lineno
);
7779 AST_LIST_UNLOCK(&users
);
7780 ast_config_destroy(cfg
);
7787 cat
= ast_category_browse(cfg
, cat
);
7789 memset(fromstring
,0,sizeof(fromstring
));
7790 memset(pagerfromstring
,0,sizeof(pagerfromstring
));
7791 memset(emailtitle
,0,sizeof(emailtitle
));
7792 strcpy(charset
, "ISO-8859-1");
7799 emailsubject
= NULL
;
7807 pagersubject
= NULL
;
7809 if ((s
= ast_variable_retrieve(cfg
, "general", "pbxskip")))
7810 ast_set2_flag((&globalflags
), ast_true(s
), VM_PBXSKIP
);
7811 if ((s
= ast_variable_retrieve(cfg
, "general", "fromstring")))
7812 ast_copy_string(fromstring
,s
,sizeof(fromstring
));
7813 if ((s
= ast_variable_retrieve(cfg
, "general", "pagerfromstring")))
7814 ast_copy_string(pagerfromstring
,s
,sizeof(pagerfromstring
));
7815 if ((s
= ast_variable_retrieve(cfg
, "general", "charset")))
7816 ast_copy_string(charset
,s
,sizeof(charset
));
7817 if ((s
= ast_variable_retrieve(cfg
, "general", "adsifdn"))) {
7818 sscanf(s
, "%2x%2x%2x%2x", &tmpadsi
[0], &tmpadsi
[1], &tmpadsi
[2], &tmpadsi
[3]);
7819 for (x
= 0; x
< 4; x
++) {
7820 memcpy(&adsifdn
[x
], &tmpadsi
[x
], 1);
7823 if ((s
= ast_variable_retrieve(cfg
, "general", "adsisec"))) {
7824 sscanf(s
, "%2x%2x%2x%2x", &tmpadsi
[0], &tmpadsi
[1], &tmpadsi
[2], &tmpadsi
[3]);
7825 for (x
= 0; x
< 4; x
++) {
7826 memcpy(&adsisec
[x
], &tmpadsi
[x
], 1);
7829 if ((s
= ast_variable_retrieve(cfg
, "general", "adsiver")))
7833 if ((s
= ast_variable_retrieve(cfg
, "general", "emailtitle"))) {
7834 ast_log(LOG_NOTICE
, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
7835 ast_copy_string(emailtitle
,s
,sizeof(emailtitle
));
7837 if ((s
= ast_variable_retrieve(cfg
, "general", "emailsubject")))
7838 emailsubject
= ast_strdup(s
);
7839 if ((s
= ast_variable_retrieve(cfg
, "general", "emailbody"))) {
7840 char *tmpread
, *tmpwrite
;
7841 emailbody
= ast_strdup(s
);
7843 /* substitute strings \t and \n into the appropriate characters */
7844 tmpread
= tmpwrite
= emailbody
;
7845 while ((tmpwrite
= strchr(tmpread
,'\\'))) {
7846 switch (tmpwrite
[1]) {
7848 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7852 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7856 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7860 ast_log(LOG_NOTICE
, "Substitution routine does not support this character: %c\n", tmpwrite
[1]);
7862 tmpread
= tmpwrite
+ 1;
7865 if ((s
= ast_variable_retrieve(cfg
, "general", "pagersubject")))
7866 pagersubject
= ast_strdup(s
);
7867 if ((s
= ast_variable_retrieve(cfg
, "general", "pagerbody"))) {
7868 char *tmpread
, *tmpwrite
;
7869 pagerbody
= ast_strdup(s
);
7871 /* substitute strings \t and \n into the appropriate characters */
7872 tmpread
= tmpwrite
= pagerbody
;
7873 while ((tmpwrite
= strchr(tmpread
, '\\'))) {
7874 switch (tmpwrite
[1]) {
7876 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7880 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7884 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7888 ast_log(LOG_NOTICE
, "Substitution routine does not support this character: %c\n", tmpwrite
[1]);
7890 tmpread
= tmpwrite
+ 1;
7893 AST_LIST_UNLOCK(&users
);
7894 ast_config_destroy(cfg
);
7897 AST_LIST_UNLOCK(&users
);
7898 ast_log(LOG_WARNING
, "Failed to load configuration file.\n");
7903 static int reload(void)
7905 return(load_config());
7908 static int unload_module(void)
7912 res
= ast_unregister_application(app
);
7913 res
|= ast_unregister_application(app2
);
7914 res
|= ast_unregister_application(app3
);
7915 res
|= ast_unregister_application(app4
);
7916 ast_cli_unregister_multiple(cli_voicemail
, sizeof(cli_voicemail
) / sizeof(struct ast_cli_entry
));
7917 ast_uninstall_vm_functions();
7919 ast_module_user_hangup_all();
7924 static int load_module(void)
7927 char *adsi_loaded
= ast_module_helper("", "res_adsi.so", 0, 0, 0, 0);
7930 ast_log(LOG_ERROR
, "app_voicemail.so depends upon res_adsi.so\n");
7931 return AST_MODULE_LOAD_DECLINE
;
7934 my_umask
= umask(0);
7936 res
= ast_register_application(app
, vm_exec
, synopsis_vm
, descrip_vm
);
7937 res
|= ast_register_application(app2
, vm_execmain
, synopsis_vmain
, descrip_vmain
);
7938 res
|= ast_register_application(app3
, vm_box_exists
, synopsis_vm_box_exists
, descrip_vm_box_exists
);
7939 res
|= ast_register_application(app4
, vmauthenticate
, synopsis_vmauthenticate
, descrip_vmauthenticate
);
7943 if ((res
=load_config())) {
7947 ast_cli_register_multiple(cli_voicemail
, sizeof(cli_voicemail
) / sizeof(struct ast_cli_entry
));
7949 /* compute the location of the voicemail spool directory */
7950 snprintf(VM_SPOOL_DIR
, sizeof(VM_SPOOL_DIR
), "%s/voicemail/", ast_config_AST_SPOOL_DIR
);
7952 ast_install_vm_functions(has_voicemail
, inboxcount
, messagecount
);
7957 static int dialout(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *num
, char *outgoing_context
)
7960 char destination
[80] = "";
7964 if (option_verbose
> 2)
7965 ast_verbose( VERBOSE_PREFIX_3
"Destination number will be entered manually\n");
7966 while (retries
< 3 && cmd
!= 't') {
7967 destination
[1] = '\0';
7968 destination
[0] = cmd
= ast_play_and_wait(chan
,"vm-enter-num-to-call");
7970 destination
[0] = cmd
= ast_play_and_wait(chan
, "vm-then-pound");
7972 destination
[0] = cmd
= ast_play_and_wait(chan
, "vm-star-cancel");
7974 cmd
= ast_waitfordigit(chan
, 6000);
7976 destination
[0] = cmd
;
7985 if (option_verbose
> 2)
7986 ast_verbose( VERBOSE_PREFIX_3
"User hit '*' to cancel outgoing call\n");
7989 if ((cmd
= ast_readstring(chan
,destination
+ strlen(destination
),sizeof(destination
)-1,6000,10000,"#")) < 0)
8000 if (option_verbose
> 2)
8001 ast_verbose( VERBOSE_PREFIX_3
"Destination number is CID number '%s'\n", num
);
8002 ast_copy_string(destination
, num
, sizeof(destination
));
8005 if (!ast_strlen_zero(destination
)) {
8006 if (destination
[strlen(destination
) -1 ] == '*')
8008 if (option_verbose
> 2)
8009 ast_verbose( VERBOSE_PREFIX_3
"Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination
, outgoing_context
, chan
->context
);
8010 ast_copy_string(chan
->exten
, destination
, sizeof(chan
->exten
));
8011 ast_copy_string(chan
->context
, outgoing_context
, sizeof(chan
->context
));
8018 static int advanced_options(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, int msg
, int option
, signed char record_gain
)
8022 char origtimeS
[256],cidS
[256],contextS
[256];
8023 char *header_content
,*temp
;
8025 char filename
[PATH_MAX
];
8026 struct ast_config
*msg_cfg
= NULL
;
8027 const char *origtime
, *context
;
8028 char *cid
, *name
, *num
;
8034 /* get the message info!! */
8035 if (option_debug
> 2)
8036 ast_log (LOG_DEBUG
,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
8037 if (vms
->msgArray
[vms
->curmsg
] == 0) {
8038 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
8042 /* This will only work for new messages... */
8043 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
8044 /* empty string means no valid header */
8045 if (ast_strlen_zero(header_content
)) {
8046 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
8050 /* Get info from headers!! */
8051 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Caller-ID-Num:");
8054 ast_copy_string(cidS
,temp
, sizeof(cidS
));
8059 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Context:");
8062 ast_copy_string(contextS
,temp
, sizeof(contextS
));
8066 context
= &contextS
[0];
8067 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Orig-time:");
8070 ast_copy_string(origtimeS
,temp
, sizeof(origtimeS
));
8072 origtimeS
[0] = '\0';
8074 origtime
= &origtimeS
[0];
8076 ast_copy_string(filename
, "IMAP_STORAGE", sizeof(filename
));
8078 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, msg
);
8080 /* Retrieve info from VM attribute file */
8082 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
8083 snprintf(filename
,sizeof(filename
), "%s.txt", vms
->fn2
);
8084 RETRIEVE(vms
->curdir
, vms
->curmsg
);
8085 msg_cfg
= ast_config_load(filename
);
8086 DISPOSE(vms
->curdir
, vms
->curmsg
);
8088 ast_log(LOG_WARNING
, "No message attribute file?!! (%s)\n", filename
);
8092 if (!(origtime
= ast_variable_retrieve(msg_cfg
, "message", "origtime"))) {
8093 ast_config_destroy(msg_cfg
);
8097 cid
= ast_strdupa(ast_variable_retrieve(msg_cfg
, "message", "callerid"));
8099 context
= ast_variable_retrieve(msg_cfg
, "message", "context");
8100 if (!strncasecmp("macro",context
,5)) /* Macro names in contexts are useless for our needs */
8101 context
= ast_variable_retrieve(msg_cfg
, "message","macrocontext");
8106 res
= play_message_datetime(chan
, vmu
, origtime
, filename
);
8108 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
8113 case 2: /* Call back */
8115 if (ast_strlen_zero(cid
))
8118 ast_callerid_parse(cid
, &name
, &num
);
8119 while ((res
> -1) && (res
!= 't')) {
8123 /* Dial the CID number */
8124 res
= dialout(chan
, vmu
, num
, vmu
->callback
);
8126 ast_config_destroy(msg_cfg
);
8135 /* Want to enter a different number, can only do this if there's a dialout context for this user */
8136 if (!ast_strlen_zero(vmu
->dialout
)) {
8137 res
= dialout(chan
, vmu
, NULL
, vmu
->dialout
);
8139 ast_config_destroy(msg_cfg
);
8143 if (option_verbose
> 2)
8144 ast_verbose( VERBOSE_PREFIX_3
"Caller can not specify callback number - no dialout context available\n");
8145 res
= ast_play_and_wait(chan
, "vm-sorry");
8147 ast_config_destroy(msg_cfg
);
8161 res
= ast_play_and_wait(chan
, "vm-sorry");
8166 if (option_verbose
> 2)
8167 ast_verbose( VERBOSE_PREFIX_3
"Confirm CID number '%s' is number to use for callback\n", num
);
8168 res
= ast_play_and_wait(chan
, "vm-num-i-have");
8170 res
= play_message_callerid(chan
, vms
, num
, vmu
->context
, 1);
8172 res
= ast_play_and_wait(chan
, "vm-tocallnum");
8173 /* Only prompt for a caller-specified number if there is a dialout context specified */
8174 if (!ast_strlen_zero(vmu
->dialout
)) {
8176 res
= ast_play_and_wait(chan
, "vm-calldiffnum");
8179 res
= ast_play_and_wait(chan
, "vm-nonumber");
8180 if (!ast_strlen_zero(vmu
->dialout
)) {
8182 res
= ast_play_and_wait(chan
, "vm-toenternumber");
8186 res
= ast_play_and_wait(chan
, "vm-star-cancel");
8188 res
= ast_waitfordigit(chan
, 6000);
8199 else if (res
== '*')
8205 /* Send reply directly to sender */
8206 if (ast_strlen_zero(cid
))
8209 ast_callerid_parse(cid
, &name
, &num
);
8211 if (option_verbose
> 2)
8212 ast_verbose(VERBOSE_PREFIX_3
"No CID number available, no reply sent\n");
8214 res
= ast_play_and_wait(chan
, "vm-nonumber");
8215 ast_config_destroy(msg_cfg
);
8218 struct ast_vm_user vmu2
;
8219 if (find_user(&vmu2
, vmu
->context
, num
)) {
8220 struct leave_vm_options leave_options
;
8221 char mailbox
[AST_MAX_EXTENSION
* 2 + 2];
8222 snprintf(mailbox
, sizeof(mailbox
), "%s@%s", num
, vmu
->context
);
8224 if (option_verbose
> 2)
8225 ast_verbose(VERBOSE_PREFIX_3
"Leaving voicemail for '%s' in context '%s'\n", num
, vmu
->context
);
8227 memset(&leave_options
, 0, sizeof(leave_options
));
8228 leave_options
.record_gain
= record_gain
;
8229 res
= leave_voicemail(chan
, mailbox
, &leave_options
);
8232 ast_config_destroy(msg_cfg
);
8235 /* Sender has no mailbox, can't reply */
8236 if (option_verbose
> 2)
8237 ast_verbose( VERBOSE_PREFIX_3
"No mailbox number '%s' in context '%s', no reply sent\n", num
, vmu
->context
);
8238 ast_play_and_wait(chan
, "vm-nobox");
8240 ast_config_destroy(msg_cfg
);
8249 #ifndef IMAP_STORAGE
8250 ast_config_destroy(msg_cfg
);
8253 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, msg
);
8254 vms
->heard
[msg
] = 1;
8255 res
= wait_file(chan
, vms
, vms
->fn
);
8261 static int play_record_review(struct ast_channel
*chan
, char *playfile
, char *recordfile
, int maxtime
, char *fmt
,
8262 int outsidecaller
, struct ast_vm_user
*vmu
, int *duration
, const char *unlockdir
,
8263 signed char record_gain
, struct vm_state
*vms
)
8265 /* Record message & let caller review or re-record it, or set options if applicable */
8268 int max_attempts
= 3;
8271 int message_exists
= 0;
8272 signed char zero_gain
= 0;
8273 char tempfile
[PATH_MAX
];
8274 char *acceptdtmf
= "#";
8275 char *canceldtmf
= "";
8277 /* Note that urgent and private are for flagging messages as such in the future */
8279 /* barf if no pointer passed to store duration in */
8280 if (duration
== NULL
) {
8281 ast_log(LOG_WARNING
, "Error play_record_review called without duration pointer\n");
8286 snprintf(tempfile
, sizeof(tempfile
), "%s.tmp", recordfile
);
8288 ast_copy_string(tempfile
, recordfile
, sizeof(tempfile
));
8290 cmd
= '3'; /* Want to start by recording */
8292 while ((cmd
>= 0) && (cmd
!= 't')) {
8295 if (!message_exists
) {
8296 /* In this case, 1 is to record a message */
8300 /* Otherwise 1 is to save the existing message */
8301 if (option_verbose
> 2)
8302 ast_verbose(VERBOSE_PREFIX_3
"Saving message as is\n");
8304 ast_filerename(tempfile
, recordfile
, NULL
);
8305 ast_stream_and_wait(chan
, "vm-msgsaved", chan
->language
, "");
8306 if (!outsidecaller
) {
8307 STORE(recordfile
, vmu
->mailbox
, vmu
->context
, -1, chan
, vmu
, fmt
, *duration
, vms
);
8308 DISPOSE(recordfile
, -1);
8315 if (option_verbose
> 2)
8316 ast_verbose(VERBOSE_PREFIX_3
"Reviewing the message\n");
8317 cmd
= ast_stream_and_wait(chan
, tempfile
, chan
->language
, AST_DIGIT_ANY
);
8322 if (recorded
== 1) {
8323 if (option_verbose
> 2)
8324 ast_verbose(VERBOSE_PREFIX_3
"Re-recording the message\n");
8326 if (option_verbose
> 2)
8327 ast_verbose(VERBOSE_PREFIX_3
"Recording the message\n");
8329 if (recorded
&& outsidecaller
) {
8330 cmd
= ast_play_and_wait(chan
, INTRO
);
8331 cmd
= ast_play_and_wait(chan
, "beep");
8334 /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
8336 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &record_gain
, sizeof(record_gain
), 0);
8337 if (ast_test_flag(vmu
, VM_OPERATOR
))
8339 cmd
= ast_play_and_record_full(chan
, playfile
, tempfile
, maxtime
, fmt
, duration
, silencethreshold
, maxsilence
, unlockdir
, acceptdtmf
, canceldtmf
);
8341 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &zero_gain
, sizeof(zero_gain
), 0);
8343 /* User has hung up, no options to give */
8344 if (!outsidecaller
) {
8345 /* user was recording a greeting and they hung up, so let's delete the recording. */
8346 ast_filedelete(tempfile
, NULL
);
8352 } else if (cmd
== '*') {
8356 else if (vmu
->review
&& (*duration
< 5)) {
8357 /* Message is too short */
8358 if (option_verbose
> 2)
8359 ast_verbose(VERBOSE_PREFIX_3
"Message too short\n");
8360 cmd
= ast_play_and_wait(chan
, "vm-tooshort");
8361 cmd
= ast_filedelete(tempfile
, NULL
);
8364 else if (vmu
->review
&& (cmd
== 2 && *duration
< (maxsilence
+ 3))) {
8365 /* Message is all silence */
8366 if (option_verbose
> 2)
8367 ast_verbose(VERBOSE_PREFIX_3
"Nothing recorded\n");
8368 cmd
= ast_filedelete(tempfile
, NULL
);
8369 cmd
= ast_play_and_wait(chan
, "vm-nothingrecorded");
8371 cmd
= ast_play_and_wait(chan
, "vm-speakup");
8376 /* If all is well, a message exists */
8389 cmd
= ast_play_and_wait(chan
, "vm-sorry");
8392 /* XXX Commented out for the moment because of the dangers of deleting
8393 a message while recording (can put the message numbers out of sync) */
8395 /* Cancel recording, delete message, offer to take another message*/
8396 cmd
= ast_play_and_wait(chan
, "vm-deleted");
8397 cmd
= ast_filedelete(tempfile
, NULL
);
8398 if (outsidecaller
) {
8399 res
= vm_exec(chan
, NULL
);
8406 if (!ast_test_flag(vmu
, VM_OPERATOR
)) {
8407 cmd
= ast_play_and_wait(chan
, "vm-sorry");
8410 if (message_exists
|| recorded
) {
8411 cmd
= ast_play_and_wait(chan
, "vm-saveoper");
8413 cmd
= ast_waitfordigit(chan
, 3000);
8415 ast_play_and_wait(chan
, "vm-msgsaved");
8418 ast_play_and_wait(chan
, "vm-deleted");
8419 DELETE(recordfile
, -1, recordfile
);
8425 /* If the caller is an ouside caller, and the review option is enabled,
8426 allow them to review the message, but let the owner of the box review
8428 if (outsidecaller
&& !ast_test_flag(vmu
, VM_REVIEW
))
8430 if (message_exists
) {
8431 cmd
= ast_play_and_wait(chan
, "vm-review");
8434 cmd
= ast_play_and_wait(chan
, "vm-torerecord");
8436 cmd
= ast_waitfordigit(chan
, 600);
8439 if (!cmd
&& outsidecaller
&& ast_test_flag(vmu
, VM_OPERATOR
)) {
8440 cmd
= ast_play_and_wait(chan
, "vm-reachoper");
8442 cmd
= ast_waitfordigit(chan
, 600);
8446 cmd
= ast_play_and_wait(chan
, "vm-tocancelmsg");
8449 cmd
= ast_waitfordigit(chan
, 6000);
8453 if (attempts
> max_attempts
) {
8459 ast_play_and_wait(chan
, "vm-goodbye");
8467 static void write_file(char *filename
, char *buffer
, unsigned long len
)
8471 output
= fopen (filename
, "w");
8472 fwrite (buffer
, len
, 1, output
);
8476 void mm_searched(MAILSTREAM
*stream
, unsigned long number
)
8478 struct vm_state
*vms
;
8481 mailbox
= stream
->mailbox
;
8482 user
= get_user_by_mailbox(mailbox
);
8483 vms
= get_vm_state_by_imapuser(user
,2);
8485 if (option_debug
> 2)
8486 ast_log (LOG_DEBUG
, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number
,vms
->vmArrayIndex
,vms
->interactive
);
8487 vms
->msgArray
[vms
->vmArrayIndex
++] = number
;
8489 ast_log (LOG_ERROR
, "No state found.\n");
8494 #if 0 /*No need for this. */
8496 * Accepts: MAIL stream
8498 static void status(MAILSTREAM
*stream
)
8501 char *s
, date
[MAILTMPLEN
];
8503 AUTHENTICATOR
*auth
;
8505 ast_log (LOG_NOTICE
,"%s\n",date
);
8507 if (stream
->mailbox
)
8508 ast_log (LOG_NOTICE
," %s mailbox: %s, %lu messages, %lu recent\n",
8509 stream
->dtb
->name
, stream
->mailbox
, stream
->nmsgs
,stream
->recent
);
8511 ast_log (LOG_NOTICE
,"No mailbox is open on this stream\n");
8512 if (stream
->user_flags
[0]) {
8513 ast_log (LOG_NOTICE
,"Keywords: %s\n", stream
->user_flags
[0]);
8514 for (i
= 1; i
< NUSERFLAGS
&& stream
->user_flags
[i
]; ++i
)
8515 ast_log (LOG_NOTICE
," %s\n", stream
->user_flags
[i
]);
8517 if (!strcmp (stream
->dtb
->name
, "imap")) {
8518 if (LEVELIMAP4rev1 (stream
))
8519 s
= "IMAP4rev1 (RFC 3501)";
8520 else if (LEVEL1730 (stream
))
8521 s
= "IMAP4 (RFC 1730)";
8522 else if (LEVELIMAP2bis (stream
))
8524 else if (LEVEL1176 (stream
))
8525 s
= "IMAP2 (RFC 1176)";
8527 s
= "IMAP2 (RFC 1064)";
8528 ast_log (LOG_NOTICE
,"%s server %s\n", s
, imap_host (stream
));
8529 if (LEVELIMAP4 (stream
)) {
8530 if ((i
= (imap_cap(stream
)->auth
))) {
8532 ast_log (LOG_NOTICE
,"Mutually-supported SASL mechanisms:\n");
8533 while ((auth
= mail_lookup_auth (find_rightmost_bit (&i
) + 1))) {
8534 ast_log (LOG_NOTICE
," %s\n", auth
->name
);
8535 if (!strcmp (auth
->name
, "PLAIN"))
8536 s
= "\n [LOGIN will not be listed here if PLAIN is supported]\n";
8538 ast_log (LOG_NOTICE
,s
);
8540 ast_log (LOG_NOTICE
,"Supported standard extensions:\n");
8541 if (LEVELACL (stream
))
8542 ast_log (LOG_NOTICE
," Access Control lists (RFC 2086)\n");
8543 if (LEVELQUOTA (stream
))
8544 ast_log (LOG_NOTICE
," Quotas (RFC 2087)\n");
8545 if (LEVELLITERALPLUS (stream
))
8546 ast_log (LOG_NOTICE
," Non-synchronizing literals (RFC 2088)\n");
8547 if (LEVELIDLE (stream
))
8548 ast_log (LOG_NOTICE
," IDLE unsolicited update (RFC 2177)\n");
8549 if (LEVELMBX_REF (stream
))
8550 ast_log (LOG_NOTICE
," Mailbox referrals (RFC 2193)\n");
8551 if (LEVELLOG_REF (stream
))
8552 ast_log (LOG_NOTICE
," Login referrals (RFC 2221)\n");
8553 if (LEVELANONYMOUS (stream
))
8554 ast_log (LOG_NOTICE
," Anonymous access (RFC 2245)\n");
8555 if (LEVELNAMESPACE (stream
))
8556 ast_log (LOG_NOTICE
," Multiple namespaces (RFC 2342)\n");
8557 if (LEVELUIDPLUS (stream
))
8558 ast_log (LOG_NOTICE
," Extended UID behavior (RFC 2359)\n");
8559 if (LEVELSTARTTLS (stream
))
8560 ast_log (LOG_NOTICE
," Transport Layer Security (RFC 2595)\n");
8561 if (LEVELLOGINDISABLED (stream
))
8562 ast_log (LOG_NOTICE
," LOGIN command disabled (RFC 2595)\n");
8563 if (LEVELID (stream
))
8564 ast_log (LOG_NOTICE
," Implementation identity negotiation (RFC 2971)\n");
8565 if (LEVELCHILDREN (stream
))
8566 ast_log (LOG_NOTICE
," LIST children announcement (RFC 3348)\n");
8567 if (LEVELMULTIAPPEND (stream
))
8568 ast_log (LOG_NOTICE
," Atomic multiple APPEND (RFC 3502)\n");
8569 if (LEVELBINARY (stream
))
8570 ast_log (LOG_NOTICE
," Binary body content (RFC 3516)\n");
8571 ast_log (LOG_NOTICE
,"Supported draft extensions:\n");
8572 if (LEVELUNSELECT (stream
))
8573 ast_log (LOG_NOTICE
," Mailbox unselect\n");
8574 if (LEVELSASLIR (stream
))
8575 ast_log (LOG_NOTICE
," SASL initial client response\n");
8576 if (LEVELSORT (stream
))
8577 ast_log (LOG_NOTICE
," Server-based sorting\n");
8578 if (LEVELTHREAD (stream
)) {
8579 ast_log (LOG_NOTICE
," Server-based threading:\n");
8580 for (thr
= imap_cap(stream
)->threader
; thr
; thr
= thr
->next
)
8581 ast_log (LOG_NOTICE
," %s\n", thr
->name
);
8583 if (LEVELSCAN (stream
))
8584 ast_log (LOG_NOTICE
," Mailbox text scan\n");
8585 if ((i
= imap_cap(stream
)->extlevel
)) {
8586 ast_log (LOG_NOTICE
,"Supported BODYSTRUCTURE extensions:\n");
8589 ast_log (LOG_NOTICE
," location\n");
8591 ast_log (LOG_NOTICE
," language\n");
8593 ast_log (LOG_NOTICE
," disposition\n");
8595 ast_log (LOG_NOTICE
," MD5\n");
8599 ast_log (LOG_NOTICE
,"\n");
8605 static struct ast_vm_user
*find_user_realtime_imapuser(const char *imapuser
)
8607 struct ast_variable
*var
;
8608 struct ast_vm_user
*vmu
;
8610 vmu
= ast_calloc(1, sizeof *vmu
);
8613 ast_set_flag(vmu
, VM_ALLOCED
);
8614 populate_defaults(vmu
);
8616 var
= ast_load_realtime("voicemail", "imapuser", imapuser
, NULL
);
8618 apply_options_full(vmu
, var
);
8619 ast_variables_destroy(var
);
8627 /* Interfaces to C-client */
8629 void mm_exists(MAILSTREAM
* stream
, unsigned long number
)
8631 /* mail_ping will callback here if new mail! */
8632 if (option_debug
> 3)
8633 ast_log (LOG_DEBUG
, "Entering EXISTS callback for message %ld\n", number
);
8634 if (number
== 0) return;
8639 void mm_expunged(MAILSTREAM
* stream
, unsigned long number
)
8641 /* mail_ping will callback here if expunged mail! */
8642 if (option_debug
> 3)
8643 ast_log (LOG_DEBUG
, "Entering EXPUNGE callback for message %ld\n", number
);
8644 if (number
== 0) return;
8649 void mm_flags(MAILSTREAM
* stream
, unsigned long number
)
8651 /* mail_ping will callback here if read mail! */
8652 if (option_debug
> 3)
8653 ast_log (LOG_DEBUG
, "Entering FLAGS callback for message %ld\n", number
);
8654 if (number
== 0) return;
8659 void mm_notify(MAILSTREAM
* stream
, char *string
, long errflg
)
8661 mm_log (string
, errflg
);
8665 void mm_list(MAILSTREAM
* stream
, int delim
, char *mailbox
, long attributes
)
8667 if (delimiter
== '\0') {
8670 if (option_debug
> 4) {
8671 ast_log(LOG_DEBUG
, "Delimiter set to %c and mailbox %s\n",delim
, mailbox
);
8672 if (attributes
& LATT_NOINFERIORS
)
8673 ast_log(LOG_DEBUG
, "no inferiors\n");
8674 if (attributes
& LATT_NOSELECT
)
8675 ast_log(LOG_DEBUG
, "no select\n");
8676 if (attributes
& LATT_MARKED
)
8677 ast_log(LOG_DEBUG
, "marked\n");
8678 if (attributes
& LATT_UNMARKED
)
8679 ast_log(LOG_DEBUG
, "unmarked\n");
8684 void mm_lsub(MAILSTREAM
* stream
, int delimiter
, char *mailbox
, long attributes
)
8686 if (option_debug
> 4) {
8687 ast_log(LOG_DEBUG
, "Delimiter set to %c and mailbox %s\n",delimiter
, mailbox
);
8688 if (attributes
& LATT_NOINFERIORS
)
8689 ast_log(LOG_DEBUG
, "no inferiors\n");
8690 if (attributes
& LATT_NOSELECT
)
8691 ast_log(LOG_DEBUG
, "no select\n");
8692 if (attributes
& LATT_MARKED
)
8693 ast_log(LOG_DEBUG
, "marked\n");
8694 if (attributes
& LATT_UNMARKED
)
8695 ast_log(LOG_DEBUG
, "unmarked\n");
8700 void mm_status(MAILSTREAM
* stream
, char *mailbox
, MAILSTATUS
* status
)
8702 ast_log (LOG_NOTICE
," Mailbox %s", mailbox
);
8703 if (status
->flags
& SA_MESSAGES
)
8704 ast_log (LOG_NOTICE
,", %lu messages", status
->messages
);
8705 if (status
->flags
& SA_RECENT
)
8706 ast_log (LOG_NOTICE
,", %lu recent", status
->recent
);
8707 if (status
->flags
& SA_UNSEEN
)
8708 ast_log (LOG_NOTICE
,", %lu unseen", status
->unseen
);
8709 if (status
->flags
& SA_UIDVALIDITY
)
8710 ast_log (LOG_NOTICE
,", %lu UID validity", status
->uidvalidity
);
8711 if (status
->flags
& SA_UIDNEXT
)
8712 ast_log (LOG_NOTICE
,", %lu next UID", status
->uidnext
);
8713 ast_log (LOG_NOTICE
,"\n");
8717 void mm_log(char *string
, long errflg
)
8719 switch ((short) errflg
) {
8722 ast_log(LOG_DEBUG
,"IMAP Info: %s\n", string
);
8726 ast_log (LOG_WARNING
,"IMAP Warning: %s\n", string
);
8729 ast_log (LOG_ERROR
,"IMAP Error: %s\n", string
);
8735 void mm_dlog(char *string
)
8737 ast_log (LOG_NOTICE
, "%s\n", string
);
8741 void mm_login(NETMBX
* mb
, char *user
, char *pwd
, long trial
)
8743 struct ast_vm_user
*vmu
;
8745 if (option_debug
> 3)
8746 ast_log(LOG_DEBUG
, "Entering callback mm_login\n");
8748 ast_copy_string(user
, mb
->user
, MAILTMPLEN
);
8750 /* We should only do this when necessary */
8751 if (!ast_strlen_zero(authpassword
)) {
8752 ast_copy_string(pwd
, authpassword
, MAILTMPLEN
);
8754 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
8755 if (!strcasecmp(mb
->user
, vmu
->imapuser
)) {
8756 ast_copy_string(pwd
, vmu
->imappassword
, MAILTMPLEN
);
8761 if ((vmu
= find_user_realtime_imapuser(mb
->user
))) {
8762 ast_copy_string(pwd
, vmu
->imappassword
, MAILTMPLEN
);
8770 void mm_critical(MAILSTREAM
* stream
)
8775 void mm_nocritical(MAILSTREAM
* stream
)
8780 long mm_diskerror(MAILSTREAM
* stream
, long errcode
, long serious
)
8782 kill (getpid (), SIGSTOP
);
8787 void mm_fatal(char *string
)
8789 ast_log(LOG_ERROR
,"IMAP access FATAL error: %s\n", string
);
8792 /* C-client callback to handle quota */
8793 static void mm_parsequota(MAILSTREAM
*stream
, unsigned char *msg
, QUOTALIST
*pquota
)
8795 struct vm_state
*vms
;
8798 unsigned long usage
= 0;
8799 unsigned long limit
= 0;
8802 usage
= pquota
->usage
;
8803 limit
= pquota
->limit
;
8804 pquota
= pquota
->next
;
8807 mailbox
= stream
->mailbox
;
8808 user
= get_user_by_mailbox(mailbox
);
8809 vms
= get_vm_state_by_imapuser(user
,2);
8811 if (option_debug
> 2)
8812 ast_log (LOG_DEBUG
, "User %s usage is %lu, limit is %lu\n",user
,usage
,limit
);
8813 vms
->quota_usage
= usage
;
8814 vms
->quota_limit
= limit
;
8816 ast_log (LOG_ERROR
, "No state found.\n");
8820 static char *get_header_by_tag(char *header
, char *tag
)
8826 if (!header
|| !tag
)
8829 taglen
= strlen(tag
) + 1;
8833 start
= strstr(header
, tag
);
8837 ast_mutex_lock(&imaptemp_lock
);
8838 ast_copy_string(imaptemp
, start
+taglen
, sizeof(imaptemp
));
8839 ast_mutex_unlock(&imaptemp_lock
);
8840 if ((eol_pnt
= strchr(imaptemp
,'\r')) || (eol_pnt
= strchr(imaptemp
,'\n')))
8845 static char *get_user_by_mailbox(char *mailbox
)
8847 char *start
, *quote
;
8853 start
= strstr(mailbox
,"/user=");
8857 ast_mutex_lock(&imaptemp_lock
);
8858 ast_copy_string(imaptemp
, start
+6, sizeof(imaptemp
));
8859 ast_mutex_unlock(&imaptemp_lock
);
8861 quote
= strchr(imaptemp
,'\"');
8862 if (!quote
) { /* if username is not in quotes */
8863 eol_pnt
= strchr(imaptemp
,'/');
8865 eol_pnt
= strchr(imaptemp
,'}');
8870 eol_pnt
= strchr(imaptemp
+1,'\"');
8876 static struct vm_state
*get_vm_state_by_imapuser(char *user
, int interactive
)
8878 struct vmstate
*vlist
= NULL
;
8880 ast_mutex_lock(&vmstate_lock
);
8884 if (vlist
->vms
->imapuser
) {
8885 if (!strcmp(vlist
->vms
->imapuser
,user
)) {
8886 if (interactive
== 2) {
8887 ast_mutex_unlock(&vmstate_lock
);
8889 } else if (vlist
->vms
->interactive
== interactive
) {
8890 ast_mutex_unlock(&vmstate_lock
);
8895 if (option_debug
> 2)
8896 ast_log(LOG_DEBUG
, " error: imapuser is NULL for %s\n",user
);
8899 if (option_debug
> 2)
8900 ast_log(LOG_DEBUG
, " error: vms is NULL for %s\n",user
);
8902 vlist
= vlist
->next
;
8904 ast_mutex_unlock(&vmstate_lock
);
8905 if (option_debug
> 2)
8906 ast_log(LOG_DEBUG
, "%s not found in vmstates\n",user
);
8910 static struct vm_state
*get_vm_state_by_mailbox(const char *mailbox
, int interactive
)
8912 struct vmstate
*vlist
= NULL
;
8914 ast_mutex_lock(&vmstate_lock
);
8916 if (option_debug
> 2)
8917 ast_log(LOG_DEBUG
, "Mailbox set to %s\n",mailbox
);
8920 if (vlist
->vms
->username
) {
8921 if (option_debug
> 2)
8922 ast_log(LOG_DEBUG
, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox
,interactive
,vlist
->vms
->username
,vlist
->vms
->interactive
);
8923 if (!strcmp(vlist
->vms
->username
,mailbox
) && vlist
->vms
->interactive
== interactive
) {
8924 if (option_debug
> 2)
8925 ast_log(LOG_DEBUG
, " Found it!\n");
8926 ast_mutex_unlock(&vmstate_lock
);
8930 if (option_debug
> 2)
8931 ast_log(LOG_DEBUG
, " error: username is NULL for %s\n",mailbox
);
8934 if (option_debug
> 2)
8935 ast_log(LOG_DEBUG
, " error: vms is NULL for %s\n",mailbox
);
8937 vlist
= vlist
->next
;
8939 ast_mutex_unlock(&vmstate_lock
);
8940 if (option_debug
> 2)
8941 ast_log(LOG_DEBUG
, "%s not found in vmstates\n",mailbox
);
8945 static void vmstate_insert(struct vm_state
*vms
)
8948 struct vm_state
*altvms
;
8950 /* If interactive, it probably already exists, and we should
8951 use the one we already have since it is more up to date.
8952 We can compare the username to find the duplicate */
8953 if (vms
->interactive
== 1) {
8954 altvms
= get_vm_state_by_mailbox(vms
->username
,0);
8956 if (option_debug
> 2)
8957 ast_log(LOG_DEBUG
, "Duplicate mailbox %s, copying message info...\n",vms
->username
);
8958 vms
->newmessages
= altvms
->newmessages
;
8959 vms
->oldmessages
= altvms
->oldmessages
;
8960 if (option_debug
> 2)
8961 ast_log(LOG_DEBUG
, "check_msgArray before memcpy\n");
8962 check_msgArray(vms
);
8963 /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long)*256); */
8964 copy_msgArray(vms
, altvms
);
8965 if (option_debug
> 2)
8966 ast_log(LOG_DEBUG
, "check_msgArray after memcpy\n");
8967 check_msgArray(vms
);
8968 vms
->vmArrayIndex
= altvms
->vmArrayIndex
;
8969 vms
->lastmsg
= altvms
->lastmsg
;
8970 vms
->curmsg
= altvms
->curmsg
;
8971 /* get a pointer to the persistent store */
8972 vms
->persist_vms
= altvms
;
8973 /* Reuse the mailstream? */
8974 vms
->mailstream
= altvms
->mailstream
;
8975 /* vms->mailstream = NIL; */
8979 v
= (struct vmstate
*)malloc(sizeof(struct vmstate
));
8981 ast_log(LOG_ERROR
, "Out of memory\n");
8983 if (option_debug
> 2)
8984 ast_log(LOG_DEBUG
, "Inserting vm_state for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
8985 ast_mutex_lock(&vmstate_lock
);
8989 ast_mutex_unlock(&vmstate_lock
);
8992 static void vmstate_delete(struct vm_state
*vms
)
8994 struct vmstate
*vc
, *vf
= NULL
, *vl
= NULL
;
8995 struct vm_state
*altvms
;
8997 /* If interactive, we should copy pertainent info
8998 back to the persistent state (to make update immediate) */
8999 if (vms
->interactive
== 1) {
9000 altvms
= vms
->persist_vms
;
9002 if (option_debug
> 2)
9003 ast_log(LOG_DEBUG
, "Duplicate mailbox %s, copying message info...\n",vms
->username
);
9004 altvms
->newmessages
= vms
->newmessages
;
9005 altvms
->oldmessages
= vms
->oldmessages
;
9006 altvms
->updated
= 1;
9010 ast_mutex_lock(&vmstate_lock
);
9012 if (option_debug
> 2)
9013 ast_log(LOG_DEBUG
, "Removing vm_state for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
9015 if (vc
->vms
== vms
) {
9018 vl
->next
= vc
->next
;
9020 vmstates
= vc
->next
;
9027 ast_log(LOG_ERROR
, "No vmstate found for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
9031 ast_mutex_unlock(&vmstate_lock
);
9034 static void set_update(MAILSTREAM
* stream
)
9036 struct vm_state
*vms
;
9040 mailbox
= stream
->mailbox
;
9041 user
= get_user_by_mailbox(mailbox
);
9042 vms
= get_vm_state_by_imapuser(user
, 0);
9044 if (option_debug
> 2)
9045 ast_log (LOG_DEBUG
, "User %s mailbox set for update.\n",user
);
9046 vms
->updated
= 1; /* set updated flag since mailbox changed */
9048 if (option_debug
> 2)
9049 ast_log (LOG_WARNING
, "User %s mailbox not found for update.\n",user
);
9053 static void init_vm_state(struct vm_state
*vms
)
9056 vms
->vmArrayIndex
= 0;
9057 for (x
= 0; x
< 256; x
++) {
9058 vms
->msgArray
[x
] = 0;
9062 static void check_msgArray(struct vm_state
*vms
)
9065 for (x
= 0; x
<256; x
++) {
9066 if (vms
->msgArray
[x
]!=0) {
9068 ast_log (LOG_DEBUG
, "Item %d set to %ld\n",x
,vms
->msgArray
[x
]);
9073 static void copy_msgArray(struct vm_state
*dst
, struct vm_state
*src
)
9076 for (x
= 0; x
<256; x
++) {
9077 dst
->msgArray
[x
] = src
->msgArray
[x
];
9081 static int save_body(BODY
*body
, struct vm_state
*vms
, char *section
, char *format
)
9086 unsigned long newlen
;
9089 if (!body
|| body
== NIL
)
9091 body_content
= mail_fetchbody (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
], section
, &len
);
9092 if (body_content
!= NIL
) {
9093 snprintf(filename
, sizeof(filename
), "%s.%s", vms
->fn
, format
);
9094 /* ast_log (LOG_DEBUG,body_content); */
9095 body_decoded
= rfc822_base64 ((unsigned char *)body_content
, len
, &newlen
);
9096 write_file (filename
, (char *) body_decoded
, newlen
);
9101 /* get delimiter via mm_list callback */
9102 static void get_mailbox_delimiter(MAILSTREAM
*stream
) {
9104 snprintf(tmp
, sizeof(tmp
), "{%s}", imapserver
);
9105 mail_list(stream
, tmp
, "*");
9108 /* Check Quota for user */
9109 static void check_quota(struct vm_state
*vms
, char *mailbox
) {
9110 mail_parameters(NULL
, SET_QUOTA
, (void *) mm_parsequota
);
9111 if (option_debug
> 2)
9112 ast_log(LOG_DEBUG
, "Mailbox name set to: %s, about to check quotas\n", mailbox
);
9113 if (vms
&& vms
->mailstream
!= NULL
) {
9114 imap_getquotaroot(vms
->mailstream
, mailbox
);
9116 ast_log(LOG_WARNING
,"Mailstream not available for mailbox: %s\n",mailbox
);
9120 #endif /* IMAP_STORAGE */
9122 /* This is a workaround so that menuselect displays a proper description
9123 * AST_MODULE_INFO(, , "Comedian Mail (Voicemail System)"
9126 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, tdesc
,
9127 .load
= load_module
,
9128 .unload
= unload_module
,