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>
77 #include "asterisk/lock.h"
78 #include "asterisk/file.h"
79 #include "asterisk/logger.h"
80 #include "asterisk/channel.h"
81 #include "asterisk/pbx.h"
82 #include "asterisk/options.h"
83 #include "asterisk/config.h"
84 #include "asterisk/say.h"
85 #include "asterisk/module.h"
86 #include "asterisk/adsi.h"
87 #include "asterisk/app.h"
88 #include "asterisk/manager.h"
89 #include "asterisk/dsp.h"
90 #include "asterisk/localtime.h"
91 #include "asterisk/cli.h"
92 #include "asterisk/utils.h"
93 #include "asterisk/stringfields.h"
94 #include "asterisk/smdi.h"
96 #include "asterisk/res_odbc.h"
100 AST_MUTEX_DEFINE_STATIC(imaptemp_lock
);
101 static char imaptemp
[1024];
103 static char imapserver
[48];
104 static char imapport
[8];
105 static char imapflags
[128];
106 static char imapfolder
[64];
107 static char authuser
[32];
108 static char authpassword
[42];
110 static int expungeonhangup
= 1;
111 static char delimiter
= '\0';
116 static int init_mailstream (struct vm_state
*vms
, int box
);
117 static void write_file (char *filename
, char *buffer
, unsigned long len
);
118 /*static void status (MAILSTREAM *stream); */ /* No need for this. */
119 static char *get_header_by_tag(char *header
, char *tag
);
120 static void vm_imap_delete(int msgnum
, struct vm_state
*vms
);
121 static char *get_user_by_mailbox(char *mailbox
);
122 static struct vm_state
*get_vm_state_by_imapuser(char *user
, int interactive
);
123 static struct vm_state
*get_vm_state_by_mailbox(const char *mailbox
, int interactive
);
124 static void vmstate_insert(struct vm_state
*vms
);
125 static void vmstate_delete(struct vm_state
*vms
);
126 static void set_update(MAILSTREAM
* stream
);
127 static void init_vm_state(struct vm_state
*vms
);
128 static void check_msgArray(struct vm_state
*vms
);
129 static void copy_msgArray(struct vm_state
*dst
, struct vm_state
*src
);
130 static int save_body(BODY
*body
, struct vm_state
*vms
, char *section
, char *format
);
131 static int make_gsm_file(char *dest
, size_t len
, char *imapuser
, char *dir
, int num
);
132 static void get_mailbox_delimiter(MAILSTREAM
*stream
);
133 static void mm_parsequota (MAILSTREAM
*stream
, unsigned char *msg
, QUOTALIST
*pquota
);
134 static void imap_mailbox_name(char *spec
, size_t len
, struct vm_state
*vms
, int box
, int target
);
135 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
);
136 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
,int box
);
138 struct vm_state
*vms
;
139 struct vmstate
*next
;
141 AST_MUTEX_DEFINE_STATIC(vmstate_lock
);
142 static struct vmstate
*vmstates
= NULL
;
145 #define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
147 #define COMMAND_TIMEOUT 5000
148 /* Don't modify these here; set your umask at runtime instead */
149 #define VOICEMAIL_DIR_MODE 0777
150 #define VOICEMAIL_FILE_MODE 0666
151 #define CHUNKSIZE 65536
153 #define VOICEMAIL_CONFIG "voicemail.conf"
154 #define ASTERISK_USERNAME "asterisk"
156 /* Default mail command to mail voicemail. Change it with the
157 mailcmd= command in voicemail.conf */
158 #define SENDMAIL "/usr/sbin/sendmail -t"
160 #define INTRO "vm-intro"
163 #define MAXMSGLIMIT 9999
165 #define BASEMAXINLINE 256
166 #define BASELINELEN 72
167 #define BASEMAXINLINE 256
170 #define MAX_DATETIME_FORMAT 512
171 #define MAX_NUM_CID_CONTEXTS 10
173 #define VM_REVIEW (1 << 0)
174 #define VM_OPERATOR (1 << 1)
175 #define VM_SAYCID (1 << 2)
176 #define VM_SVMAIL (1 << 3)
177 #define VM_ENVELOPE (1 << 4)
178 #define VM_SAYDURATION (1 << 5)
179 #define VM_SKIPAFTERCMD (1 << 6)
180 #define VM_FORCENAME (1 << 7) /*!< Have new users record their name */
181 #define VM_FORCEGREET (1 << 8) /*!< Have new users record their greetings */
182 #define VM_PBXSKIP (1 << 9)
183 #define VM_DIRECFORWARD (1 << 10) /*!< directory_forward */
184 #define VM_ATTACH (1 << 11)
185 #define VM_DELETE (1 << 12)
186 #define VM_ALLOCED (1 << 13)
187 #define VM_SEARCH (1 << 14)
188 #define VM_TEMPGREETWARN (1 << 15) /*!< Remind user tempgreeting is set */
189 #define ERROR_LOCK_PATH -100
193 OPT_SILENT
= (1 << 0),
194 OPT_BUSY_GREETING
= (1 << 1),
195 OPT_UNAVAIL_GREETING
= (1 << 2),
196 OPT_RECORDGAIN
= (1 << 3),
197 OPT_PREPEND_MAILBOX
= (1 << 4),
198 OPT_PRIORITY_JUMP
= (1 << 5),
199 OPT_AUTOPLAY
= (1 << 6),
203 OPT_ARG_RECORDGAIN
= 0,
204 OPT_ARG_PLAYFOLDER
= 1,
205 /* This *must* be the last value in this enum! */
206 OPT_ARG_ARRAY_SIZE
= 2,
209 AST_APP_OPTIONS(vm_app_options
, {
210 AST_APP_OPTION('s', OPT_SILENT
),
211 AST_APP_OPTION('b', OPT_BUSY_GREETING
),
212 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING
),
213 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN
, OPT_ARG_RECORDGAIN
),
214 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX
),
215 AST_APP_OPTION('j', OPT_PRIORITY_JUMP
),
216 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY
, OPT_ARG_PLAYFOLDER
),
219 static int load_config(void);
221 /*! \page vmlang Voicemail Language Syntaxes Supported
223 \par Syntaxes supported, not really language codes.
231 \arg \b pt - Portuguese
232 \arg \b pt_BR - Portuguese (Brazil)
234 \arg \b no - Norwegian
236 \arg \b ua - Ukrainian
238 German requires the following additional soundfile:
239 \arg \b 1F einE (feminine)
241 Spanish requires the following additional soundfile:
242 \arg \b 1M un (masculine)
244 Dutch, Portuguese & Spanish require the following additional soundfiles:
245 \arg \b vm-INBOXs singular of 'new'
246 \arg \b vm-Olds singular of 'old/heard/read'
249 \arg \b vm-INBOX nieuwe (nl)
250 \arg \b vm-Old oude (nl)
253 \arg \b vm-new-a 'new', feminine singular accusative
254 \arg \b vm-new-e 'new', feminine plural accusative
255 \arg \b vm-new-ych 'new', feminine plural genitive
256 \arg \b vm-old-a 'old', feminine singular accusative
257 \arg \b vm-old-e 'old', feminine plural accusative
258 \arg \b vm-old-ych 'old', feminine plural genitive
259 \arg \b digits/1-a 'one', not always same as 'digits/1'
260 \arg \b digits/2-ie 'two', not always same as 'digits/2'
263 \arg \b vm-nytt singular of 'new'
264 \arg \b vm-nya plural of 'new'
265 \arg \b vm-gammalt singular of 'old'
266 \arg \b vm-gamla plural of 'old'
267 \arg \b digits/ett 'one', not always same as 'digits/1'
270 \arg \b vm-ny singular of 'new'
271 \arg \b vm-nye plural of 'new'
272 \arg \b vm-gammel singular of 'old'
273 \arg \b vm-gamle plural of 'old'
281 Ukrainian requires the following additional soundfile:
282 \arg \b vm-nove 'nove'
283 \arg \b vm-stare 'stare'
284 \arg \b digits/ua/1e 'odne'
286 Italian requires the following additional soundfile:
290 \arg \b vm-nuovi new plural
291 \arg \b vm-vecchio old
292 \arg \b vm-vecchi old plural
294 \note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
295 spelled among others when you have to change folder. For the above reasons, vm-INBOX
296 and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
305 unsigned char iobuf
[BASEMAXINLINE
];
308 /*! Structure for linked list of users */
310 char context
[AST_MAX_CONTEXT
]; /*!< Voicemail context */
311 char mailbox
[AST_MAX_EXTENSION
]; /*!< Mailbox id, unique within vm context */
312 char password
[80]; /*!< Secret pin code, numbers only */
313 char fullname
[80]; /*!< Full name, for directory app */
314 char email
[80]; /*!< E-mail address */
315 char pager
[80]; /*!< E-mail address to pager (no attachment) */
316 char serveremail
[80]; /*!< From: Mail address */
317 char mailcmd
[160]; /*!< Configurable mail command */
318 char language
[MAX_LANGUAGE
]; /*!< Config: Language setting */
319 char zonetag
[80]; /*!< Time zone */
322 char uniqueid
[20]; /*!< Unique integer identifier */
324 char attachfmt
[20]; /*!< Attachment format */
325 unsigned int flags
; /*!< VM_ flags */
327 int maxmsg
; /*!< Maximum number of msgs per folder for this mailbox */
329 char imapuser
[80]; /* IMAP server login */
330 char imappassword
[80]; /* IMAP server password if authpassword not defined */
332 double volgain
; /*!< Volume gain for voicemails sent via email */
333 AST_LIST_ENTRY(ast_vm_user
) list
;
337 AST_LIST_ENTRY(vm_zone
) list
;
340 char msg_format
[512];
346 char curdir
[PATH_MAX
];
347 char vmbox
[PATH_MAX
];
359 int updated
; /* decremented on each mail check until 1 -allows delay */
361 MAILSTREAM
*mailstream
;
363 char imapuser
[80]; /* IMAP server login */
365 unsigned int quota_limit
;
366 unsigned int quota_usage
;
367 struct vm_state
*persist_vms
;
370 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
);
371 static int dialout(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *num
, char *outgoing_context
);
372 static int play_record_review(struct ast_channel
*chan
, char *playfile
, char *recordfile
, int maxtime
,
373 char *fmt
, int outsidecaller
, struct ast_vm_user
*vmu
, int *duration
, const char *unlockdir
,
374 signed char record_gain
, struct vm_state
*vms
);
375 static int vm_tempgreeting(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
);
376 static int vm_play_folder_name(struct ast_channel
*chan
, char *mbox
);
377 static int notify_new_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int msgnum
, long duration
, char *fmt
, char *cidnum
, char *cidname
);
378 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
);
379 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
380 static int __has_voicemail(const char *context
, const char *mailbox
, const char *folder
, int shortcircuit
);
382 static void apply_options(struct ast_vm_user
*vmu
, const char *options
);
385 static char odbc_database
[80];
386 static char odbc_table
[80];
387 #define RETRIEVE(a,b) retrieve_file(a,b)
388 #define DISPOSE(a,b) remove_file(a,b)
389 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
390 #define EXISTS(a,b,c,d) (message_exists(a,b))
391 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
392 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
393 #define DELETE(a,b,c) (delete_file(a,b))
396 #define RETRIEVE(a,b)
398 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
399 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
400 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
401 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
402 #define IMAP_DELETE(a,b,c,d) (vm_imap_delete(b,d))
403 #define DELETE(a,b,c) (vm_delete(c))
405 #define RETRIEVE(a,b)
407 #define STORE(a,b,c,d,e,f,g,h,i)
408 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
409 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
410 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
411 #define DELETE(a,b,c) (vm_delete(c))
415 static char VM_SPOOL_DIR
[PATH_MAX
];
417 static char ext_pass_cmd
[128];
422 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
424 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
426 #define tdesc "Comedian Mail (Voicemail System)"
429 static char userscontext
[AST_MAX_EXTENSION
] = "default";
431 static char *addesc
= "Comedian Mail";
433 static char *synopsis_vm
=
434 "Leave a Voicemail message";
436 static char *descrip_vm
=
437 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
438 "application allows the calling party to leave a message for the specified\n"
439 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
440 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
441 "specified mailbox does not exist.\n"
442 " The Voicemail application will exit if any of the following DTMF digits are\n"
444 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
445 " * - Jump to the 'a' extension in the current dialplan context.\n"
446 " This application will set the following channel variable upon completion:\n"
447 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
448 " application. The possible values are:\n"
449 " SUCCESS | USEREXIT | FAILED\n\n"
451 " b - Play the 'busy' greeting to the calling party.\n"
452 " g(#) - Use the specified amount of gain when recording the voicemail\n"
453 " message. The units are whole-number decibels (dB).\n"
454 " s - Skip the playback of instructions for leaving a message to the\n"
456 " u - Play the 'unavailable' greeting.\n"
457 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
460 static char *synopsis_vmain
=
461 "Check Voicemail messages";
463 static char *descrip_vmain
=
464 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
465 "calling party to check voicemail messages. A specific mailbox, and optional\n"
466 "corresponding context, may be specified. If a mailbox is not provided, the\n"
467 "calling party will be prompted to enter one. If a context is not specified,\n"
468 "the 'default' context will be used.\n\n"
470 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
471 " is entered by the caller.\n"
472 " g(#) - Use the specified amount of gain when recording a voicemail\n"
473 " message. The units are whole-number decibels (dB).\n"
474 " s - Skip checking the passcode for the mailbox.\n"
475 " a(#) - Skip folder prompt and go directly to folder specified.\n"
476 " Defaults to INBOX\n";
478 static char *synopsis_vm_box_exists
=
479 "Check to see if Voicemail mailbox exists";
481 static char *descrip_vm_box_exists
=
482 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
483 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
485 " This application will set the following channel variable upon completion:\n"
486 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
487 " MailboxExists application. Possible values include:\n"
488 " SUCCESS | FAILED\n\n"
490 " j - Jump to priority n+101 if the mailbox is found.\n";
492 static char *synopsis_vmauthenticate
=
493 "Authenticate with Voicemail passwords";
495 static char *descrip_vmauthenticate
=
496 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
497 "same way as the Authenticate application, but the passwords are taken from\n"
499 " If the mailbox is specified, only that mailbox's password will be considered\n"
500 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
501 "be set with the authenticated mailbox.\n\n"
503 " s - Skip playing the initial prompts.\n";
505 /* Leave a message */
506 static char *app
= "VoiceMail";
508 /* Check mail, control, etc */
509 static char *app2
= "VoiceMailMain";
511 static char *app3
= "MailboxExists";
512 static char *app4
= "VMAuthenticate";
514 static AST_LIST_HEAD_STATIC(users
, ast_vm_user
);
515 static AST_LIST_HEAD_STATIC(zones
, vm_zone
);
516 static int maxsilence
;
518 static int silencethreshold
= 128;
519 static char serveremail
[80];
520 static char mailcmd
[160]; /* Configurable mail cmd */
521 static char externnotify
[160];
522 static struct ast_smdi_interface
*smdi_iface
= NULL
;
523 static char vmfmts
[80];
524 static double volgain
;
525 static int vmminmessage
;
526 static int vmmaxmessage
;
529 static int maxlogins
;
531 static struct ast_flags globalflags
= {0};
533 static int saydurationminfo
;
535 static char dialcontext
[AST_MAX_CONTEXT
];
536 static char callcontext
[AST_MAX_CONTEXT
];
537 static char exitcontext
[AST_MAX_CONTEXT
];
539 static char cidinternalcontexts
[MAX_NUM_CID_CONTEXTS
][64];
542 static char *emailbody
= NULL
;
543 static char *emailsubject
= NULL
;
544 static char *pagerbody
= NULL
;
545 static char *pagersubject
= NULL
;
546 static char fromstring
[100];
547 static char pagerfromstring
[100];
548 static char emailtitle
[100];
549 static char charset
[32] = "ISO-8859-1";
551 static unsigned char adsifdn
[4] = "\x00\x00\x00\x0F";
552 static unsigned char adsisec
[4] = "\x9B\xDB\xF7\xAC";
553 static int adsiver
= 1;
554 static char emaildateformat
[32] = "%A, %B %d, %Y at %r";
557 static void populate_defaults(struct ast_vm_user
*vmu
)
559 ast_copy_flags(vmu
, (&globalflags
), AST_FLAGS_ALL
);
560 if (saydurationminfo
)
561 vmu
->saydurationm
= saydurationminfo
;
562 ast_copy_string(vmu
->callback
, callcontext
, sizeof(vmu
->callback
));
563 ast_copy_string(vmu
->dialout
, dialcontext
, sizeof(vmu
->dialout
));
564 ast_copy_string(vmu
->exit
, exitcontext
, sizeof(vmu
->exit
));
566 vmu
->maxmsg
= maxmsg
;
567 vmu
->volgain
= volgain
;
570 static void apply_option(struct ast_vm_user
*vmu
, const char *var
, const char *value
)
573 if (!strcasecmp(var
, "attach")) {
574 ast_set2_flag(vmu
, ast_true(value
), VM_ATTACH
);
575 } else if (!strcasecmp(var
, "attachfmt")) {
576 ast_copy_string(vmu
->attachfmt
, value
, sizeof(vmu
->attachfmt
));
577 } else if (!strcasecmp(var
, "serveremail")) {
578 ast_copy_string(vmu
->serveremail
, value
, sizeof(vmu
->serveremail
));
579 } else if (!strcasecmp(var
, "language")) {
580 ast_copy_string(vmu
->language
, value
, sizeof(vmu
->language
));
581 } else if (!strcasecmp(var
, "tz")) {
582 ast_copy_string(vmu
->zonetag
, value
, sizeof(vmu
->zonetag
));
584 } else if (!strcasecmp(var
, "imapuser")) {
585 ast_copy_string(vmu
->imapuser
, value
, sizeof(vmu
->imapuser
));
586 } else if (!strcasecmp(var
, "imappassword")) {
587 ast_copy_string(vmu
->imappassword
, value
, sizeof(vmu
->imappassword
));
589 } else if (!strcasecmp(var
, "delete") || !strcasecmp(var
, "deletevoicemail")) {
590 ast_set2_flag(vmu
, ast_true(value
), VM_DELETE
);
591 } else if (!strcasecmp(var
, "saycid")){
592 ast_set2_flag(vmu
, ast_true(value
), VM_SAYCID
);
593 } else if (!strcasecmp(var
,"sendvoicemail")){
594 ast_set2_flag(vmu
, ast_true(value
), VM_SVMAIL
);
595 } else if (!strcasecmp(var
, "review")){
596 ast_set2_flag(vmu
, ast_true(value
), VM_REVIEW
);
597 } else if (!strcasecmp(var
, "tempgreetwarn")){
598 ast_set2_flag(vmu
, ast_true(value
), VM_TEMPGREETWARN
);
599 } else if (!strcasecmp(var
, "operator")){
600 ast_set2_flag(vmu
, ast_true(value
), VM_OPERATOR
);
601 } else if (!strcasecmp(var
, "envelope")){
602 ast_set2_flag(vmu
, ast_true(value
), VM_ENVELOPE
);
603 } else if (!strcasecmp(var
, "sayduration")){
604 ast_set2_flag(vmu
, ast_true(value
), VM_SAYDURATION
);
605 } else if (!strcasecmp(var
, "saydurationm")){
606 if (sscanf(value
, "%d", &x
) == 1) {
607 vmu
->saydurationm
= x
;
609 ast_log(LOG_WARNING
, "Invalid min duration for say duration\n");
611 } else if (!strcasecmp(var
, "forcename")){
612 ast_set2_flag(vmu
, ast_true(value
), VM_FORCENAME
);
613 } else if (!strcasecmp(var
, "forcegreetings")){
614 ast_set2_flag(vmu
, ast_true(value
), VM_FORCEGREET
);
615 } else if (!strcasecmp(var
, "callback")) {
616 ast_copy_string(vmu
->callback
, value
, sizeof(vmu
->callback
));
617 } else if (!strcasecmp(var
, "dialout")) {
618 ast_copy_string(vmu
->dialout
, value
, sizeof(vmu
->dialout
));
619 } else if (!strcasecmp(var
, "exitcontext")) {
620 ast_copy_string(vmu
->exit
, value
, sizeof(vmu
->exit
));
621 } else if (!strcasecmp(var
, "maxmsg")) {
622 vmu
->maxmsg
= atoi(value
);
623 if (vmu
->maxmsg
<= 0) {
624 ast_log(LOG_WARNING
, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value
, MAXMSG
);
625 vmu
->maxmsg
= MAXMSG
;
626 } else if (vmu
->maxmsg
> MAXMSGLIMIT
) {
627 ast_log(LOG_WARNING
, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT
, value
);
628 vmu
->maxmsg
= MAXMSGLIMIT
;
630 } else if (!strcasecmp(var
, "volgain")) {
631 sscanf(value
, "%lf", &vmu
->volgain
);
632 } else if (!strcasecmp(var
, "options")) {
633 apply_options(vmu
, value
);
637 static int change_password_realtime(struct ast_vm_user
*vmu
, const char *password
)
640 if (!ast_strlen_zero(vmu
->uniqueid
)) {
641 res
= ast_update_realtime("voicemail", "uniqueid", vmu
->uniqueid
, "password", password
, NULL
);
643 ast_copy_string(vmu
->password
, password
, sizeof(vmu
->password
));
653 static void apply_options(struct ast_vm_user
*vmu
, const char *options
)
654 { /* Destructively Parse options and apply */
658 stringp
= ast_strdupa(options
);
659 while ((s
= strsep(&stringp
, "|"))) {
661 if ((var
= strsep(&value
, "=")) && value
) {
662 apply_option(vmu
, var
, value
);
667 static void apply_options_full(struct ast_vm_user
*retval
, struct ast_variable
*var
)
669 struct ast_variable
*tmp
;
672 if (!strcasecmp(tmp
->name
, "vmsecret")) {
673 ast_copy_string(retval
->password
, tmp
->value
, sizeof(retval
->password
));
674 } else if (!strcasecmp(tmp
->name
, "secret") || !strcasecmp(tmp
->name
, "password")) { /* don't overwrite vmsecret if it exists */
675 if (ast_strlen_zero(retval
->password
))
676 ast_copy_string(retval
->password
, tmp
->value
, sizeof(retval
->password
));
677 } else if (!strcasecmp(tmp
->name
, "uniqueid")) {
678 ast_copy_string(retval
->uniqueid
, tmp
->value
, sizeof(retval
->uniqueid
));
679 } else if (!strcasecmp(tmp
->name
, "pager")) {
680 ast_copy_string(retval
->pager
, tmp
->value
, sizeof(retval
->pager
));
681 } else if (!strcasecmp(tmp
->name
, "email")) {
682 ast_copy_string(retval
->email
, tmp
->value
, sizeof(retval
->email
));
683 } else if (!strcasecmp(tmp
->name
, "fullname")) {
684 ast_copy_string(retval
->fullname
, tmp
->value
, sizeof(retval
->fullname
));
685 } else if (!strcasecmp(tmp
->name
, "context")) {
686 ast_copy_string(retval
->context
, tmp
->value
, sizeof(retval
->context
));
688 } else if (!strcasecmp(tmp
->name
, "imapuser")) {
689 ast_copy_string(retval
->imapuser
, tmp
->value
, sizeof(retval
->imapuser
));
690 } else if (!strcasecmp(tmp
->name
, "imappassword")) {
691 ast_copy_string(retval
->imappassword
, tmp
->value
, sizeof(retval
->imappassword
));
694 apply_option(retval
, tmp
->name
, tmp
->value
);
699 static struct ast_vm_user
*find_user_realtime(struct ast_vm_user
*ivm
, const char *context
, const char *mailbox
)
701 struct ast_variable
*var
;
702 struct ast_vm_user
*retval
;
704 if ((retval
= (ivm
? ivm
: ast_calloc(1, sizeof(*retval
))))) {
706 ast_set_flag(retval
, VM_ALLOCED
);
708 memset(retval
, 0, sizeof(*retval
));
710 ast_copy_string(retval
->mailbox
, mailbox
, sizeof(retval
->mailbox
));
711 populate_defaults(retval
);
712 if (!context
&& ast_test_flag((&globalflags
), VM_SEARCH
))
713 var
= ast_load_realtime("voicemail", "mailbox", mailbox
, NULL
);
715 var
= ast_load_realtime("voicemail", "mailbox", mailbox
, "context", context
, NULL
);
717 apply_options_full(retval
, var
);
718 ast_variables_destroy(var
);
728 static struct ast_vm_user
*find_user(struct ast_vm_user
*ivm
, const char *context
, const char *mailbox
)
730 /* This function could be made to generate one from a database, too */
731 struct ast_vm_user
*vmu
=NULL
, *cur
;
732 AST_LIST_LOCK(&users
);
734 if (!context
&& !ast_test_flag((&globalflags
), VM_SEARCH
))
737 AST_LIST_TRAVERSE(&users
, cur
, list
) {
738 if (ast_test_flag((&globalflags
), VM_SEARCH
) && !strcasecmp(mailbox
, cur
->mailbox
))
740 if (context
&& (!strcasecmp(context
, cur
->context
)) && (!strcasecmp(mailbox
, cur
->mailbox
)))
744 /* Make a copy, so that on a reload, we have no race */
745 if ((vmu
= (ivm
? ivm
: ast_malloc(sizeof(*vmu
))))) {
746 memcpy(vmu
, cur
, sizeof(*vmu
));
747 ast_set2_flag(vmu
, !ivm
, VM_ALLOCED
);
748 AST_LIST_NEXT(vmu
, list
) = NULL
;
751 vmu
= find_user_realtime(ivm
, context
, mailbox
);
752 AST_LIST_UNLOCK(&users
);
756 static int reset_user_pw(const char *context
, const char *mailbox
, const char *newpass
)
758 /* This function could be made to generate one from a database, too */
759 struct ast_vm_user
*cur
;
761 AST_LIST_LOCK(&users
);
762 AST_LIST_TRAVERSE(&users
, cur
, list
) {
763 if ((!context
|| !strcasecmp(context
, cur
->context
)) &&
764 (!strcasecmp(mailbox
, cur
->mailbox
)))
768 ast_copy_string(cur
->password
, newpass
, sizeof(cur
->password
));
771 AST_LIST_UNLOCK(&users
);
775 static void vm_change_password(struct ast_vm_user
*vmu
, const char *newpassword
)
777 struct ast_config
*cfg
=NULL
;
778 struct ast_variable
*var
=NULL
;
779 struct ast_category
*cat
=NULL
;
780 char *category
=NULL
, *value
=NULL
, *new=NULL
;
781 const char *tmp
=NULL
;
783 if (!change_password_realtime(vmu
, newpassword
))
786 /* check voicemail.conf */
787 if ((cfg
= ast_config_load_with_comments(VOICEMAIL_CONFIG
))) {
788 while ((category
= ast_category_browse(cfg
, category
))) {
789 if (!strcasecmp(category
, vmu
->context
)) {
790 tmp
= ast_variable_retrieve(cfg
, category
, vmu
->mailbox
);
792 ast_log(LOG_WARNING
, "We could not find the mailbox.\n");
795 value
= strstr(tmp
,",");
797 ast_log(LOG_WARNING
, "variable has bad format.\n");
800 new = alloca((strlen(value
)+strlen(newpassword
)+1));
801 sprintf(new,"%s%s", newpassword
, value
);
802 if (!(cat
= ast_category_get(cfg
, category
))) {
803 ast_log(LOG_WARNING
, "Failed to get category structure.\n");
806 ast_variable_update(cat
, vmu
->mailbox
, new, NULL
, 0);
809 /* save the results */
810 reset_user_pw(vmu
->context
, vmu
->mailbox
, newpassword
);
811 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
812 config_text_file_save(VOICEMAIL_CONFIG
, cfg
, "AppVoicemail");
816 /* check users.conf and update the password stored for the mailbox*/
817 /* if no vmsecret entry exists create one. */
818 if ((cfg
= ast_config_load_with_comments("users.conf"))) {
819 if (option_debug
> 3)
820 ast_log(LOG_DEBUG
, "we are looking for %s\n", vmu
->mailbox
);
821 while ((category
= ast_category_browse(cfg
, category
))) {
822 if (option_debug
> 3)
823 ast_log(LOG_DEBUG
, "users.conf: %s\n", category
);
824 if (!strcasecmp(category
, vmu
->mailbox
)) {
825 if (!(tmp
= ast_variable_retrieve(cfg
, category
, "vmsecret"))) {
826 if (option_debug
> 3)
827 ast_log(LOG_DEBUG
, "looks like we need to make vmsecret!\n");
828 var
= ast_variable_new("vmsecret", newpassword
);
830 new = alloca(strlen(newpassword
)+1);
831 sprintf(new, "%s", newpassword
);
832 if (!(cat
= ast_category_get(cfg
, category
))) {
833 if (option_debug
> 3)
834 ast_log(LOG_DEBUG
, "failed to get category!\n");
838 ast_variable_update(cat
, "vmsecret", new, NULL
, 0);
840 ast_variable_append(cat
, var
);
843 /* save the results and clean things up */
844 reset_user_pw(vmu
->context
, vmu
->mailbox
, newpassword
);
845 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
846 config_text_file_save("users.conf", cfg
, "AppVoicemail");
850 static void vm_change_password_shell(struct ast_vm_user
*vmu
, char *newpassword
)
853 snprintf(buf
,255,"%s %s %s %s",ext_pass_cmd
,vmu
->context
,vmu
->mailbox
,newpassword
);
854 if (!ast_safe_system(buf
))
855 ast_copy_string(vmu
->password
, newpassword
, sizeof(vmu
->password
));
858 static int make_dir(char *dest
, int len
, const char *context
, const char *ext
, const char *folder
)
860 return snprintf(dest
, len
, "%s%s/%s/%s", VM_SPOOL_DIR
, context
, ext
, folder
);
864 static int make_gsm_file(char *dest
, size_t len
, char *imapuser
, char *dir
, int num
)
866 if (mkdir(dir
, 01777) && (errno
!= EEXIST
)) {
867 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dir
, strerror(errno
));
868 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
870 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
873 static void vm_imap_delete(int msgnum
, struct vm_state
*vms
)
875 unsigned long messageNum
= 0;
878 /* find real message number based on msgnum */
879 /* this may be an index into vms->msgArray based on the msgnum. */
881 messageNum
= vms
->msgArray
[msgnum
];
882 if (messageNum
== 0) {
883 ast_log(LOG_WARNING
, "msgnum %d, mailbox message %lu is zero.\n",msgnum
,messageNum
);
887 ast_log(LOG_DEBUG
, "deleting msgnum %d, which is mailbox message %lu\n",msgnum
,messageNum
);
889 snprintf (arg
, sizeof(arg
), "%lu",messageNum
);
890 mail_setflag (vms
->mailstream
,arg
,"\\DELETED");
894 static int make_file(char *dest
, int len
, char *dir
, int num
)
896 return snprintf(dest
, len
, "%s/msg%04d", dir
, num
);
899 /*! \brief basically mkdir -p $dest/$context/$ext/$folder
900 * \param dest String. base directory.
901 * \param len Length of dest.
902 * \param context String. Ignored if is null or empty string.
903 * \param ext String. Ignored if is null or empty string.
904 * \param folder String. Ignored if is null or empty string.
905 * \return -1 on failure, 0 on success.
907 static int create_dirpath(char *dest
, int len
, const char *context
, const char *ext
, const char *folder
)
909 mode_t mode
= VOICEMAIL_DIR_MODE
;
911 if (!ast_strlen_zero(context
)) {
912 make_dir(dest
, len
, context
, "", "");
913 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
914 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
918 if (!ast_strlen_zero(ext
)) {
919 make_dir(dest
, len
, context
, ext
, "");
920 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
921 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
925 if (!ast_strlen_zero(folder
)) {
926 make_dir(dest
, len
, context
, ext
, folder
);
927 if (mkdir(dest
, mode
) && errno
!= EEXIST
) {
928 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", dest
, strerror(errno
));
935 /* only return failure if ast_lock_path returns 'timeout',
936 not if the path does not exist or any other reason
938 static int vm_lock_path(const char *path
)
940 switch (ast_lock_path(path
)) {
941 case AST_LOCK_TIMEOUT
:
950 struct generic_prepare_struct
{
956 static SQLHSTMT
generic_prepare(struct odbc_obj
*obj
, void *data
)
958 struct generic_prepare_struct
*gps
= data
;
962 res
= SQLAllocHandle(SQL_HANDLE_STMT
, obj
->con
, &stmt
);
963 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
964 ast_log(LOG_WARNING
, "SQL Alloc Handle failed!\n");
967 res
= SQLPrepare(stmt
, (unsigned char *)gps
->sql
, SQL_NTS
);
968 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
969 ast_log(LOG_WARNING
, "SQL Prepare failed![%s]\n", gps
->sql
);
970 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
973 for (i
= 0; i
< gps
->argc
; i
++)
974 SQLBindParameter(stmt
, i
+ 1, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(gps
->argv
[i
]), 0, gps
->argv
[i
], 0, NULL
);
979 static int retrieve_file(char *dir
, int msgnum
)
985 void *fdm
= MAP_FAILED
;
986 SQLSMALLINT colcount
=0;
993 SQLSMALLINT datatype
;
994 SQLSMALLINT decimaldigits
;
995 SQLSMALLINT nullable
;
1001 char full_fn
[PATH_MAX
];
1003 char *argv
[] = { dir
, msgnums
};
1004 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1006 struct odbc_obj
*obj
;
1007 obj
= ast_odbc_request_obj(odbc_database
, 0);
1009 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
1010 c
= strchr(fmt
, '|');
1013 if (!strcasecmp(fmt
, "wav49"))
1015 snprintf(msgnums
, sizeof(msgnums
),"%d", msgnum
);
1017 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1019 ast_copy_string(fn
, dir
, sizeof(fn
));
1020 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1022 if (!(f
= fopen(full_fn
, "w+"))) {
1023 ast_log(LOG_WARNING
, "Failed to open/create '%s'\n", full_fn
);
1027 snprintf(full_fn
, sizeof(full_fn
), "%s.%s", fn
, fmt
);
1028 snprintf(sql
, sizeof(sql
), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1029 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1031 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1032 ast_odbc_release_obj(obj
);
1035 res
= SQLFetch(stmt
);
1036 if (res
== SQL_NO_DATA
) {
1037 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1038 ast_odbc_release_obj(obj
);
1041 else if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1042 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1043 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1044 ast_odbc_release_obj(obj
);
1047 fd
= open(full_fn
, O_RDWR
| O_CREAT
| O_TRUNC
, 0770);
1049 ast_log(LOG_WARNING
, "Failed to write '%s': %s\n", full_fn
, strerror(errno
));
1050 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1051 ast_odbc_release_obj(obj
);
1054 res
= SQLNumResultCols(stmt
, &colcount
);
1055 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1056 ast_log(LOG_WARNING
, "SQL Column Count error!\n[%s]\n\n", sql
);
1057 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1058 ast_odbc_release_obj(obj
);
1062 fprintf(f
, "[message]\n");
1063 for (x
=0;x
<colcount
;x
++) {
1065 collen
= sizeof(coltitle
);
1066 res
= SQLDescribeCol(stmt
, x
+ 1, (unsigned char *)coltitle
, sizeof(coltitle
), &collen
,
1067 &datatype
, &colsize
, &decimaldigits
, &nullable
);
1068 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1069 ast_log(LOG_WARNING
, "SQL Describe Column error!\n[%s]\n\n", sql
);
1070 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1071 ast_odbc_release_obj(obj
);
1074 if (!strcasecmp(coltitle
, "recording")) {
1076 res
= SQLGetData(stmt
, x
+ 1, SQL_BINARY
, rowdata
, 0, &colsize2
);
1080 lseek(fd
, fdlen
- 1, SEEK_SET
);
1081 if (write(fd
, tmp
, 1) != 1) {
1086 /* Read out in small chunks */
1087 for (offset
= 0; offset
< colsize2
; offset
+= CHUNKSIZE
) {
1088 if ((fdm
= mmap(NULL
, CHUNKSIZE
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, offset
)) == MAP_FAILED
) {
1089 ast_log(LOG_WARNING
, "Could not mmap the output file: %s (%d)\n", strerror(errno
), errno
);
1090 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1091 ast_odbc_release_obj(obj
);
1094 res
= SQLGetData(stmt
, x
+ 1, SQL_BINARY
, fdm
, CHUNKSIZE
, NULL
);
1095 munmap(fdm
, CHUNKSIZE
);
1096 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1097 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1099 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1100 ast_odbc_release_obj(obj
);
1105 truncate(full_fn
, fdlen
);
1108 res
= SQLGetData(stmt
, x
+ 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1109 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1110 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1111 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1112 ast_odbc_release_obj(obj
);
1115 if (strcasecmp(coltitle
, "msgnum") && strcasecmp(coltitle
, "dir") && f
)
1116 fprintf(f
, "%s=%s\n", coltitle
, rowdata
);
1119 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1120 ast_odbc_release_obj(obj
);
1122 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1131 static int remove_file(char *dir
, int msgnum
)
1134 char full_fn
[PATH_MAX
];
1138 snprintf(msgnums
, sizeof(msgnums
), "%d", msgnum
);
1139 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1141 ast_copy_string(fn
, dir
, sizeof(fn
));
1142 ast_filedelete(fn
, NULL
);
1143 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1148 static int last_message_index(struct ast_vm_user
*vmu
, char *dir
)
1155 char *argv
[] = { dir
};
1156 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 1, .argv
= argv
};
1158 struct odbc_obj
*obj
;
1159 obj
= ast_odbc_request_obj(odbc_database
, 0);
1161 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table
);
1162 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1164 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1165 ast_odbc_release_obj(obj
);
1168 res
= SQLFetch(stmt
);
1169 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1170 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1171 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1172 ast_odbc_release_obj(obj
);
1175 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1176 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1177 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1178 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1179 ast_odbc_release_obj(obj
);
1182 if (sscanf(rowdata
, "%d", &x
) != 1)
1183 ast_log(LOG_WARNING
, "Failed to read message count!\n");
1184 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1185 ast_odbc_release_obj(obj
);
1187 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1192 static int message_exists(char *dir
, int msgnum
)
1200 char *argv
[] = { dir
, msgnums
};
1201 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1203 struct odbc_obj
*obj
;
1204 obj
= ast_odbc_request_obj(odbc_database
, 0);
1206 snprintf(msgnums
, sizeof(msgnums
), "%d", msgnum
);
1207 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1208 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1210 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1211 ast_odbc_release_obj(obj
);
1214 res
= SQLFetch(stmt
);
1215 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1216 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
1217 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1218 ast_odbc_release_obj(obj
);
1221 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
1222 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1223 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
1224 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1225 ast_odbc_release_obj(obj
);
1228 if (sscanf(rowdata
, "%d", &x
) != 1)
1229 ast_log(LOG_WARNING
, "Failed to read message count!\n");
1230 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1231 ast_odbc_release_obj(obj
);
1233 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1238 static int count_messages(struct ast_vm_user
*vmu
, char *dir
)
1240 return last_message_index(vmu
, dir
) + 1;
1243 static void delete_file(char *sdir
, int smsg
)
1248 char *argv
[] = { sdir
, msgnums
};
1249 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 2, .argv
= argv
};
1251 struct odbc_obj
*obj
;
1252 obj
= ast_odbc_request_obj(odbc_database
, 0);
1254 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1255 snprintf(sql
, sizeof(sql
), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table
);
1256 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1258 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1260 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1261 ast_odbc_release_obj(obj
);
1263 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1267 static void copy_file(char *sdir
, int smsg
, char *ddir
, int dmsg
, char *dmailboxuser
, char *dmailboxcontext
)
1273 struct odbc_obj
*obj
;
1274 char *argv
[] = { ddir
, msgnumd
, dmailboxuser
, dmailboxcontext
, sdir
, msgnums
};
1275 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 6, .argv
= argv
};
1277 delete_file(ddir
, dmsg
);
1278 obj
= ast_odbc_request_obj(odbc_database
, 0);
1280 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1281 snprintf(msgnumd
, sizeof(msgnumd
), "%d", dmsg
);
1282 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
);
1283 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1285 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql
);
1287 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1288 ast_odbc_release_obj(obj
);
1290 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1294 static int store_file(char *dir
, char *mailboxuser
, char *mailboxcontext
, int msgnum
)
1299 void *fdm
= MAP_FAILED
;
1306 char full_fn
[PATH_MAX
];
1309 const char *context
="", *macrocontext
="", *callerid
="", *origtime
="", *duration
="";
1310 const char *category
= "";
1311 struct ast_config
*cfg
=NULL
;
1312 struct odbc_obj
*obj
;
1314 delete_file(dir
, msgnum
);
1315 obj
= ast_odbc_request_obj(odbc_database
, 0);
1317 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
1318 c
= strchr(fmt
, '|');
1321 if (!strcasecmp(fmt
, "wav49"))
1323 snprintf(msgnums
, sizeof(msgnums
),"%d", msgnum
);
1325 make_file(fn
, sizeof(fn
), dir
, msgnum
);
1327 ast_copy_string(fn
, dir
, sizeof(fn
));
1328 snprintf(full_fn
, sizeof(full_fn
), "%s.txt", fn
);
1329 cfg
= ast_config_load(full_fn
);
1330 snprintf(full_fn
, sizeof(full_fn
), "%s.%s", fn
, fmt
);
1331 fd
= open(full_fn
, O_RDWR
);
1333 ast_log(LOG_WARNING
, "Open of sound file '%s' failed: %s\n", full_fn
, strerror(errno
));
1334 ast_odbc_release_obj(obj
);
1338 context
= ast_variable_retrieve(cfg
, "message", "context");
1339 if (!context
) context
= "";
1340 macrocontext
= ast_variable_retrieve(cfg
, "message", "macrocontext");
1341 if (!macrocontext
) macrocontext
= "";
1342 callerid
= ast_variable_retrieve(cfg
, "message", "callerid");
1343 if (!callerid
) callerid
= "";
1344 origtime
= ast_variable_retrieve(cfg
, "message", "origtime");
1345 if (!origtime
) origtime
= "";
1346 duration
= ast_variable_retrieve(cfg
, "message", "duration");
1347 if (!duration
) duration
= "";
1348 category
= ast_variable_retrieve(cfg
, "message", "category");
1349 if (!category
) category
= "";
1351 fdlen
= lseek(fd
, 0, SEEK_END
);
1352 lseek(fd
, 0, SEEK_SET
);
1353 printf("Length is %zd\n", fdlen
);
1354 fdm
= mmap(NULL
, fdlen
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,fd
, 0);
1355 if (fdm
== MAP_FAILED
) {
1356 ast_log(LOG_WARNING
, "Memory map failed!\n");
1357 ast_odbc_release_obj(obj
);
1360 res
= SQLAllocHandle(SQL_HANDLE_STMT
, obj
->con
, &stmt
);
1361 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1362 ast_log(LOG_WARNING
, "SQL Alloc Handle failed!\n");
1363 ast_odbc_release_obj(obj
);
1366 if (!ast_strlen_zero(category
))
1367 snprintf(sql
, sizeof(sql
), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table
);
1369 snprintf(sql
, sizeof(sql
), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)",odbc_table
);
1370 res
= SQLPrepare(stmt
, (unsigned char *)sql
, SQL_NTS
);
1371 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1372 ast_log(LOG_WARNING
, "SQL Prepare failed![%s]\n", sql
);
1373 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1374 ast_odbc_release_obj(obj
);
1377 len
= fdlen
; /* SQL_LEN_DATA_AT_EXEC(fdlen); */
1378 SQLBindParameter(stmt
, 1, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(dir
), 0, (void *)dir
, 0, NULL
);
1379 SQLBindParameter(stmt
, 2, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(msgnums
), 0, (void *)msgnums
, 0, NULL
);
1380 SQLBindParameter(stmt
, 3, SQL_PARAM_INPUT
, SQL_C_BINARY
, SQL_LONGVARBINARY
, fdlen
, 0, (void *)fdm
, fdlen
, &len
);
1381 SQLBindParameter(stmt
, 4, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(context
), 0, (void *)context
, 0, NULL
);
1382 SQLBindParameter(stmt
, 5, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(macrocontext
), 0, (void *)macrocontext
, 0, NULL
);
1383 SQLBindParameter(stmt
, 6, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(callerid
), 0, (void *)callerid
, 0, NULL
);
1384 SQLBindParameter(stmt
, 7, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(origtime
), 0, (void *)origtime
, 0, NULL
);
1385 SQLBindParameter(stmt
, 8, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(duration
), 0, (void *)duration
, 0, NULL
);
1386 SQLBindParameter(stmt
, 9, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(mailboxuser
), 0, (void *)mailboxuser
, 0, NULL
);
1387 SQLBindParameter(stmt
, 10, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(mailboxcontext
), 0, (void *)mailboxcontext
, 0, NULL
);
1388 if (!ast_strlen_zero(category
))
1389 SQLBindParameter(stmt
, 11, SQL_PARAM_INPUT
, SQL_C_CHAR
, SQL_CHAR
, strlen(category
), 0, (void *)category
, 0, NULL
);
1390 res
= ast_odbc_smart_execute(obj
, stmt
);
1391 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
1392 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1393 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1394 ast_odbc_release_obj(obj
);
1397 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
1398 ast_odbc_release_obj(obj
);
1400 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1403 ast_config_destroy(cfg
);
1404 if (fdm
!= MAP_FAILED
)
1411 static void rename_file(char *sdir
, int smsg
, char *mailboxuser
, char *mailboxcontext
, char *ddir
, int dmsg
)
1417 struct odbc_obj
*obj
;
1418 char *argv
[] = { ddir
, msgnumd
, mailboxuser
, mailboxcontext
, sdir
, msgnums
};
1419 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 6, .argv
= argv
};
1421 delete_file(ddir
, dmsg
);
1422 obj
= ast_odbc_request_obj(odbc_database
, 0);
1424 snprintf(msgnums
, sizeof(msgnums
), "%d", smsg
);
1425 snprintf(msgnumd
, sizeof(msgnumd
), "%d", dmsg
);
1426 snprintf(sql
, sizeof(sql
), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table
);
1427 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
1429 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
1431 SQLFreeHandle(SQL_HANDLE_STMT
, stmt
);
1432 ast_odbc_release_obj(obj
);
1434 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
1439 #ifndef IMAP_STORAGE
1440 static int count_messages(struct ast_vm_user
*vmu
, char *dir
)
1442 /* Find all .txt files - even if they are not in sequence from 0000 */
1446 struct dirent
*vment
= NULL
;
1448 if (vm_lock_path(dir
))
1449 return ERROR_LOCK_PATH
;
1451 if ((vmdir
= opendir(dir
))) {
1452 while ((vment
= readdir(vmdir
))) {
1453 if (strlen(vment
->d_name
) > 7 && !strncmp(vment
->d_name
+ 7, ".txt", 4))
1458 ast_unlock_path(dir
);
1463 static void rename_file(char *sfn
, char *dfn
)
1465 char stxt
[PATH_MAX
];
1466 char dtxt
[PATH_MAX
];
1467 ast_filerename(sfn
,dfn
,NULL
);
1468 snprintf(stxt
, sizeof(stxt
), "%s.txt", sfn
);
1469 snprintf(dtxt
, sizeof(dtxt
), "%s.txt", dfn
);
1473 static int copy(char *infile
, char *outfile
)
1481 #ifdef HARDLINK_WHEN_POSSIBLE
1482 /* Hard link if possible; saves disk space & is faster */
1483 if (link(infile
, outfile
)) {
1485 if ((ifd
= open(infile
, O_RDONLY
)) < 0) {
1486 ast_log(LOG_WARNING
, "Unable to open %s in read-only mode\n", infile
);
1489 if ((ofd
= open(outfile
, O_WRONLY
| O_TRUNC
| O_CREAT
, VOICEMAIL_FILE_MODE
)) < 0) {
1490 ast_log(LOG_WARNING
, "Unable to open %s in write-only mode\n", outfile
);
1495 len
= read(ifd
, buf
, sizeof(buf
));
1497 ast_log(LOG_WARNING
, "Read failed on %s: %s\n", infile
, strerror(errno
));
1503 res
= write(ofd
, buf
, len
);
1504 if (errno
== ENOMEM
|| errno
== ENOSPC
|| res
!= len
) {
1505 ast_log(LOG_WARNING
, "Write failed on %s (%d of %d): %s\n", outfile
, res
, len
, strerror(errno
));
1515 #ifdef HARDLINK_WHEN_POSSIBLE
1517 /* Hard link succeeded */
1523 static void copy_file(char *frompath
, char *topath
)
1525 char frompath2
[PATH_MAX
], topath2
[PATH_MAX
];
1526 ast_filecopy(frompath
, topath
, NULL
);
1527 snprintf(frompath2
, sizeof(frompath2
), "%s.txt", frompath
);
1528 snprintf(topath2
, sizeof(topath2
), "%s.txt", topath
);
1529 copy(frompath2
, topath2
);
1533 * A negative return value indicates an error.
1535 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
1536 static int last_message_index(struct ast_vm_user
*vmu
, char *dir
)
1541 if (vm_lock_path(dir
))
1542 return ERROR_LOCK_PATH
;
1544 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
1545 make_file(fn
, sizeof(fn
), dir
, x
);
1546 if (ast_fileexists(fn
, NULL
, NULL
) < 1)
1549 ast_unlock_path(dir
);
1556 #ifndef ODBC_STORAGE
1557 static int vm_delete(char *file
)
1562 txtsize
= (strlen(file
) + 5)*sizeof(char);
1563 txt
= alloca(txtsize
);
1564 /* Sprintf here would safe because we alloca'd exactly the right length,
1565 * but trying to eliminate all sprintf's anyhow
1567 snprintf(txt
, txtsize
, "%s.txt", file
);
1569 return ast_filedelete(file
, NULL
);
1573 static int inbuf(struct baseio
*bio
, FILE *fi
)
1580 if ((l
= fread(bio
->iobuf
,1,BASEMAXINLINE
,fi
)) <= 0) {
1594 static int inchar(struct baseio
*bio
, FILE *fi
)
1596 if (bio
->iocp
>=bio
->iolen
) {
1597 if (!inbuf(bio
, fi
))
1601 return bio
->iobuf
[bio
->iocp
++];
1604 static int ochar(struct baseio
*bio
, int c
, FILE *so
)
1606 if (bio
->linelength
>=BASELINELEN
) {
1607 if (fputs(eol
,so
)==EOF
)
1613 if (putc(((unsigned char)c
),so
)==EOF
)
1621 static int base_encode(char *filename
, FILE *so
)
1623 unsigned char dtable
[BASEMAXINLINE
];
1628 memset(&bio
, 0, sizeof(bio
));
1629 bio
.iocp
= BASEMAXINLINE
;
1631 if (!(fi
= fopen(filename
, "rb"))) {
1632 ast_log(LOG_WARNING
, "Failed to open file: %s: %s\n", filename
, strerror(errno
));
1636 for (i
= 0;i
<9;i
++) {
1639 dtable
[26+i
]= 'a'+i
;
1640 dtable
[26+i
+9]= 'j'+i
;
1642 for (i
= 0;i
<8;i
++) {
1643 dtable
[i
+18]= 'S'+i
;
1644 dtable
[26+i
+18]= 's'+i
;
1646 for (i
= 0;i
<10;i
++) {
1647 dtable
[52+i
]= '0'+i
;
1653 unsigned char igroup
[3],ogroup
[4];
1656 igroup
[0]= igroup
[1]= igroup
[2]= 0;
1658 for (n
= 0;n
<3;n
++) {
1659 if ((c
= inchar(&bio
, fi
)) == EOF
) {
1664 igroup
[n
]= (unsigned char)c
;
1668 ogroup
[0]= dtable
[igroup
[0]>>2];
1669 ogroup
[1]= dtable
[((igroup
[0]&3)<<4)|(igroup
[1]>>4)];
1670 ogroup
[2]= dtable
[((igroup
[1]&0xF)<<2)|(igroup
[2]>>6)];
1671 ogroup
[3]= dtable
[igroup
[2]&0x3F];
1681 ochar(&bio
, ogroup
[i
], so
);
1685 if (fputs(eol
,so
)==EOF
)
1693 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
)
1696 /* Prepare variables for substition in email body and subject */
1697 pbx_builtin_setvar_helper(ast
, "VM_NAME", vmu
->fullname
);
1698 pbx_builtin_setvar_helper(ast
, "VM_DUR", dur
);
1699 snprintf(passdata
, passdatasize
, "%d", msgnum
);
1700 pbx_builtin_setvar_helper(ast
, "VM_MSGNUM", passdata
);
1701 pbx_builtin_setvar_helper(ast
, "VM_CONTEXT", context
);
1702 pbx_builtin_setvar_helper(ast
, "VM_MAILBOX", mailbox
);
1703 pbx_builtin_setvar_helper(ast
, "VM_CALLERID", ast_callerid_merge(callerid
, sizeof(callerid
), cidname
, cidnum
, "Unknown Caller"));
1704 pbx_builtin_setvar_helper(ast
, "VM_CIDNAME", (cidname
? cidname
: "an unknown caller"));
1705 pbx_builtin_setvar_helper(ast
, "VM_CIDNUM", (cidnum
? cidnum
: "an unknown caller"));
1706 pbx_builtin_setvar_helper(ast
, "VM_DATE", date
);
1707 pbx_builtin_setvar_helper(ast
, "VM_CATEGORY", category
? ast_strdupa(category
) : "no category");
1710 static char *quote(const char *from
, char *to
, size_t len
)
1714 for (; ptr
< to
+ len
- 1; from
++) {
1717 else if (*from
== '\0')
1721 if (ptr
< to
+ len
- 1)
1727 * fill in *tm for current time according to the proper timezone, if any.
1728 * Return tm so it can be used as a function argument.
1730 static const struct tm
*vmu_tm(const struct ast_vm_user
*vmu
, struct tm
*tm
)
1732 const struct vm_zone
*z
= NULL
;
1733 time_t t
= time(NULL
);
1735 /* Does this user have a timezone specified? */
1736 if (!ast_strlen_zero(vmu
->zonetag
)) {
1737 /* Find the zone in the list */
1738 AST_LIST_LOCK(&zones
);
1739 AST_LIST_TRAVERSE(&zones
, z
, list
) {
1740 if (!strcmp(z
->name
, vmu
->zonetag
))
1743 AST_LIST_UNLOCK(&zones
);
1745 ast_localtime(&t
, tm
, z
? z
->timezone
: NULL
);
1749 /* same as mkstemp, but return a FILE * */
1750 static FILE *vm_mkftemp(char *template)
1753 int pfd
= mkstemp(template);
1754 chmod(template, VOICEMAIL_FILE_MODE
& ~my_umask
);
1756 p
= fdopen(pfd
, "w+");
1765 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
)
1768 char host
[MAXHOSTNAMELEN
] = "";
1776 size_t len_passdata
;
1783 gethostname(host
, sizeof(host
) - 1);
1784 if (strchr(srcemail
, '@'))
1785 ast_copy_string(who
, srcemail
, sizeof(who
));
1787 snprintf(who
, sizeof(who
), "%s@%s", srcemail
, host
);
1789 snprintf(dur
, sizeof(dur
), "%d:%02d", duration
/ 60, duration
% 60);
1790 strftime(date
, sizeof(date
), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu
, &tm
));
1791 fprintf(p
, "Date: %s" ENDL
, date
);
1793 /* Set date format for voicemail mail */
1794 strftime(date
, sizeof(date
), emaildateformat
, &tm
);
1797 struct ast_channel
*ast
;
1798 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1800 int vmlen
= strlen(fromstring
)*3 + 200;
1801 if ((passdata
= alloca(vmlen
))) {
1802 memset(passdata
, 0, vmlen
);
1803 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1804 pbx_substitute_variables_helper(ast
, fromstring
, passdata
, vmlen
);
1805 len_passdata
= strlen(passdata
) * 2 + 3;
1806 passdata2
= alloca(len_passdata
);
1807 fprintf(p
, "From: %s <%s>" ENDL
, quote(passdata
, passdata2
, len_passdata
), who
);
1809 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1810 ast_channel_free(ast
);
1812 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1814 fprintf(p
, "From: Asterisk PBX <%s>" ENDL
, who
);
1815 len_passdata
= strlen(vmu
->fullname
) * 2 + 3;
1816 passdata2
= alloca(len_passdata
);
1817 fprintf(p
, "To: %s <%s>" ENDL
, quote(vmu
->fullname
, passdata2
, len_passdata
), vmu
->email
);
1819 struct ast_channel
*ast
;
1820 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1822 int vmlen
= strlen(emailsubject
)*3 + 200;
1823 if ((passdata
= alloca(vmlen
))) {
1824 memset(passdata
, 0, vmlen
);
1825 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1826 pbx_substitute_variables_helper(ast
, emailsubject
, passdata
, vmlen
);
1827 fprintf(p
, "Subject: %s" ENDL
, passdata
);
1829 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1830 ast_channel_free(ast
);
1832 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1833 } else if (*emailtitle
) {
1834 fprintf(p
, emailtitle
, msgnum
+ 1, mailbox
) ;
1836 } else if (ast_test_flag((&globalflags
), VM_PBXSKIP
))
1837 fprintf(p
, "Subject: New message %d in mailbox %s" ENDL
, msgnum
+ 1, mailbox
);
1839 fprintf(p
, "Subject: [PBX]: New message %d in mailbox %s" ENDL
, msgnum
+ 1, mailbox
);
1840 fprintf(p
, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL
, msgnum
+ 1, (unsigned int)ast_random(), mailbox
, (int)getpid(), host
);
1842 /* additional information needed for IMAP searching */
1843 fprintf(p
, "X-Asterisk-VM-Message-Num: %d" ENDL
, msgnum
+ 1);
1844 /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
1845 fprintf(p
, "X-Asterisk-VM-Server-Name: %s" ENDL
, fromstring
);
1846 fprintf(p
, "X-Asterisk-VM-Context: %s" ENDL
, context
);
1847 fprintf(p
, "X-Asterisk-VM-Extension: %s" ENDL
, mailbox
);
1848 fprintf(p
, "X-Asterisk-VM-Priority: %d" ENDL
, chan
->priority
);
1849 fprintf(p
, "X-Asterisk-VM-Caller-channel: %s" ENDL
, chan
->name
);
1850 fprintf(p
, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL
, cidnum
);
1851 fprintf(p
, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL
, cidname
);
1852 fprintf(p
, "X-Asterisk-VM-Duration: %d" ENDL
, duration
);
1853 if (!ast_strlen_zero(category
))
1854 fprintf(p
, "X-Asterisk-VM-Category: %s" ENDL
, category
);
1855 fprintf(p
, "X-Asterisk-VM-Orig-date: %s" ENDL
, date
);
1856 fprintf(p
, "X-Asterisk-VM-Orig-time: %ld" ENDL
, (long)time(NULL
));
1858 if (!ast_strlen_zero(cidnum
))
1859 fprintf(p
, "X-Asterisk-CallerID: %s" ENDL
, cidnum
);
1860 if (!ast_strlen_zero(cidname
))
1861 fprintf(p
, "X-Asterisk-CallerIDName: %s" ENDL
, cidname
);
1862 fprintf(p
, "MIME-Version: 1.0" ENDL
);
1863 if (attach_user_voicemail
) {
1864 /* Something unique. */
1865 snprintf(bound
, sizeof(bound
), "----voicemail_%d%s%d%d", msgnum
+ 1, mailbox
, (int)getpid(), (unsigned int)ast_random());
1867 fprintf(p
, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL
, bound
);
1868 fprintf(p
, ENDL ENDL
"This is a multi-part message in MIME format." ENDL ENDL
);
1869 fprintf(p
, "--%s" ENDL
, bound
);
1871 fprintf(p
, "Content-Type: text/plain; charset=%s" ENDL
"Content-Transfer-Encoding: 8bit" ENDL ENDL
, charset
);
1873 struct ast_channel
*ast
;
1874 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1876 int vmlen
= strlen(emailbody
)*3 + 200;
1877 if ((passdata
= alloca(vmlen
))) {
1878 memset(passdata
, 0, vmlen
);
1879 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1880 pbx_substitute_variables_helper(ast
, emailbody
, passdata
, vmlen
);
1881 fprintf(p
, "%s" ENDL
, passdata
);
1883 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1884 ast_channel_free(ast
);
1886 ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
1888 fprintf(p
, "Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
1890 "in mailbox %s from %s, on %s so you might" ENDL
1891 "want to check it when you get a chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk" ENDL ENDL
, vmu
->fullname
,
1892 dur
, msgnum
+ 1, mailbox
, (cidname
? cidname
: (cidnum
? cidnum
: "an unknown caller")), date
);
1894 if (attach_user_voicemail
) {
1895 /* Eww. We want formats to tell us their own MIME type */
1896 char *ctype
= (!strcasecmp(format
, "ogg")) ? "application/" : "audio/x-";
1897 char tmpdir
[256], newtmp
[256];
1900 if (vmu
->volgain
< -.001 || vmu
->volgain
> .001) {
1901 create_dirpath(tmpdir
, sizeof(tmpdir
), vmu
->context
, vmu
->mailbox
, "tmp");
1902 snprintf(newtmp
, sizeof(newtmp
), "%s/XXXXXX", tmpdir
);
1903 tmpfd
= mkstemp(newtmp
);
1904 chmod(newtmp
, VOICEMAIL_FILE_MODE
& ~my_umask
);
1905 if (option_debug
> 2)
1906 ast_log(LOG_DEBUG
, "newtmp: %s\n", newtmp
);
1908 snprintf(tmpcmd
, sizeof(tmpcmd
), "sox -v %.4f %s.%s %s.%s", vmu
->volgain
, attach
, format
, newtmp
, format
);
1909 ast_safe_system(tmpcmd
);
1911 if (option_debug
> 2)
1912 ast_log(LOG_DEBUG
, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach
, format
, vmu
->volgain
, mailbox
);
1915 fprintf(p
, "--%s" ENDL
, bound
);
1916 fprintf(p
, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL
, ctype
, format
, msgnum
+ 1, format
);
1917 fprintf(p
, "Content-Transfer-Encoding: base64" ENDL
);
1918 fprintf(p
, "Content-Description: Voicemail sound attachment." ENDL
);
1919 fprintf(p
, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL
, msgnum
+ 1, format
);
1920 snprintf(fname
, sizeof(fname
), "%s.%s", attach
, format
);
1921 base_encode(fname
, p
);
1922 fprintf(p
, ENDL
"--%s--" ENDL
"." ENDL
, bound
);
1931 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
)
1934 char tmp
[80] = "/tmp/astmail-XXXXXX";
1937 if (vmu
&& ast_strlen_zero(vmu
->email
)) {
1938 ast_log(LOG_WARNING
, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu
->mailbox
);
1941 if (!strcmp(format
, "wav49"))
1943 if (option_debug
> 2)
1944 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
));
1945 /* Make a temporary file instead of piping directly to sendmail, in case the mail
1947 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
1948 ast_log(LOG_WARNING
, "Unable to launch '%s' (can't create temporary file)\n", mailcmd
);
1951 make_email_file(p
, srcemail
, vmu
, msgnum
, context
, mailbox
, cidnum
, cidname
, attach
, format
, duration
, attach_user_voicemail
, chan
, category
, 0);
1953 snprintf(tmp2
, sizeof(tmp2
), "( %s < %s ; rm -f %s ) &", mailcmd
, tmp
, tmp
);
1954 ast_safe_system(tmp2
);
1955 if (option_debug
> 2)
1956 ast_log(LOG_DEBUG
, "Sent mail to %s with command '%s'\n", vmu
->email
, mailcmd
);
1961 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
)
1964 char host
[MAXHOSTNAMELEN
] = "";
1967 char tmp
[80] = "/tmp/astmail-XXXXXX";
1968 char tmp2
[PATH_MAX
];
1972 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
1973 ast_log(LOG_WARNING
, "Unable to launch '%s' (can't create temporary file)\n", mailcmd
);
1976 gethostname(host
, sizeof(host
)-1);
1977 if (strchr(srcemail
, '@'))
1978 ast_copy_string(who
, srcemail
, sizeof(who
));
1980 snprintf(who
, sizeof(who
), "%s@%s", srcemail
, host
);
1982 snprintf(dur
, sizeof(dur
), "%d:%02d", duration
/ 60, duration
% 60);
1983 strftime(date
, sizeof(date
), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu
, &tm
));
1984 fprintf(p
, "Date: %s\n", date
);
1986 if (*pagerfromstring
) {
1987 struct ast_channel
*ast
;
1988 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
1990 int vmlen
= strlen(fromstring
)*3 + 200;
1991 if ((passdata
= alloca(vmlen
))) {
1992 memset(passdata
, 0, vmlen
);
1993 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
1994 pbx_substitute_variables_helper(ast
, pagerfromstring
, passdata
, vmlen
);
1995 fprintf(p
, "From: %s <%s>\n", passdata
, who
);
1997 ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
1998 ast_channel_free(ast
);
1999 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2001 fprintf(p
, "From: Asterisk PBX <%s>\n", who
);
2002 fprintf(p
, "To: %s\n", pager
);
2004 struct ast_channel
*ast
;
2005 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
2007 int vmlen
= strlen(pagersubject
) * 3 + 200;
2008 if ((passdata
= alloca(vmlen
))) {
2009 memset(passdata
, 0, vmlen
);
2010 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
2011 pbx_substitute_variables_helper(ast
, pagersubject
, passdata
, vmlen
);
2012 fprintf(p
, "Subject: %s\n\n", passdata
);
2013 } else ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
2014 ast_channel_free(ast
);
2015 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2017 fprintf(p
, "Subject: New VM\n\n");
2018 strftime(date
, sizeof(date
), "%A, %B %d, %Y at %r", &tm
);
2020 struct ast_channel
*ast
;
2021 if ((ast
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0))) {
2023 int vmlen
= strlen(pagerbody
)*3 + 200;
2024 if ((passdata
= alloca(vmlen
))) {
2025 memset(passdata
, 0, vmlen
);
2026 prep_email_sub_vars(ast
, vmu
, msgnum
+ 1, context
, mailbox
, cidnum
, cidname
, dur
, date
, passdata
, vmlen
, category
);
2027 pbx_substitute_variables_helper(ast
, pagerbody
, passdata
, vmlen
);
2028 fprintf(p
, "%s\n", passdata
);
2029 } else ast_log(LOG_WARNING
, "Cannot allocate workspace for variable substitution\n");
2030 ast_channel_free(ast
);
2031 } else ast_log(LOG_WARNING
, "Cannot allocate the channel for variables substitution\n");
2033 fprintf(p
, "New %s long msg in box %s\n"
2034 "from %s, on %s", dur
, mailbox
, (cidname
? cidname
: (cidnum
? cidnum
: "unknown")), date
);
2037 snprintf(tmp2
, sizeof(tmp2
), "( %s < %s ; rm -f %s ) &", mailcmd
, tmp
, tmp
);
2038 ast_safe_system(tmp2
);
2039 if (option_debug
> 2)
2040 ast_log(LOG_DEBUG
, "Sent page to %s with command '%s'\n", pager
, mailcmd
);
2045 static int get_date(char *s
, int len
)
2052 ast_localtime(&t
, &tm
, NULL
);
2054 return strftime(s
, len
, "%a %b %e %r %Z %Y", &tm
);
2057 static int invent_message(struct ast_channel
*chan
, char *context
, char *ext
, int busy
, char *ecodes
)
2061 char dest
[PATH_MAX
];
2063 snprintf(fn
, sizeof(fn
), "%s%s/%s/greet", VM_SPOOL_DIR
, context
, ext
);
2065 if ((res
= create_dirpath(dest
, sizeof(dest
), context
, ext
, "greet"))) {
2066 ast_log(LOG_WARNING
, "Failed to make directory(%s)\n", fn
);
2071 if (ast_fileexists(fn
, NULL
, NULL
) > 0) {
2072 res
= ast_stream_and_wait(chan
, fn
, chan
->language
, ecodes
);
2078 /* Dispose just in case */
2080 res
= ast_stream_and_wait(chan
, "vm-theperson", chan
->language
, ecodes
);
2083 res
= ast_say_digit_str(chan
, ext
, ecodes
, chan
->language
);
2087 res
= ast_stream_and_wait(chan
, busy
? "vm-isonphone" : "vm-isunavail", chan
->language
, ecodes
);
2091 static void free_user(struct ast_vm_user
*vmu
)
2093 if (ast_test_flag(vmu
, VM_ALLOCED
))
2097 static void free_zone(struct vm_zone
*z
)
2102 static const char *mbox(int id
)
2104 static const char *msgs
[] = {
2116 return (id
>= 0 && id
< (sizeof(msgs
)/sizeof(msgs
[0]))) ? msgs
[id
] : "Unknown";
2119 static int folder_int(const char *folder
)
2121 /*assume a NULL folder means INBOX*/
2124 if(!strcasecmp(folder
, "INBOX"))
2126 else if (!strcasecmp(folder
, "Old"))
2128 else if (!strcasecmp(folder
, "Work"))
2130 else if (!strcasecmp(folder
, "Family"))
2132 else if (!strcasecmp(folder
, "Friends"))
2134 else if (!strcasecmp(folder
, "Cust1"))
2136 else if (!strcasecmp(folder
, "Cust2"))
2138 else if (!strcasecmp(folder
, "Cust3"))
2140 else if (!strcasecmp(folder
, "Cust4"))
2142 else if (!strcasecmp(folder
, "Cust5"))
2144 else /*assume they meant INBOX if folder is not found otherwise*/
2150 /*! XXX \todo Fix this function to support multiple mailboxes in the intput string */
2151 static int inboxcount(const char *mailbox
, int *newmsgs
, int *oldmsgs
)
2158 char tmp
[PATH_MAX
] = "";
2159 struct odbc_obj
*obj
;
2161 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 0 };
2168 /* If no mailbox, return immediately */
2169 if (ast_strlen_zero(mailbox
))
2172 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2174 context
= strchr(tmp
, '@');
2179 context
= "default";
2181 obj
= ast_odbc_request_obj(odbc_database
, 0);
2183 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, tmp
, "INBOX");
2184 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2186 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2187 ast_odbc_release_obj(obj
);
2190 res
= SQLFetch(stmt
);
2191 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2192 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2193 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2194 ast_odbc_release_obj(obj
);
2197 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2198 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2199 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2200 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2201 ast_odbc_release_obj(obj
);
2204 *newmsgs
= atoi(rowdata
);
2205 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2207 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, tmp
, "Old");
2208 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2210 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2211 ast_odbc_release_obj(obj
);
2214 res
= SQLFetch(stmt
);
2215 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2216 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2217 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2218 ast_odbc_release_obj(obj
);
2221 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2222 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2223 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2224 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2225 ast_odbc_release_obj(obj
);
2228 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2229 ast_odbc_release_obj(obj
);
2230 *oldmsgs
= atoi(rowdata
);
2233 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
2239 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2241 struct odbc_obj
*obj
= NULL
;
2244 SQLHSTMT stmt
= NULL
;
2247 struct generic_prepare_struct gps
= { .sql
= sql
, .argc
= 0 };
2250 /* If no mailbox, return immediately */
2251 if (ast_strlen_zero(mailbox
))
2254 obj
= ast_odbc_request_obj(odbc_database
, 0);
2256 snprintf(sql
, sizeof(sql
), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table
, VM_SPOOL_DIR
, context
, mailbox
, folder
);
2257 stmt
= ast_odbc_prepare_and_execute(obj
, generic_prepare
, &gps
);
2259 ast_log(LOG_WARNING
, "SQL Execute error!\n[%s]\n\n", sql
);
2262 res
= SQLFetch(stmt
);
2263 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2264 ast_log(LOG_WARNING
, "SQL Fetch error!\n[%s]\n\n", sql
);
2265 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2268 res
= SQLGetData(stmt
, 1, SQL_CHAR
, rowdata
, sizeof(rowdata
), NULL
);
2269 if ((res
!= SQL_SUCCESS
) && (res
!= SQL_SUCCESS_WITH_INFO
)) {
2270 ast_log(LOG_WARNING
, "SQL Get Data error!\n[%s]\n\n", sql
);
2271 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2274 nummsgs
= atoi(rowdata
);
2275 SQLFreeHandle (SQL_HANDLE_STMT
, stmt
);
2277 ast_log(LOG_WARNING
, "Failed to obtain database object for '%s'!\n", odbc_database
);
2281 ast_odbc_release_obj(obj
);
2285 static int has_voicemail(const char *mailbox
, const char *folder
)
2287 char tmp
[256], *tmp2
= tmp
, *mbox
, *context
;
2288 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2289 while ((context
= mbox
= strsep(&tmp2
, ","))) {
2290 strsep(&context
, "@");
2291 if (ast_strlen_zero(context
))
2292 context
= "default";
2293 if (messagecount(context
, mbox
, folder
))
2299 #elif defined(IMAP_STORAGE)
2301 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
)
2303 char *myserveremail
= serveremail
;
2308 char tmp
[80] = "/tmp/astmail-XXXXXX";
2313 /* Attach only the first format */
2314 fmt
= ast_strdupa(fmt
);
2316 strsep(&stringp
, "|");
2318 if (!ast_strlen_zero(vmu
->serveremail
))
2319 myserveremail
= vmu
->serveremail
;
2321 make_file(fn
, sizeof(fn
), dir
, msgnum
);
2323 if (ast_strlen_zero(vmu
->email
))
2324 ast_copy_string(vmu
->email
, vmu
->imapuser
, sizeof(vmu
->email
));
2326 if (!strcmp(fmt
, "wav49"))
2328 if(option_debug
> 2)
2329 ast_log(LOG_DEBUG
, "Storing file '%s', format '%s'\n", fn
, fmt
);
2330 /* Make a temporary file instead of piping directly to sendmail, in case the mail
2332 if ((p
= vm_mkftemp(tmp
)) == NULL
) {
2333 ast_log(LOG_WARNING
, "Unable to store '%s' (can't create temporary file)\n", fn
);
2336 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);
2337 /* read mail file to memory */
2340 if((buf
= ast_malloc(len
+1)) == NIL
) {
2341 ast_log(LOG_ERROR
, "Can't allocate %ld bytes to read message\n", len
+1);
2344 fread(buf
, len
, 1, p
);
2345 ((char *)buf
)[len
] = '\0';
2346 INIT(&str
, mail_string
, buf
, len
);
2347 init_mailstream(vms
, 0);
2348 imap_mailbox_name(mailbox
, sizeof(mailbox
), vms
, 0, 1);
2349 if(!mail_append(vms
->mailstream
, mailbox
, &str
))
2350 ast_log(LOG_ERROR
, "Error while sending the message to %s\n", mailbox
);
2354 if(option_debug
> 2)
2355 ast_log(LOG_DEBUG
, "%s stored\n", fn
);
2361 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2366 struct ast_vm_user
*vmu
, vmus
;
2367 struct vm_state
*vms_p
;
2369 int fold
= folder_int(folder
);
2371 if (ast_strlen_zero(mailbox
))
2374 /* We have to get the user before we can open the stream! */
2375 /* ast_log (LOG_DEBUG,"Before find_user, context is %s and mailbox is %s\n",context,mailbox); */
2376 vmu
= find_user(&vmus
, context
, mailbox
);
2378 ast_log (LOG_ERROR
,"Couldn't find mailbox %s in context %s\n",mailbox
,context
);
2381 /* No IMAP account available */
2382 if (vmu
->imapuser
[0] == '\0') {
2383 ast_log (LOG_WARNING
,"IMAP user not set for mailbox %s\n",vmu
->mailbox
);
2388 /* check if someone is accessing this box right now... */
2389 vms_p
= get_vm_state_by_imapuser(vmu
->imapuser
,1);
2391 vms_p
= get_vm_state_by_mailbox(mailbox
,1);
2394 if(option_debug
> 2)
2395 ast_log (LOG_DEBUG
,"Returning before search - user is logged in\n");
2396 if(fold
== 0) {/*INBOX*/
2397 return vms_p
->newmessages
;
2399 if(fold
== 1) {/*Old messages*/
2400 return vms_p
->oldmessages
;
2404 /* add one if not there... */
2405 vms_p
= get_vm_state_by_imapuser(vmu
->imapuser
,0);
2407 vms_p
= get_vm_state_by_mailbox(mailbox
,0);
2411 if(option_debug
> 2)
2412 ast_log (LOG_DEBUG
,"Adding new vmstate for %s\n",vmu
->imapuser
);
2413 if (!(vms_p
= ast_calloc(1, sizeof(*vms_p
)))) {
2416 ast_copy_string(vms_p
->imapuser
,vmu
->imapuser
, sizeof(vms_p
->imapuser
));
2417 ast_copy_string(vms_p
->username
, mailbox
, sizeof(vms_p
->username
)); /* save for access from interactive entry point */
2418 vms_p
->mailstream
= NIL
; /* save for access from interactive entry point */
2419 if(option_debug
> 2)
2420 ast_log (LOG_DEBUG
,"Copied %s to %s\n",vmu
->imapuser
,vms_p
->imapuser
);
2422 /* set mailbox to INBOX! */
2423 ast_copy_string(vms_p
->curbox
, mbox(fold
), sizeof(vms_p
->curbox
));
2424 init_vm_state(vms_p
);
2425 vmstate_insert(vms_p
);
2427 ret
= init_mailstream(vms_p
, fold
);
2428 if (!vms_p
->mailstream
) {
2429 ast_log (LOG_ERROR
,"IMAP mailstream is NULL\n");
2433 pgm
= mail_newsearchpgm ();
2434 hdr
= mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox
);
2440 /* In the special case where fold is 1 (old messages) we have to do things a bit
2441 * differently. Old messages are stored in the INBOX but are marked as "seen"
2450 vms_p
->vmArrayIndex
= 0;
2451 mail_search_full (vms_p
->mailstream
, NULL
, pgm
, NIL
);
2453 vms_p
->newmessages
= vms_p
->vmArrayIndex
;
2455 vms_p
->oldmessages
= vms_p
->vmArrayIndex
;
2456 /*Freeing the searchpgm also frees the searchhdr*/
2457 mail_free_searchpgm(&pgm
);
2459 return vms_p
->vmArrayIndex
;
2461 mail_ping(vms_p
->mailstream
);
2465 static int inboxcount(const char *mailbox_context
, int *newmsgs
, int *oldmsgs
)
2467 char tmp
[PATH_MAX
] = "";
2477 if(option_debug
> 2)
2478 ast_log (LOG_DEBUG
,"Mailbox is set to %s\n",mailbox_context
);
2479 /* If no mailbox, return immediately */
2480 if (ast_strlen_zero(mailbox_context
))
2483 ast_copy_string(tmp
, mailbox_context
, sizeof(tmp
));
2484 context
= strchr(tmp
, '@');
2485 if (strchr(mailbox_context
, ',')) {
2487 ast_copy_string(tmp
, mailbox_context
, sizeof(tmp
));
2489 while((cur
= strsep(&mb
, ", "))) {
2490 if (!ast_strlen_zero(cur
)) {
2491 if (inboxcount(cur
, newmsgs
? &tmpnew
: NULL
, oldmsgs
? &tmpold
: NULL
))
2508 context
= "default";
2509 mailboxnc
= (char *)mailbox_context
;
2512 if((*newmsgs
= messagecount(context
, mailboxnc
, "INBOX")) < 0)
2516 if((*oldmsgs
= messagecount(context
, mailboxnc
, "Old")) < 0)
2523 static int has_voicemail(const char *mailbox
, const char *folder
)
2525 char tmp
[256], *tmp2
, *mbox
, *context
;
2526 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2528 if(strchr(tmp2
, ',')) {
2529 while((mbox
= strsep(&tmp2
, ","))) {
2530 if(!ast_strlen_zero(mbox
)) {
2531 if (has_voicemail(mbox
, folder
))
2536 if ((context
= strchr(tmp
, '@')))
2539 context
= "default";
2540 return messagecount(context
, tmp
, folder
) ? 1 : 0;
2543 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
)
2546 struct vm_state
*sendvms
= NULL
, *destvms
= NULL
;
2547 char messagestring
[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
2548 if(!(sendvms
= get_vm_state_by_imapuser(vmu
->imapuser
, 2)))
2550 ast_log(LOG_ERROR
, "Couldn't get vm_state for originator's mailbox!!\n");
2553 if(!(destvms
= get_vm_state_by_imapuser(recip
->imapuser
, 2)))
2555 ast_log(LOG_ERROR
, "Couldn't get vm_state for destination mailbox!\n");
2558 imap_mailbox_name(dest
, sizeof(dest
), destvms
, imbox
, 1);
2559 snprintf(messagestring
, sizeof(messagestring
), "%ld", sendvms
->msgArray
[msgnum
]);
2560 if((mail_copy(sendvms
->mailstream
, messagestring
, dest
) == T
))
2562 ast_log(LOG_WARNING
, "Unable to copy message from mailbox %s to mailbox %s\n", vmu
->mailbox
, recip
->mailbox
);
2567 #ifndef IMAP_STORAGE
2568 /* copy message only used by file storage */
2569 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
)
2571 char fromdir
[PATH_MAX
], todir
[PATH_MAX
], frompath
[PATH_MAX
], topath
[PATH_MAX
];
2572 const char *frombox
= mbox(imbox
);
2575 ast_log(LOG_NOTICE
, "Copying message from %s@%s to %s@%s\n", vmu
->mailbox
, vmu
->context
, recip
->mailbox
, recip
->context
);
2577 create_dirpath(todir
, sizeof(todir
), recip
->context
, recip
->mailbox
, "INBOX");
2580 make_dir(fromdir
, sizeof(fromdir
), vmu
->context
, vmu
->mailbox
, frombox
);
2582 ast_copy_string(fromdir
, dir
, sizeof(fromdir
));
2584 make_file(frompath
, sizeof(frompath
), fromdir
, msgnum
);
2586 if (vm_lock_path(todir
))
2587 return ERROR_LOCK_PATH
;
2591 make_file(topath
, sizeof(topath
), todir
, recipmsgnum
);
2592 if (!EXISTS(todir
, recipmsgnum
, topath
, chan
->language
))
2595 } while (recipmsgnum
< recip
->maxmsg
);
2596 if (recipmsgnum
< recip
->maxmsg
) {
2597 COPY(fromdir
, msgnum
, todir
, recipmsgnum
, recip
->mailbox
, recip
->context
, frompath
, topath
);
2599 ast_log(LOG_ERROR
, "Recipient mailbox %s@%s is full\n", recip
->mailbox
, recip
->context
);
2601 ast_unlock_path(todir
);
2602 notify_new_message(chan
, recip
, recipmsgnum
, duration
, fmt
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
));
2607 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
2608 static int messagecount(const char *context
, const char *mailbox
, const char *folder
)
2610 return __has_voicemail(context
, mailbox
, folder
, 0);
2614 static int __has_voicemail(const char *context
, const char *mailbox
, const char *folder
, int shortcircuit
)
2622 /* If no mailbox, return immediately */
2623 if (ast_strlen_zero(mailbox
))
2626 context
= "default";
2627 snprintf(fn
, sizeof(fn
), "%s%s/%s/%s", VM_SPOOL_DIR
, context
, mailbox
, folder
);
2631 while ((de
= readdir(dir
))) {
2632 if (!strncasecmp(de
->d_name
, "msg", 3)) {
2636 } else if (!strncasecmp(de
->d_name
+ 8, "txt", 3))
2645 static int has_voicemail(const char *mailbox
, const char *folder
)
2647 char tmp
[256], *tmp2
= tmp
, *mbox
, *context
;
2648 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2649 while ((mbox
= strsep(&tmp2
, ","))) {
2650 if ((context
= strchr(mbox
, '@')))
2653 context
= "default";
2654 if (__has_voicemail(context
, mbox
, folder
, 1))
2661 static int inboxcount(const char *mailbox
, int *newmsgs
, int *oldmsgs
)
2670 /* If no mailbox, return immediately */
2671 if (ast_strlen_zero(mailbox
))
2673 if (strchr(mailbox
, ',')) {
2677 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2679 while ((cur
= strsep(&mb
, ", "))) {
2680 if (!ast_strlen_zero(cur
)) {
2681 if (inboxcount(cur
, newmsgs
? &tmpnew
: NULL
, oldmsgs
? &tmpold
: NULL
))
2693 ast_copy_string(tmp
, mailbox
, sizeof(tmp
));
2694 context
= strchr(tmp
, '@');
2699 context
= "default";
2701 *newmsgs
= __has_voicemail(context
, tmp
, "INBOX", 0);
2703 *oldmsgs
= __has_voicemail(context
, tmp
, "Old", 0);
2709 static void run_externnotify(char *context
, char *extension
)
2711 char arguments
[255];
2712 char ext_context
[256] = "";
2713 int newvoicemails
= 0, oldvoicemails
= 0;
2714 struct ast_smdi_mwi_message
*mwi_msg
;
2716 if (!ast_strlen_zero(context
))
2717 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", extension
, context
);
2719 ast_copy_string(ext_context
, extension
, sizeof(ext_context
));
2721 if (!strcasecmp(externnotify
, "smdi")) {
2722 if (ast_app_has_voicemail(ext_context
, NULL
))
2723 ast_smdi_mwi_set(smdi_iface
, extension
);
2725 ast_smdi_mwi_unset(smdi_iface
, extension
);
2727 if ((mwi_msg
= ast_smdi_mwi_message_wait(smdi_iface
, SMDI_MWI_WAIT_TIMEOUT
))) {
2728 ast_log(LOG_ERROR
, "Error executing SMDI MWI change for %s on %s\n", extension
, smdi_iface
->name
);
2729 if (!strncmp(mwi_msg
->cause
, "INV", 3))
2730 ast_log(LOG_ERROR
, "Invalid MWI extension: %s\n", mwi_msg
->fwd_st
);
2731 else if (!strncmp(mwi_msg
->cause
, "BLK", 3))
2732 ast_log(LOG_WARNING
, "MWI light was already on or off for %s\n", mwi_msg
->fwd_st
);
2733 ast_log(LOG_WARNING
, "The switch reported '%s'\n", mwi_msg
->cause
);
2734 ASTOBJ_UNREF(mwi_msg
, ast_smdi_mwi_message_destroy
);
2737 ast_log(LOG_DEBUG
, "Successfully executed SMDI MWI change for %s on %s\n", extension
, smdi_iface
->name
);
2739 } else if (!ast_strlen_zero(externnotify
)) {
2740 if (inboxcount(ext_context
, &newvoicemails
, &oldvoicemails
)) {
2741 ast_log(LOG_ERROR
, "Problem in calculating number of voicemail messages available for extension %s\n", extension
);
2743 snprintf(arguments
, sizeof(arguments
), "%s %s %s %d&", externnotify
, context
, extension
, newvoicemails
);
2745 ast_log(LOG_DEBUG
, "Executing %s\n", arguments
);
2746 ast_safe_system(arguments
);
2751 struct leave_vm_options
{
2753 signed char record_gain
;
2756 static int leave_voicemail(struct ast_channel
*chan
, char *ext
, struct leave_vm_options
*options
)
2759 int newmsgs
, oldmsgs
;
2760 struct vm_state
*vms
= NULL
;
2762 char txtfile
[PATH_MAX
], tmptxtfile
[PATH_MAX
];
2773 char dir
[PATH_MAX
], tmpdir
[PATH_MAX
];
2774 char dest
[PATH_MAX
];
2776 char prefile
[PATH_MAX
] = "";
2777 char tempfile
[PATH_MAX
] = "";
2778 char ext_context
[256] = "";
2781 char ecodes
[16] = "#";
2782 char tmp
[1024] = "", *tmpptr
;
2783 struct ast_vm_user
*vmu
;
2784 struct ast_vm_user svm
;
2785 const char *category
= NULL
;
2787 ast_copy_string(tmp
, ext
, sizeof(tmp
));
2789 context
= strchr(tmp
, '@');
2792 tmpptr
= strchr(context
, '&');
2794 tmpptr
= strchr(ext
, '&');
2800 category
= pbx_builtin_getvar_helper(chan
, "VM_CATEGORY");
2802 if(option_debug
> 2)
2803 ast_log(LOG_DEBUG
, "Before find_user\n");
2804 if (!(vmu
= find_user(&svm
, context
, ext
))) {
2805 ast_log(LOG_WARNING
, "No entry in voicemail config file for '%s'\n", ext
);
2806 if (ast_test_flag(options
, OPT_PRIORITY_JUMP
) || ast_opt_priority_jumping
)
2807 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
2808 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2811 /* Setup pre-file if appropriate */
2812 if (strcmp(vmu
->context
, "default"))
2813 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", ext
, vmu
->context
);
2815 ast_copy_string(ext_context
, vmu
->mailbox
, sizeof(ext_context
));
2816 if (ast_test_flag(options
, OPT_BUSY_GREETING
)) {
2817 res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "busy");
2818 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, ext
);
2819 } else if (ast_test_flag(options
, OPT_UNAVAIL_GREETING
)) {
2820 res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "unavail");
2821 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, ext
);
2823 snprintf(tempfile
, sizeof(tempfile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, ext
);
2824 if ((res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, ext
, "temp"))) {
2825 ast_log(LOG_WARNING
, "Failed to make directory (%s)\n", tempfile
);
2828 RETRIEVE(tempfile
, -1);
2829 if (ast_fileexists(tempfile
, NULL
, NULL
) > 0)
2830 ast_copy_string(prefile
, tempfile
, sizeof(prefile
));
2831 DISPOSE(tempfile
, -1);
2832 /* It's easier just to try to make it than to check for its existence */
2833 create_dirpath(dir
, sizeof(dir
), vmu
->context
, ext
, "INBOX");
2834 create_dirpath(tmpdir
, sizeof(tmpdir
), vmu
->context
, ext
, "tmp");
2836 /* Check current or macro-calling context for special extensions */
2837 if (ast_test_flag(vmu
, VM_OPERATOR
)) {
2838 if (!ast_strlen_zero(vmu
->exit
)) {
2839 if (ast_exists_extension(chan
, vmu
->exit
, "o", 1, chan
->cid
.cid_num
)) {
2840 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2843 } else if (ast_exists_extension(chan
, chan
->context
, "o", 1, chan
->cid
.cid_num
)) {
2844 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2847 else if (!ast_strlen_zero(chan
->macrocontext
) && ast_exists_extension(chan
, chan
->macrocontext
, "o", 1, chan
->cid
.cid_num
)) {
2848 strncat(ecodes
, "0", sizeof(ecodes
) - strlen(ecodes
) - 1);
2853 if (!ast_strlen_zero(vmu
->exit
)) {
2854 if (ast_exists_extension(chan
, vmu
->exit
, "a", 1, chan
->cid
.cid_num
))
2855 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2856 } else if (ast_exists_extension(chan
, chan
->context
, "a", 1, chan
->cid
.cid_num
))
2857 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2858 else if (!ast_strlen_zero(chan
->macrocontext
) && ast_exists_extension(chan
, chan
->macrocontext
, "a", 1, chan
->cid
.cid_num
)) {
2859 strncat(ecodes
, "*", sizeof(ecodes
) - strlen(ecodes
) - 1);
2863 /* Play the beginning intro if desired */
2864 if (!ast_strlen_zero(prefile
)) {
2868 RETRIEVE(prefile
, -1);
2869 if (ast_fileexists(prefile
, NULL
, NULL
) > 0) {
2870 if (ast_streamfile(chan
, prefile
, chan
->language
) > -1)
2871 res
= ast_waitstream(chan
, ecodes
);
2873 if (success
== -1) {
2874 /* We couldn't retrieve the file from the database, but we found it on the file system. Let's put it in the database. */
2876 ast_log(LOG_DEBUG
, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
2877 store_file(prefile
, vmu
->mailbox
, vmu
->context
, -1);
2882 ast_log(LOG_DEBUG
, "%s doesn't exist, doing what we can\n", prefile
);
2883 res
= invent_message(chan
, vmu
->context
, ext
, ast_test_flag(options
, OPT_BUSY_GREETING
), ecodes
);
2885 DISPOSE(prefile
, -1);
2888 ast_log(LOG_DEBUG
, "Hang up during prefile playback\n");
2890 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2895 /* On a '#' we skip the instructions */
2896 ast_set_flag(options
, OPT_SILENT
);
2899 if (!res
&& !ast_test_flag(options
, OPT_SILENT
)) {
2900 res
= ast_stream_and_wait(chan
, INTRO
, chan
->language
, ecodes
);
2902 ast_set_flag(options
, OPT_SILENT
);
2907 ast_stopstream(chan
);
2908 /* Check for a '*' here in case the caller wants to escape from voicemail to something
2909 other than the operator -- an automated attendant or mailbox login for example */
2911 chan
->exten
[0] = 'a';
2912 chan
->exten
[1] = '\0';
2913 if (!ast_strlen_zero(vmu
->exit
)) {
2914 ast_copy_string(chan
->context
, vmu
->exit
, sizeof(chan
->context
));
2915 } else if (ausemacro
&& !ast_strlen_zero(chan
->macrocontext
)) {
2916 ast_copy_string(chan
->context
, chan
->macrocontext
, sizeof(chan
->context
));
2920 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "USEREXIT");
2924 /* Check for a '0' here */
2927 if (ouseexten
|| ousemacro
) {
2928 chan
->exten
[0] = 'o';
2929 chan
->exten
[1] = '\0';
2930 if (!ast_strlen_zero(vmu
->exit
)) {
2931 ast_copy_string(chan
->context
, vmu
->exit
, sizeof(chan
->context
));
2932 } else if (ousemacro
&& !ast_strlen_zero(chan
->macrocontext
)) {
2933 ast_copy_string(chan
->context
, chan
->macrocontext
, sizeof(chan
->context
));
2935 ast_play_and_wait(chan
, "transfer");
2938 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "USEREXIT");
2944 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
2947 /* The meat of recording the message... All the announcements and beeps have been played*/
2948 ast_copy_string(fmt
, vmfmts
, sizeof(fmt
));
2949 if (!ast_strlen_zero(fmt
)) {
2953 /* Is ext a mailbox? */
2954 /* must open stream for this user to get info! */
2955 res
= inboxcount(ext_context
, &newmsgs
, &oldmsgs
);
2957 ast_log(LOG_NOTICE
,"Can not leave voicemail, unable to count messages\n");
2960 if(!(vms
= get_vm_state_by_mailbox(ext
,0))) {
2961 /*It is possible under certain circumstances that inboxcount did not create a vm_state when it was needed. This is a catchall which will
2963 if (!(vms
= ast_calloc(1, sizeof(*vms
)))) {
2964 ast_log(LOG_ERROR
, "Couldn't allocate necessary space\n");
2967 ast_copy_string(vms
->imapuser
, vmu
->imapuser
, sizeof(vms
->imapuser
));
2968 ast_copy_string(vms
->username
, ext
, sizeof(vms
->username
));
2969 vms
->mailstream
= NIL
;
2970 if (option_debug
> 2)
2971 ast_log(LOG_DEBUG
, "Copied %s to %s\n", vmu
->imapuser
, vms
->imapuser
);
2973 ast_copy_string(vms
->curbox
, mbox(0), sizeof(vms
->curbox
));
2975 vmstate_insert(vms
);
2976 vms
= get_vm_state_by_mailbox(ext
,0);
2979 /* here is a big difference! We add one to it later */
2980 msgnum
= newmsgs
+ oldmsgs
;
2981 if (option_debug
> 2)
2982 ast_log(LOG_DEBUG
, "Messagecount set to %d\n",msgnum
);
2983 snprintf(fn
, sizeof(fn
), "%s/imap/msg%s%04d", VM_SPOOL_DIR
, vmu
->mailbox
, msgnum
);
2984 /* set variable for compatability */
2985 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", "IMAP_STORAGE");
2987 /* Check if mailbox is full */
2988 if (vms
->quota_limit
&& vms
->quota_usage
>= vms
->quota_limit
) {
2990 ast_log(LOG_DEBUG
, "*** QUOTA EXCEEDED!! %u >= %u\n", vms
->quota_usage
, vms
->quota_limit
);
2991 ast_play_and_wait(chan
, "vm-mailboxfull");
2994 /* here is a big difference! We add one to it later */
2995 if (option_debug
> 2)
2996 ast_log(LOG_DEBUG
, "Messagecount set to %d\n",msgnum
);
2998 if (count_messages(vmu
, dir
) >= vmu
->maxmsg
) {
2999 res
= ast_streamfile(chan
, "vm-mailboxfull", chan
->language
);
3001 res
= ast_waitstream(chan
, "");
3002 ast_log(LOG_WARNING
, "No more messages possible\n");
3003 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3008 snprintf(tmptxtfile
, sizeof(tmptxtfile
), "%s/XXXXXX", tmpdir
);
3009 txtdes
= mkstemp(tmptxtfile
);
3010 chmod(tmptxtfile
, VOICEMAIL_FILE_MODE
& ~my_umask
);
3012 res
= ast_streamfile(chan
, "vm-mailboxfull", chan
->language
);
3014 res
= ast_waitstream(chan
, "");
3015 ast_log(LOG_ERROR
, "Unable to create message file: %s\n", strerror(errno
));
3016 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3020 /* Now play the beep once we have the message number for our next message. */
3022 /* Unless we're *really* silent, try to send the beep */
3023 res
= ast_stream_and_wait(chan
, "beep", chan
->language
, "");
3026 /* Store information */
3027 txt
= fdopen(txtdes
, "w+");
3029 get_date(date
, sizeof(date
));
3032 "; Message Information file\n"
3051 ast_callerid_merge(callerid
, sizeof(callerid
), S_OR(chan
->cid
.cid_name
, NULL
), S_OR(chan
->cid
.cid_num
, NULL
), "Unknown"),
3052 date
, (long)time(NULL
),
3053 category
? category
: "");
3055 ast_log(LOG_WARNING
, "Error opening text file for output\n");
3057 res
= play_record_review(chan
, NULL
, tmptxtfile
, vmmaxmessage
, fmt
, 1, vmu
, &duration
, NULL
, options
->record_gain
, vms
);
3059 res
= play_record_review(chan
, NULL
, tmptxtfile
, vmmaxmessage
, fmt
, 1, vmu
, &duration
, NULL
, options
->record_gain
, NULL
);
3063 if (duration
< vmminmessage
) {
3065 if (option_verbose
> 2)
3066 ast_verbose( VERBOSE_PREFIX_3
"Recording was %d seconds long but needs to be at least %d - abandoning\n", duration
, vmminmessage
);
3067 ast_filedelete(tmptxtfile
, NULL
);
3070 fprintf(txt
, "duration=%d\n", duration
);
3072 if (vm_lock_path(dir
)) {
3073 ast_log(LOG_ERROR
, "Couldn't lock directory %s. Voicemail will be lost.\n", dir
);
3075 ast_filedelete(tmptxtfile
, NULL
);
3077 } else if (ast_fileexists(tmptxtfile
, NULL
, NULL
) <= 0) {
3079 ast_log(LOG_DEBUG
, "The recorded media file is gone, so we should remove the .txt file too!\n");
3081 ast_unlock_path(dir
);
3084 make_file(fn
, sizeof(fn
), dir
, msgnum
);
3085 if (!EXISTS(dir
, msgnum
, fn
, NULL
))
3090 /* assign a variable with the name of the voicemail file */
3091 #ifndef IMAP_STORAGE
3092 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", fn
);
3094 pbx_builtin_setvar_helper(chan
, "VM_MESSAGEFILE", "IMAP_STORAGE");
3097 snprintf(txtfile
, sizeof(txtfile
), "%s.txt", fn
);
3098 ast_filerename(tmptxtfile
, fn
, NULL
);
3099 rename(tmptxtfile
, txtfile
);
3101 ast_unlock_path(dir
);
3102 /* We must store the file first, before copying the message, because
3103 * ODBC storage does the entire copy with SQL.
3105 if (ast_fileexists(fn
, NULL
, NULL
) > 0) {
3106 STORE(dir
, vmu
->mailbox
, vmu
->context
, msgnum
, chan
, vmu
, fmt
, duration
, vms
);
3109 /* Are there to be more recipients of this message? */
3111 struct ast_vm_user recipu
, *recip
;
3112 char *exten
, *context
;
3114 exten
= strsep(&tmpptr
, "&");
3115 context
= strchr(exten
, '@');
3120 if ((recip
= find_user(&recipu
, context
, exten
))) {
3121 copy_message(chan
, vmu
, 0, msgnum
, duration
, recip
, fmt
, dir
);
3125 /* Notification and disposal needs to happen after the copy, though. */
3126 if (ast_fileexists(fn
, NULL
, NULL
)) {
3127 notify_new_message(chan
, vmu
, msgnum
, duration
, fmt
, S_OR(chan
->cid
.cid_num
, NULL
), S_OR(chan
->cid
.cid_name
, NULL
));
3128 DISPOSE(dir
, msgnum
);
3138 if (duration
< vmminmessage
)
3139 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
3140 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
3142 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "SUCCESS");
3144 ast_log(LOG_WARNING
, "No format for saving voicemail?\n");
3151 #ifndef IMAP_STORAGE
3152 static int resequence_mailbox(struct ast_vm_user
*vmu
, char *dir
)
3154 /* we know max messages, so stop process when number is hit */
3160 if (vm_lock_path(dir
))
3161 return ERROR_LOCK_PATH
;
3163 for (x
= 0, dest
= 0; x
< vmu
->maxmsg
; x
++) {
3164 make_file(sfn
, sizeof(sfn
), dir
, x
);
3165 if (EXISTS(dir
, x
, sfn
, NULL
)) {
3168 make_file(dfn
, sizeof(dfn
), dir
, dest
);
3169 RENAME(dir
, x
, vmu
->mailbox
, vmu
->context
, dir
, dest
, sfn
, dfn
);
3175 ast_unlock_path(dir
);
3181 static int say_and_wait(struct ast_channel
*chan
, int num
, const char *language
)
3184 d
= ast_say_number(chan
, num
, AST_DIGIT_ANY
, language
, (char *) NULL
);
3188 static int save_to_folder(struct ast_vm_user
*vmu
, struct vm_state
*vms
, int msg
, int box
)
3191 /* we must use mbox(x) folder names, and copy the message there */
3197 /* if save to Old folder, just leave in INBOX */
3198 if (box
== 1) return 10;
3199 /* get the real IMAP message number for this message */
3200 snprintf(sequence
, sizeof(sequence
), "%ld", vms
->msgArray
[msg
]);
3201 imap_mailbox_name(dbox
, sizeof(dbox
), vms
, box
, 1);
3202 if(option_debug
> 2)
3203 ast_log(LOG_DEBUG
, "Copying sequence %s to mailbox %s\n",sequence
,dbox
);
3204 res
= mail_copy(vms
->mailstream
,sequence
,dbox
);
3205 if (res
== 1) return 0;
3208 char *dir
= vms
->curdir
;
3209 char *username
= vms
->username
;
3210 char *context
= vmu
->context
;
3213 char ddir
[PATH_MAX
];
3214 const char *dbox
= mbox(box
);
3216 make_file(sfn
, sizeof(sfn
), dir
, msg
);
3217 create_dirpath(ddir
, sizeof(ddir
), context
, username
, dbox
);
3219 if (vm_lock_path(ddir
))
3220 return ERROR_LOCK_PATH
;
3222 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
3223 make_file(dfn
, sizeof(dfn
), ddir
, x
);
3224 if (!EXISTS(ddir
, x
, dfn
, NULL
))
3227 if (x
>= vmu
->maxmsg
) {
3228 ast_unlock_path(ddir
);
3231 if (strcmp(sfn
, dfn
)) {
3232 COPY(dir
, msg
, ddir
, x
, username
, context
, sfn
, dfn
);
3234 ast_unlock_path(ddir
);
3239 static int adsi_logo(unsigned char *buf
)
3242 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_CENT
, 0, "Comedian Mail", "");
3243 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_CENT
, 0, "(C)2002-2006 Digium, Inc.", "");
3247 static int adsi_load_vmail(struct ast_channel
*chan
, int *useadsi
)
3249 unsigned char buf
[256];
3255 bytes
+= ast_adsi_data_mode(buf
+ bytes
);
3256 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3259 bytes
+= adsi_logo(buf
);
3260 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Downloading Scripts", "");
3262 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " .", "");
3264 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3265 bytes
+= ast_adsi_data_mode(buf
+ bytes
);
3266 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3268 if (ast_adsi_begin_download(chan
, addesc
, adsifdn
, adsisec
, adsiver
)) {
3270 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Load Cancelled.", "");
3271 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "ADSI Unavailable", "");
3272 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3273 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3274 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3281 bytes
+= ast_adsi_logo(buf
);
3282 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Downloading Scripts", "");
3283 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ..", "");
3284 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3285 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3288 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 0, "Listen", "Listen", "1", 1);
3289 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 1, "Folder", "Folder", "2", 1);
3290 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 2, "Advanced", "Advnced", "3", 1);
3291 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 3, "Options", "Options", "0", 1);
3292 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 4, "Help", "Help", "*", 1);
3293 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 5, "Exit", "Exit", "#", 1);
3294 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3297 /* Add another dot */
3299 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ...", "");
3300 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3302 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3303 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3307 /* These buttons we load but don't use yet */
3308 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 6, "Previous", "Prev", "4", 1);
3309 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 8, "Repeat", "Repeat", "5", 1);
3310 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 7, "Delete", "Delete", "7", 1);
3311 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 9, "Next", "Next", "6", 1);
3312 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 10, "Save", "Save", "9", 1);
3313 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 11, "Undelete", "Restore", "7", 1);
3314 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3317 /* Add another dot */
3319 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " ....", "");
3320 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3321 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3326 snprintf(num
, sizeof(num
), "%d", x
);
3327 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 12 + x
, mbox(x
), mbox(x
), num
, 1);
3329 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 12 + 5, "Cancel", "Cancel", "#", 1);
3330 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3333 /* Add another dot */
3335 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, " .....", "");
3336 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3337 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3340 if (ast_adsi_end_download(chan
)) {
3342 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Download Unsuccessful.", "");
3343 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "ADSI Unavailable", "");
3344 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3345 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3346 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3350 bytes
+= ast_adsi_download_disconnect(buf
+ bytes
);
3351 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3352 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
);
3355 ast_log(LOG_DEBUG
, "Done downloading scripts...\n");
3360 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, " ......", "");
3361 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3364 ast_log(LOG_DEBUG
, "Restarting session...\n");
3367 /* Load the session now */
3368 if (ast_adsi_load_session(chan
, adsifdn
, adsiver
, 1) == 1) {
3370 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Scripts Loaded!", "");
3372 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Load Failed!", "");
3374 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3378 static void adsi_begin(struct ast_channel
*chan
, int *useadsi
)
3381 if (!ast_adsi_available(chan
))
3383 x
= ast_adsi_load_session(chan
, adsifdn
, adsiver
, 1);
3387 if (adsi_load_vmail(chan
, useadsi
)) {
3388 ast_log(LOG_WARNING
, "Unable to upload voicemail scripts\n");
3395 static void adsi_login(struct ast_channel
*chan
)
3397 unsigned char buf
[256];
3399 unsigned char keys
[8];
3401 if (!ast_adsi_available(chan
))
3406 /* Set one key for next */
3407 keys
[3] = ADSI_KEY_APPS
+ 3;
3409 bytes
+= adsi_logo(buf
+ bytes
);
3410 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, " ", "");
3411 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, " ", "");
3412 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3413 bytes
+= ast_adsi_input_format(buf
+ bytes
, 1, ADSI_DIR_FROM_LEFT
, 0, "Mailbox: ******", "");
3414 bytes
+= ast_adsi_input_control(buf
+ bytes
, ADSI_COMM_PAGE
, 4, 1, 1, ADSI_JUST_LEFT
);
3415 bytes
+= ast_adsi_load_soft_key(buf
+ bytes
, ADSI_KEY_APPS
+ 3, "Enter", "Enter", "#", 1);
3416 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3417 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3418 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3421 static void adsi_password(struct ast_channel
*chan
)
3423 unsigned char buf
[256];
3425 unsigned char keys
[8];
3427 if (!ast_adsi_available(chan
))
3432 /* Set one key for next */
3433 keys
[3] = ADSI_KEY_APPS
+ 3;
3435 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3436 bytes
+= ast_adsi_input_format(buf
+ bytes
, 1, ADSI_DIR_FROM_LEFT
, 0, "Password: ******", "");
3437 bytes
+= ast_adsi_input_control(buf
+ bytes
, ADSI_COMM_PAGE
, 4, 0, 1, ADSI_JUST_LEFT
);
3438 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3439 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3440 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3443 static void adsi_folders(struct ast_channel
*chan
, int start
, char *label
)
3445 unsigned char buf
[256];
3447 unsigned char keys
[8];
3450 if (!ast_adsi_available(chan
))
3454 y
= ADSI_KEY_APPS
+ 12 + start
+ x
;
3455 if (y
> ADSI_KEY_APPS
+ 12 + 4)
3457 keys
[x
] = ADSI_KEY_SKT
| y
;
3459 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 17);
3463 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_CENT
, 0, label
, "");
3464 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_CENT
, 0, " ", "");
3465 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3466 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3467 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3469 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3472 static void adsi_message(struct ast_channel
*chan
, struct vm_state
*vms
)
3475 unsigned char buf
[256];
3476 char buf1
[256], buf2
[256];
3482 char datetime
[21]="";
3485 unsigned char keys
[8];
3489 if (!ast_adsi_available(chan
))
3492 /* Retrieve important info */
3493 snprintf(fn2
, sizeof(fn2
), "%s.txt", vms
->fn
);
3494 f
= fopen(fn2
, "r");
3497 fgets((char *)buf
, sizeof(buf
), f
);
3500 stringp
= (char *)buf
;
3501 strsep(&stringp
, "=");
3502 val
= strsep(&stringp
, "=");
3503 if (!ast_strlen_zero(val
)) {
3504 if (!strcmp((char *)buf
, "callerid"))
3505 ast_copy_string(cid
, val
, sizeof(cid
));
3506 if (!strcmp((char *)buf
, "origdate"))
3507 ast_copy_string(datetime
, val
, sizeof(datetime
));
3513 /* New meaning for keys */
3515 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 6 + x
);
3520 /* No prev key, provide "Folder" instead */
3521 keys
[0] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3523 if (vms
->curmsg
>= vms
->lastmsg
) {
3524 /* If last message ... */
3526 /* but not only message, provide "Folder" instead */
3527 keys
[3] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3528 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3531 /* Otherwise if only message, leave blank */
3536 if (!ast_strlen_zero(cid
)) {
3537 ast_callerid_parse(cid
, &name
, &num
);
3541 name
= "Unknown Caller";
3543 /* If deleted, show "undeleted" */
3545 if (vms
->deleted
[vms
->curmsg
])
3546 keys
[1] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 11);
3549 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 5);
3550 snprintf(buf1
, sizeof(buf1
), "%s%s", vms
->curbox
,
3551 strcasecmp(vms
->curbox
, "INBOX") ? " Messages" : "");
3552 snprintf(buf2
, sizeof(buf2
), "Message %d of %d", vms
->curmsg
+ 1, vms
->lastmsg
+ 1);
3554 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3555 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3556 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, name
, "");
3557 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_LEFT
, 0, datetime
, "");
3558 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3559 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3560 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3562 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3565 static void adsi_delete(struct ast_channel
*chan
, struct vm_state
*vms
)
3568 unsigned char buf
[256];
3569 unsigned char keys
[8];
3573 if (!ast_adsi_available(chan
))
3576 /* New meaning for keys */
3578 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 6 + x
);
3584 /* No prev key, provide "Folder" instead */
3585 keys
[0] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3587 if (vms
->curmsg
>= vms
->lastmsg
) {
3588 /* If last message ... */
3590 /* but not only message, provide "Folder" instead */
3591 keys
[3] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 1);
3593 /* Otherwise if only message, leave blank */
3598 /* If deleted, show "undeleted" */
3599 if (vms
->deleted
[vms
->curmsg
])
3600 keys
[1] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 11);
3603 keys
[5] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ 5);
3604 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3605 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3607 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3610 static void adsi_status(struct ast_channel
*chan
, struct vm_state
*vms
)
3612 unsigned char buf
[256] = "";
3613 char buf1
[256] = "", buf2
[256] = "";
3615 unsigned char keys
[8];
3618 char *newm
= (vms
->newmessages
== 1) ? "message" : "messages";
3619 char *oldm
= (vms
->oldmessages
== 1) ? "message" : "messages";
3620 if (!ast_adsi_available(chan
))
3622 if (vms
->newmessages
) {
3623 snprintf(buf1
, sizeof(buf1
), "You have %d new", vms
->newmessages
);
3624 if (vms
->oldmessages
) {
3625 strncat(buf1
, " and", sizeof(buf1
) - strlen(buf1
) - 1);
3626 snprintf(buf2
, sizeof(buf2
), "%d old %s.", vms
->oldmessages
, oldm
);
3628 snprintf(buf2
, sizeof(buf2
), "%s.", newm
);
3630 } else if (vms
->oldmessages
) {
3631 snprintf(buf1
, sizeof(buf1
), "You have %d old", vms
->oldmessages
);
3632 snprintf(buf2
, sizeof(buf2
), "%s.", oldm
);
3634 strcpy(buf1
, "You have no messages.");
3638 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3639 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3640 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3643 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ x
);
3647 /* Don't let them listen if there are none */
3648 if (vms
->lastmsg
< 0)
3650 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3652 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3654 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3657 static void adsi_status2(struct ast_channel
*chan
, struct vm_state
*vms
)
3659 unsigned char buf
[256] = "";
3660 char buf1
[256] = "", buf2
[256] = "";
3662 unsigned char keys
[8];
3665 char *mess
= (vms
->lastmsg
== 0) ? "message" : "messages";
3667 if (!ast_adsi_available(chan
))
3670 /* Original command keys */
3672 keys
[x
] = ADSI_KEY_SKT
| (ADSI_KEY_APPS
+ x
);
3677 if ((vms
->lastmsg
+ 1) < 1)
3680 snprintf(buf1
, sizeof(buf1
), "%s%s has", vms
->curbox
,
3681 strcasecmp(vms
->curbox
, "INBOX") ? " folder" : "");
3683 if (vms
->lastmsg
+ 1)
3684 snprintf(buf2
, sizeof(buf2
), "%d %s.", vms
->lastmsg
+ 1, mess
);
3686 strcpy(buf2
, "no messages.");
3687 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 1, ADSI_JUST_LEFT
, 0, buf1
, "");
3688 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 2, ADSI_JUST_LEFT
, 0, buf2
, "");
3689 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, "", "");
3690 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3691 bytes
+= ast_adsi_set_keys(buf
+ bytes
, keys
);
3693 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3695 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3700 static void adsi_clear(struct ast_channel *chan)
3704 if (!ast_adsi_available(chan))
3706 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3707 bytes += ast_adsi_voice_mode(buf + bytes, 0);
3709 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3713 static void adsi_goodbye(struct ast_channel
*chan
)
3715 unsigned char buf
[256];
3718 if (!ast_adsi_available(chan
))
3720 bytes
+= adsi_logo(buf
+ bytes
);
3721 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_LEFT
, 0, " ", "");
3722 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Goodbye", "");
3723 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
3724 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
3726 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
3729 /*--- get_folder: Folder menu ---*/
3730 /* Plays "press 1 for INBOX messages" etc
3731 Should possibly be internationalized
3733 static int get_folder(struct ast_channel
*chan
, int start
)
3738 d
= ast_play_and_wait(chan
, "vm-press"); /* "Press" */
3741 for (x
= start
; x
< 5; x
++) { /* For all folders */
3742 if ((d
= ast_say_number(chan
, x
, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
)))
3744 d
= ast_play_and_wait(chan
, "vm-for"); /* "for" */
3747 snprintf(fn
, sizeof(fn
), "vm-%s", mbox(x
)); /* Folder name */
3748 d
= vm_play_folder_name(chan
, fn
);
3751 d
= ast_waitfordigit(chan
, 500);
3755 d
= ast_play_and_wait(chan
, "vm-tocancel"); /* "or pound to cancel" */
3758 d
= ast_waitfordigit(chan
, 4000);
3762 static int get_folder2(struct ast_channel
*chan
, char *fn
, int start
)
3765 res
= ast_play_and_wait(chan
, fn
); /* Folder name */
3766 while (((res
< '0') || (res
> '9')) &&
3767 (res
!= '#') && (res
>= 0)) {
3768 res
= get_folder(chan
, 0);
3773 static int vm_forwardoptions(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *curdir
, int curmsg
, char *vmfmts
,
3774 char *context
, signed char record_gain
, long *duration
, struct vm_state
*vms
)
3778 signed char zero_gain
= 0;
3780 while ((cmd
>= 0) && (cmd
!= 't') && (cmd
!= '*')) {
3785 /* prepend a message to the current message, update the metadata and return */
3787 char msgfile
[PATH_MAX
];
3788 char textfile
[PATH_MAX
];
3789 int prepend_duration
= 0;
3790 struct ast_config
*msg_cfg
;
3791 const char *duration_str
;
3793 make_file(msgfile
, sizeof(msgfile
), curdir
, curmsg
);
3794 strcpy(textfile
, msgfile
);
3795 strncat(textfile
, ".txt", sizeof(textfile
) - 1);
3798 /* if we can't read the message metadata, stop now */
3799 if (!(msg_cfg
= ast_config_load(textfile
))) {
3805 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &record_gain
, sizeof(record_gain
), 0);
3807 cmd
= ast_play_and_prepend(chan
, NULL
, msgfile
, 0, vmfmts
, &prepend_duration
, 1, silencethreshold
, maxsilence
);
3809 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &zero_gain
, sizeof(zero_gain
), 0);
3812 if ((duration_str
= ast_variable_retrieve(msg_cfg
, "message", "duration")))
3813 *duration
= atoi(duration_str
);
3815 if (prepend_duration
) {
3816 struct ast_category
*msg_cat
;
3817 /* need enough space for a maximum-length message duration */
3818 char duration_str
[12];
3820 *duration
+= prepend_duration
;
3821 msg_cat
= ast_category_get(msg_cfg
, "message");
3822 snprintf(duration_str
, 11, "%ld", *duration
);
3823 if (!ast_variable_update(msg_cat
, "duration", duration_str
, NULL
, 0)) {
3824 config_text_file_save(textfile
, msg_cfg
, "app_voicemail");
3825 STORE(curdir
, vmu
->mailbox
, context
, curmsg
, chan
, vmu
, vmfmts
, *duration
, vms
);
3829 ast_config_destroy(msg_cfg
);
3840 cmd
= ast_play_and_wait(chan
,"vm-forwardoptions");
3841 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
3843 cmd
= ast_play_and_wait(chan
,"vm-starmain");
3844 /* "press star to return to the main menu" */
3846 cmd
= ast_waitfordigit(chan
,6000);
3853 if (cmd
== 't' || cmd
== 'S')
3858 static int notify_new_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, int msgnum
, long duration
, char *fmt
, char *cidnum
, char *cidname
)
3860 char todir
[PATH_MAX
], fn
[PATH_MAX
], ext_context
[PATH_MAX
], *stringp
;
3861 int newmsgs
= 0, oldmsgs
= 0;
3862 const char *category
= pbx_builtin_getvar_helper(chan
, "VM_CATEGORY");
3864 make_dir(todir
, sizeof(todir
), vmu
->context
, vmu
->mailbox
, "INBOX");
3865 make_file(fn
, sizeof(fn
), todir
, msgnum
);
3866 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", vmu
->mailbox
, vmu
->context
);
3868 if (!ast_strlen_zero(vmu
->attachfmt
)) {
3869 if (strstr(fmt
, vmu
->attachfmt
)) {
3870 fmt
= vmu
->attachfmt
;
3872 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
);
3876 /* Attach only the first format */
3877 fmt
= ast_strdupa(fmt
);
3879 strsep(&stringp
, "|");
3881 if (!ast_strlen_zero(vmu
->email
)) {
3882 int attach_user_voicemail
= ast_test_flag((&globalflags
), VM_ATTACH
);
3883 char *myserveremail
= serveremail
;
3884 attach_user_voicemail
= ast_test_flag(vmu
, VM_ATTACH
);
3885 if (!ast_strlen_zero(vmu
->serveremail
))
3886 myserveremail
= vmu
->serveremail
;
3888 if (attach_user_voicemail
)
3889 RETRIEVE(todir
, msgnum
);
3891 /*XXX possible imap issue, should category be NULL XXX*/
3892 sendmail(myserveremail
, vmu
, msgnum
, vmu
->context
, vmu
->mailbox
, cidnum
, cidname
, fn
, fmt
, duration
, attach_user_voicemail
, chan
, category
);
3894 if (attach_user_voicemail
)
3895 DISPOSE(todir
, msgnum
);
3898 if (!ast_strlen_zero(vmu
->pager
)) {
3899 char *myserveremail
= serveremail
;
3900 if (!ast_strlen_zero(vmu
->serveremail
))
3901 myserveremail
= vmu
->serveremail
;
3902 sendpage(myserveremail
, vmu
->pager
, msgnum
, vmu
->context
, vmu
->mailbox
, cidnum
, cidname
, duration
, vmu
, category
);
3905 if (ast_test_flag(vmu
, VM_DELETE
)) {
3906 DELETE(todir
, msgnum
, fn
);
3910 DELETE(todir
, msgnum
, fn
);
3912 /* Leave voicemail for someone */
3913 if (ast_app_has_voicemail(ext_context
, NULL
)) {
3914 ast_app_inboxcount(ext_context
, &newmsgs
, &oldmsgs
);
3916 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
);
3917 run_externnotify(vmu
->context
, vmu
->mailbox
);
3921 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
)
3925 char *header_content
;
3929 struct vm_state
*dstvms
;
3931 char username
[70]="";
3932 int res
= 0, cmd
= 0;
3933 struct ast_vm_user
*receiver
= NULL
, *vmtmp
;
3934 AST_LIST_HEAD_NOLOCK_STATIC(extensions
, ast_vm_user
);
3937 int saved_messages
= 0, found
= 0;
3938 int valid_extensions
= 0;
3942 if (vms
== NULL
) return -1;
3944 curmsg
= vms
->curmsg
;
3946 while (!res
&& !valid_extensions
) {
3947 int use_directory
= 0;
3948 if (ast_test_flag((&globalflags
), VM_DIRECFORWARD
)) {
3952 while ((cmd
>= 0) && !done
){
3969 /* Press 1 to enter an extension press 2 to use the directory */
3970 cmd
= ast_play_and_wait(chan
,"vm-forward");
3972 cmd
= ast_waitfordigit(chan
,3000);
3983 if (cmd
< 0 || cmd
== 't')
3987 if (use_directory
) {
3988 /* use app_directory */
3990 char old_context
[sizeof(chan
->context
)];
3991 char old_exten
[sizeof(chan
->exten
)];
3993 struct ast_app
* app
;
3996 app
= pbx_findapp("Directory");
3998 char vmcontext
[256];
3999 /* make backup copies */
4000 memcpy(old_context
, chan
->context
, sizeof(chan
->context
));
4001 memcpy(old_exten
, chan
->exten
, sizeof(chan
->exten
));
4002 old_priority
= chan
->priority
;
4004 /* call the the Directory, changes the channel */
4005 snprintf(vmcontext
, sizeof(vmcontext
), "%s||v", context
? context
: "default");
4006 res
= pbx_exec(chan
, app
, vmcontext
);
4008 ast_copy_string(username
, chan
->exten
, sizeof(username
));
4010 /* restore the old context, exten, and priority */
4011 memcpy(chan
->context
, old_context
, sizeof(chan
->context
));
4012 memcpy(chan
->exten
, old_exten
, sizeof(chan
->exten
));
4013 chan
->priority
= old_priority
;
4016 ast_log(LOG_WARNING
, "Could not find the Directory application, disabling directory_forward\n");
4017 ast_clear_flag((&globalflags
), VM_DIRECFORWARD
);
4020 /* Ask for an extension */
4021 res
= ast_streamfile(chan
, "vm-extension", chan
->language
); /* "extension" */
4024 if ((res
= ast_readstring(chan
, username
, sizeof(username
) - 1, 2000, 10000, "#") < 0))
4028 /* start all over if no username */
4029 if (ast_strlen_zero(username
))
4032 s
= strsep(&stringp
, "*");
4033 /* start optimistic */
4034 valid_extensions
= 1;
4036 /* Don't forward to ourselves. find_user is going to malloc since we have a NULL as first argument */
4037 if (strcmp(s
,sender
->mailbox
) && (receiver
= find_user(NULL
, context
, s
))) {
4038 AST_LIST_INSERT_HEAD(&extensions
, receiver
, list
);
4041 valid_extensions
= 0;
4044 s
= strsep(&stringp
, "*");
4046 /* break from the loop of reading the extensions */
4047 if (valid_extensions
)
4049 /* "I am sorry, that's not a valid extension. Please try again." */
4050 res
= ast_play_and_wait(chan
, "pbx-invalid");
4052 /* check if we're clear to proceed */
4053 if (AST_LIST_EMPTY(&extensions
) || !valid_extensions
)
4056 struct leave_vm_options leave_options
;
4057 char mailbox
[AST_MAX_EXTENSION
* 2 + 2];
4058 snprintf(mailbox
, sizeof(mailbox
), "%s@%s", username
, context
);
4060 /* Send VoiceMail */
4061 memset(&leave_options
, 0, sizeof(leave_options
));
4062 leave_options
.record_gain
= record_gain
;
4063 cmd
= leave_voicemail(chan
, mailbox
, &leave_options
);
4066 /* Forward VoiceMail */
4068 RETRIEVE(dir
, curmsg
);
4069 cmd
= vm_forwardoptions(chan
, sender
, dir
, curmsg
, vmfmts
, S_OR(context
, "default"), record_gain
, &duration
, vms
);
4071 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions
, vmtmp
, list
) {
4073 char *myserveremail
;
4074 int attach_user_voicemail
;
4075 /* Need to get message content */
4076 if(option_debug
> 2)
4077 ast_log (LOG_DEBUG
,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
4078 if (vms
->msgArray
[vms
->curmsg
] == 0) {
4079 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
4083 /* This will only work for new messages... */
4084 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
4085 /* empty string means no valid header */
4086 if (ast_strlen_zero(header_content
)) {
4087 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
4090 /* Get header info needed by sendmail */
4091 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Duration:");
4093 duration
= atoi(temp
);
4097 /* Attach only the first format */
4098 fmt
= ast_strdupa(fmt
);
4101 strsep(&stringp
, "|");
4103 ast_log (LOG_ERROR
,"audio format not set. Default to WAV\n");
4106 if (!strcasecmp(fmt
, "wav49"))
4108 if(option_debug
> 2)
4109 ast_log (LOG_DEBUG
,"**** format set to %s, vmfmts set to %s\n",fmt
,vmfmts
);
4110 /* ast_copy_string(fmt, vmfmts, sizeof(fmt));*/
4111 /* if (!ast_strlen_zero(fmt)) { */
4112 snprintf(todir
, sizeof(todir
), "%s%s/%s/tmp", VM_SPOOL_DIR
, vmtmp
->context
, vmtmp
->mailbox
);
4113 make_gsm_file(vms
->fn
, sizeof(vms
->fn
), vms
->imapuser
, todir
, vms
->curmsg
);
4114 if(option_debug
> 2)
4115 ast_log (LOG_DEBUG
,"Before mail_fetchstructure, message number is %ld, filename is:%s\n",vms
->msgArray
[vms
->curmsg
], vms
->fn
);
4116 /*mail_fetchstructure (mailstream, vmArray[0], &body); */
4117 mail_fetchstructure (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
], &body
);
4118 save_body(body
,vms
,"3","gsm");
4119 /* should not assume "fmt" here! */
4120 save_body(body
,vms
,"2",fmt
);
4122 /* get destination mailbox */
4123 dstvms
= get_vm_state_by_mailbox(vmtmp
->mailbox
,0);
4125 init_mailstream(dstvms
, 0);
4126 if (!dstvms
->mailstream
) {
4127 ast_log (LOG_ERROR
,"IMAP mailstream for %s is NULL\n",vmtmp
->mailbox
);
4129 STORE(todir
, vmtmp
->mailbox
, vmtmp
->context
, dstvms
->curmsg
, chan
, vmtmp
, fmt
, duration
, dstvms
);
4130 run_externnotify(vmtmp
->context
, vmtmp
->mailbox
);
4133 ast_log (LOG_ERROR
,"Could not find state information for mailbox %s\n",vmtmp
->mailbox
);
4136 myserveremail
= serveremail
;
4137 if (!ast_strlen_zero(vmtmp
->serveremail
))
4138 myserveremail
= vmtmp
->serveremail
;
4139 attach_user_voicemail
= ast_test_flag((&globalflags
), VM_ATTACH
);
4140 attach_user_voicemail
= ast_test_flag(vmtmp
, VM_ATTACH
);
4141 /* NULL category for IMAP storage */
4142 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
);
4144 copy_message(chan
, sender
, 0, curmsg
, duration
, vmtmp
, fmt
, dir
);
4147 AST_LIST_REMOVE_CURRENT(&extensions
, list
);
4152 AST_LIST_TRAVERSE_SAFE_END
;
4153 if (saved_messages
> 0) {
4154 /* give confirmation that the message was saved */
4155 /* commented out since we can't forward batches yet
4156 if (saved_messages == 1)
4157 res = ast_play_and_wait(chan, "vm-message");
4159 res = ast_play_and_wait(chan, "vm-messages");
4161 res = ast_play_and_wait(chan, "vm-saved"); */
4162 res
= ast_play_and_wait(chan
, "vm-msgsaved");
4167 /* If anything failed above, we still have this list to free */
4168 while ((vmtmp
= AST_LIST_REMOVE_HEAD(&extensions
, list
)))
4170 return res
? res
: cmd
;
4173 static int wait_file2(struct ast_channel
*chan
, struct vm_state
*vms
, char *file
)
4176 if ((res
= ast_stream_and_wait(chan
, file
, chan
->language
, AST_DIGIT_ANY
)) < 0)
4177 ast_log(LOG_WARNING
, "Unable to play message %s\n", file
);
4181 static int wait_file(struct ast_channel
*chan
, struct vm_state
*vms
, char *file
)
4183 return ast_control_streamfile(chan
, file
, "#", "*", "1456789", "0", "2", skipms
);
4186 static int play_message_category(struct ast_channel
*chan
, const char *category
)
4190 if (!ast_strlen_zero(category
))
4191 res
= ast_play_and_wait(chan
, category
);
4194 ast_log(LOG_WARNING
, "No sound file for category '%s' was found.\n", category
);
4201 static int play_message_datetime(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, const char *origtime
, const char *filename
)
4204 struct vm_zone
*the_zone
= NULL
;
4207 if (ast_get_time_t(origtime
, &t
, 0, NULL
)) {
4208 ast_log(LOG_WARNING
, "Couldn't find origtime in %s\n", filename
);
4212 /* Does this user have a timezone specified? */
4213 if (!ast_strlen_zero(vmu
->zonetag
)) {
4214 /* Find the zone in the list */
4216 AST_LIST_LOCK(&zones
);
4217 AST_LIST_TRAVERSE(&zones
, z
, list
) {
4218 if (!strcmp(z
->name
, vmu
->zonetag
)) {
4223 AST_LIST_UNLOCK(&zones
);
4226 /* No internal variable parsing for now, so we'll comment it out for the time being */
4228 /* Set the DIFF_* variables */
4229 ast_localtime(&t
, &time_now
, NULL
);
4230 tv_now
= ast_tvnow();
4231 tnow
= tv_now
.tv_sec
;
4232 ast_localtime(&tnow
, &time_then
, NULL
);
4234 /* Day difference */
4235 if (time_now
.tm_year
== time_then
.tm_year
)
4236 snprintf(temp
,sizeof(temp
),"%d",time_now
.tm_yday
);
4238 snprintf(temp
,sizeof(temp
),"%d",(time_now
.tm_year
- time_then
.tm_year
) * 365 + (time_now
.tm_yday
- time_then
.tm_yday
));
4239 pbx_builtin_setvar_helper(chan
, "DIFF_DAY", temp
);
4241 /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
4244 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, the_zone
->msg_format
, the_zone
->timezone
);
4245 else if (!strcasecmp(chan
->language
,"pl")) /* POLISH syntax */
4246 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q HM", NULL
);
4247 else if (!strcasecmp(chan
->language
,"se")) /* SWEDISH syntax */
4248 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' dB 'digits/at' k 'and' M", NULL
);
4249 else if (!strcasecmp(chan
->language
,"no")) /* NORWEGIAN syntax */
4250 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q 'digits/at' HM", NULL
);
4251 else if (!strcasecmp(chan
->language
,"de")) /* GERMAN syntax */
4252 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' Q 'digits/at' HM", NULL
);
4253 else if (!strcasecmp(chan
->language
,"nl")) /* DUTCH syntax */
4254 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q 'digits/nl-om' HM", NULL
);
4255 else if (!strcasecmp(chan
->language
,"it")) /* ITALIAN syntax */
4256 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
);
4257 else if (!strcasecmp(chan
->language
,"gr"))
4258 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q H 'digits/kai' M ", NULL
);
4259 else if (!strcasecmp(chan
->language
,"pt_BR"))
4260 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
);
4262 res
= ast_say_date_with_format(chan
, t
, AST_DIGIT_ANY
, chan
->language
, "'vm-received' q 'digits/at' IMp", NULL
);
4264 pbx_builtin_setvar_helper(chan
, "DIFF_DAY", NULL
);
4271 static int play_message_callerid(struct ast_channel
*chan
, struct vm_state
*vms
, char *cid
, const char *context
, int callback
)
4275 char *callerid
, *name
;
4276 char prefile
[PATH_MAX
] = "";
4279 /* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
4280 /* 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 */
4281 if ((cid
== NULL
)||(context
== NULL
))
4284 /* Strip off caller ID number from name */
4285 if (option_debug
> 2)
4286 ast_log(LOG_DEBUG
, "VM-CID: composite caller ID received: %s, context: %s\n", cid
, context
);
4287 ast_callerid_parse(cid
, &name
, &callerid
);
4288 if ((!ast_strlen_zero(callerid
)) && strcmp(callerid
, "Unknown")) {
4289 /* Check for internal contexts and only */
4290 /* say extension when the call didn't come from an internal context in the list */
4291 for (i
= 0 ; i
< MAX_NUM_CID_CONTEXTS
; i
++){
4292 if (option_debug
> 2)
4293 ast_log(LOG_DEBUG
, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts
[i
]);
4294 if ((strcmp(cidinternalcontexts
[i
], context
) == 0))
4297 if (i
!= MAX_NUM_CID_CONTEXTS
){ /* internal context? */
4299 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, context
, callerid
);
4300 if (!ast_strlen_zero(prefile
)) {
4301 /* See if we can find a recorded name for this person instead of their extension number */
4302 if (ast_fileexists(prefile
, NULL
, NULL
) > 0) {
4303 if (option_verbose
> 2)
4304 ast_verbose(VERBOSE_PREFIX_3
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid
);
4306 res
= wait_file2(chan
, vms
, "vm-from");
4307 res
= ast_stream_and_wait(chan
, prefile
, chan
->language
, "");
4309 if (option_verbose
> 2)
4310 ast_verbose(VERBOSE_PREFIX_3
"Playing envelope info: message from '%s'\n", callerid
);
4311 /* BB: Say "from extension" as one saying to sound smoother */
4313 res
= wait_file2(chan
, vms
, "vm-from-extension");
4314 res
= ast_say_digit_str(chan
, callerid
, "", chan
->language
);
4321 if (option_debug
> 2)
4322 ast_log(LOG_DEBUG
, "VM-CID: Numeric caller id: (%s)\n",callerid
);
4323 /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
4325 res
= wait_file2(chan
, vms
, "vm-from-phonenumber");
4326 res
= ast_say_digit_str(chan
, callerid
, AST_DIGIT_ANY
, chan
->language
);
4329 /* Number unknown */
4331 ast_log(LOG_DEBUG
, "VM-CID: From an unknown number\n");
4332 /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
4333 res
= wait_file2(chan
, vms
, "vm-unknown-caller");
4338 static int play_message_duration(struct ast_channel
*chan
, struct vm_state
*vms
, const char *duration
, int minduration
)
4343 /* Verify that we have a duration for the message */
4344 if (duration
== NULL
)
4347 /* Convert from seconds to minutes */
4348 durations
=atoi(duration
);
4349 durationm
=(durations
/ 60);
4351 if (option_debug
> 2)
4352 ast_log(LOG_DEBUG
, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations
, durationm
);
4354 if ((!res
) && (durationm
>= minduration
)) {
4355 res
= wait_file2(chan
, vms
, "vm-duration");
4358 if (!strcasecmp(chan
->language
, "pl")) {
4359 div_t num
= div(durationm
, 10);
4361 if (durationm
== 1) {
4362 res
= ast_play_and_wait(chan
, "digits/1z");
4363 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-ta");
4364 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
4367 res
= ast_play_and_wait(chan
, "digits/2-ie");
4369 res
= say_and_wait(chan
, durationm
- 2 , chan
->language
);
4370 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
4373 res
= say_and_wait(chan
, durationm
, chan
->language
);
4375 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-ty");
4377 res
= say_and_wait(chan
, durationm
, chan
->language
);
4378 res
= res
? res
: ast_play_and_wait(chan
, "vm-minute-t");
4380 /* DEFAULT syntax */
4382 res
= ast_say_number(chan
, durationm
, AST_DIGIT_ANY
, chan
->language
, NULL
);
4383 res
= wait_file2(chan
, vms
, "vm-minutes");
4390 static int play_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
4393 char *header_content
;
4399 char todir
[PATH_MAX
];
4401 char *attachedfilefmt
;
4405 if(option_debug
> 2)
4406 ast_log (LOG_DEBUG
,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
4407 if (vms
->msgArray
[vms
->curmsg
] == 0) {
4408 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
4412 /* This will only work for new messages... */
4413 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
4414 /* empty string means no valid header */
4415 if (ast_strlen_zero(header_content
)) {
4416 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
4419 snprintf(todir
, sizeof(todir
), "%s%s/%s/tmp", VM_SPOOL_DIR
, vmu
->context
, vmu
->mailbox
);
4420 make_gsm_file(vms
->fn
, sizeof(vms
->fn
), vms
->imapuser
, todir
, vms
->curmsg
);
4422 mail_fetchstructure (vms
->mailstream
,vms
->msgArray
[vms
->curmsg
],&body
);
4424 /* We have the body, now we extract the file name of the first attachment. */
4425 if (body
->nested
.part
&& body
->nested
.part
->next
&& body
->nested
.part
->next
->body
.parameter
->value
) {
4426 attachedfilefmt
= ast_strdupa(body
->nested
.part
->next
->body
.parameter
->value
);
4428 ast_log(LOG_ERROR
, "There is no file attached to this IMAP message.\n");
4432 /* Find the format of the attached file */
4434 strsep(&attachedfilefmt
, ".");
4435 if (!attachedfilefmt
) {
4436 ast_log(LOG_ERROR
, "File format could not be obtained from IMAP message attachment\n");
4439 save_body(body
, vms
, "2", attachedfilefmt
);
4441 adsi_message(chan
, vms
);
4443 res
= wait_file2(chan
, vms
, "vm-first"); /* "First" */
4444 else if (vms
->curmsg
== vms
->lastmsg
)
4445 res
= wait_file2(chan
, vms
, "vm-last"); /* "last" */
4447 res
= wait_file2(chan
, vms
, "vm-message"); /* "message" */
4448 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4450 res
= ast_say_number(chan
, vms
->curmsg
+ 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
4454 /* Get info from headers!! */
4455 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Caller-ID-Num:");
4458 ast_copy_string(cid
, temp
, sizeof(cid
));
4462 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Context:");
4465 ast_copy_string(context
, temp
, sizeof(context
));
4469 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Orig-time:");
4472 ast_copy_string(origtime
, temp
, sizeof(origtime
));
4476 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Duration:");
4479 ast_copy_string(duration
,temp
, sizeof(duration
));
4483 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Category:");
4486 ast_copy_string(category
,temp
, sizeof(category
));
4490 /*if (!strncasecmp("macro",context,5)) Macro names in contexts are useless for our needs */
4491 /* context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); */
4495 if ((!res
) && !ast_strlen_zero(category
)) {
4496 res
= play_message_category(chan
, category
);
4499 if ((!res
) && (ast_test_flag(vmu
, VM_ENVELOPE
)) && origtime
[0] != '\0')
4500 res
= play_message_datetime(chan
, vmu
, origtime
, "IMAP_STORAGE");
4501 if ((!res
) && (ast_test_flag(vmu
, VM_SAYCID
)) && cid
[0] !='\0' && context
[0] !='\0')
4502 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
4504 if ((!res
) && (ast_test_flag(vmu
, VM_SAYDURATION
)) && duration
[0] != '\0')
4505 res
= play_message_duration(chan
, vms
, duration
, vmu
->saydurationm
);
4507 /* Allow pressing '1' to skip envelope / callerid */
4511 /*ast_config_destroy(msg_cfg);*/
4515 vms
->heard
[vms
->curmsg
] = 1;
4516 res
= wait_file(chan
, vms
, vms
->fn
);
4518 DISPOSE(vms
->curdir
, vms
->curmsg
);
4519 DELETE(0, 0, vms
->fn
);
4523 static int play_message(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
4526 char filename
[256], *cid
;
4527 const char *origtime
, *context
, *category
, *duration
;
4528 struct ast_config
*msg_cfg
;
4531 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, vms
->curmsg
);
4532 adsi_message(chan
, vms
);
4534 res
= wait_file2(chan
, vms
, "vm-first"); /* "First" */
4535 else if (vms
->curmsg
== vms
->lastmsg
)
4536 res
= wait_file2(chan
, vms
, "vm-last"); /* "last" */
4539 if (!strcasecmp(chan
->language
, "pl")) {
4540 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4543 ten
= (vms
->curmsg
+ 1) / 10;
4544 one
= (vms
->curmsg
+ 1) % 10;
4546 if (vms
->curmsg
< 20) {
4547 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", vms
->curmsg
+ 1);
4548 res
= wait_file2(chan
, vms
, nextmsg
);
4550 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", ten
* 10);
4551 res
= wait_file2(chan
, vms
, nextmsg
);
4554 snprintf(nextmsg
, sizeof(nextmsg
), "digits/n-%d", one
);
4555 res
= wait_file2(chan
, vms
, nextmsg
);
4561 res
= wait_file2(chan
, vms
, "vm-message");
4563 if (!strcasecmp(chan
->language
, "se")) /* SWEDISH syntax */
4564 res
= wait_file2(chan
, vms
, "vm-meddelandet"); /* "message" */
4565 else /* DEFAULT syntax */
4566 res
= wait_file2(chan
, vms
, "vm-message");
4567 if (vms
->curmsg
&& (vms
->curmsg
!= vms
->lastmsg
)) {
4569 res
= ast_say_number(chan
, vms
->curmsg
+ 1, AST_DIGIT_ANY
, chan
->language
, NULL
);
4574 /* Retrieve info from VM attribute file */
4575 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
4576 snprintf(filename
, sizeof(filename
), "%s.txt", vms
->fn2
);
4577 RETRIEVE(vms
->curdir
, vms
->curmsg
);
4578 msg_cfg
= ast_config_load(filename
);
4580 ast_log(LOG_WARNING
, "No message attribute file?!! (%s)\n", filename
);
4584 if (!(origtime
= ast_variable_retrieve(msg_cfg
, "message", "origtime"))) {
4585 ast_log(LOG_WARNING
, "No origtime?!\n");
4586 DISPOSE(vms
->curdir
, vms
->curmsg
);
4587 ast_config_destroy(msg_cfg
);
4591 cid
= ast_strdupa(ast_variable_retrieve(msg_cfg
, "message", "callerid"));
4592 duration
= ast_variable_retrieve(msg_cfg
, "message", "duration");
4593 category
= ast_variable_retrieve(msg_cfg
, "message", "category");
4595 context
= ast_variable_retrieve(msg_cfg
, "message", "context");
4596 if (!strncasecmp("macro",context
,5)) /* Macro names in contexts are useless for our needs */
4597 context
= ast_variable_retrieve(msg_cfg
, "message","macrocontext");
4599 res
= play_message_category(chan
, category
);
4600 if ((!res
) && (ast_test_flag(vmu
, VM_ENVELOPE
)))
4601 res
= play_message_datetime(chan
, vmu
, origtime
, filename
);
4602 if ((!res
) && (ast_test_flag(vmu
, VM_SAYCID
)))
4603 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
4604 if ((!res
) && (ast_test_flag(vmu
, VM_SAYDURATION
)))
4605 res
= play_message_duration(chan
, vms
, duration
, vmu
->saydurationm
);
4606 /* Allow pressing '1' to skip envelope / callerid */
4609 ast_config_destroy(msg_cfg
);
4612 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, vms
->curmsg
);
4613 vms
->heard
[vms
->curmsg
] = 1;
4614 res
= wait_file(chan
, vms
, vms
->fn
);
4616 DISPOSE(vms
->curdir
, vms
->curmsg
);
4622 static void imap_mailbox_name(char *spec
, size_t len
, struct vm_state
*vms
, int box
, int use_folder
)
4624 char tmp
[256], *t
= tmp
;
4625 size_t left
= sizeof(tmp
);
4628 ast_copy_string(vms
->curbox
, mbox(0), sizeof(vms
->curbox
));
4629 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", mbox(1));
4631 ast_copy_string(vms
->curbox
, mbox(box
), sizeof(vms
->curbox
));
4632 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", vms
->curbox
);
4635 /* Build up server information */
4636 ast_build_string(&t
, &left
, "{%s:%s/imap", imapserver
, imapport
);
4638 /* Add authentication user if present */
4639 if (!ast_strlen_zero(authuser
))
4640 ast_build_string(&t
, &left
, "/authuser=%s", authuser
);
4642 /* Add flags if present */
4643 if (!ast_strlen_zero(imapflags
))
4644 ast_build_string(&t
, &left
, "/%s", imapflags
);
4646 /* End with username */
4647 ast_build_string(&t
, &left
, "/user=%s}", vms
->imapuser
);
4649 if(box
== 0 || box
== 1)
4650 snprintf(spec
, len
, "%s%s", tmp
, use_folder
? imapfolder
: "INBOX");
4652 snprintf(spec
, len
, "%s%s%c%s", tmp
, imapfolder
, delimiter
, mbox(box
));
4655 static int init_mailstream(struct vm_state
*vms
, int box
)
4657 MAILSTREAM
*stream
= NIL
;
4662 ast_log (LOG_ERROR
,"vm_state is NULL!\n");
4665 if(option_debug
> 2)
4666 ast_log (LOG_DEBUG
,"vm_state user is:%s\n",vms
->imapuser
);
4667 if (vms
->mailstream
== NIL
|| !vms
->mailstream
) {
4669 ast_log (LOG_DEBUG
,"mailstream not set.\n");
4671 stream
= vms
->mailstream
;
4673 /* debug = T; user wants protocol telemetry? */
4674 debug
= NIL
; /* NO protocol telemetry? */
4676 if (delimiter
== '\0') { /* did not probe the server yet */
4678 #include "linkage.c"
4679 /* Connect to INBOX first to get folders delimiter */
4680 imap_mailbox_name(tmp
, sizeof(tmp
), vms
, 0, 1);
4681 stream
= mail_open (stream
, tmp
, debug
? OP_DEBUG
: NIL
);
4682 if (stream
== NIL
) {
4683 ast_log (LOG_ERROR
, "Can't connect to imap server %s\n", tmp
);
4686 get_mailbox_delimiter(stream
);
4687 /* update delimiter in imapfolder */
4688 for(cp
= imapfolder
; *cp
; cp
++)
4692 /* Now connect to the target folder */
4693 imap_mailbox_name(tmp
, sizeof(tmp
), vms
, box
, 1);
4694 if(option_debug
> 2)
4695 ast_log (LOG_DEBUG
,"Before mail_open, server: %s, box:%d\n", tmp
, box
);
4696 vms
->mailstream
= mail_open (stream
, tmp
, debug
? OP_DEBUG
: NIL
);
4697 if (vms
->mailstream
== NIL
) {
4704 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
, int box
)
4711 ast_copy_string(vms
->imapuser
,vmu
->imapuser
, sizeof(vms
->imapuser
));
4712 if(option_debug
> 2)
4713 ast_log(LOG_DEBUG
,"Before init_mailstream, user is %s\n",vmu
->imapuser
);
4714 ret
= init_mailstream(vms
, box
);
4715 if (ret
!= 0 || !vms
->mailstream
) {
4716 ast_log (LOG_ERROR
,"Could not initialize mailstream\n");
4720 pgm
= mail_newsearchpgm();
4722 /* Check IMAP folder for Asterisk messages only... */
4723 hdr
= mail_newsearchheader ("X-Asterisk-VM-Extension", vmu
->mailbox
);
4728 /* if box = 0, check for new, if box = 1, check for read */
4732 } else if (box
== 1) {
4737 vms
->vmArrayIndex
= 0;
4738 if(option_debug
> 2)
4739 ast_log(LOG_DEBUG
,"Before mail_search_full, user is %s\n",vmu
->imapuser
);
4740 mail_search_full (vms
->mailstream
, NULL
, pgm
, NIL
);
4743 vms
->lastmsg
= vms
->vmArrayIndex
- 1;
4745 mail_free_searchpgm(&pgm
);
4749 static int open_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
,int box
)
4752 int count_msg
, last_msg
;
4754 ast_copy_string(vms
->curbox
, mbox(box
), sizeof(vms
->curbox
));
4756 /* Rename the member vmbox HERE so that we don't try to return before
4757 * we know what's going on.
4759 snprintf(vms
->vmbox
, sizeof(vms
->vmbox
), "vm-%s", vms
->curbox
);
4761 /* Faster to make the directory than to check if it exists. */
4762 create_dirpath(vms
->curdir
, sizeof(vms
->curdir
), vmu
->context
, vms
->username
, vms
->curbox
);
4764 count_msg
= count_messages(vmu
, vms
->curdir
);
4768 vms
->lastmsg
= count_msg
- 1;
4771 The following test is needed in case sequencing gets messed up.
4772 There appears to be more than one way to mess up sequence, so
4773 we will not try to find all of the root causes--just fix it when
4777 last_msg
= last_message_index(vmu
, vms
->curdir
);
4780 else if (vms
->lastmsg
!= last_msg
)
4782 ast_log(LOG_NOTICE
, "Resequencing Mailbox: %s\n", vms
->curdir
);
4783 res
= resequence_mailbox(vmu
, vms
->curdir
);
4792 static int close_mailbox(struct vm_state
*vms
, struct ast_vm_user
*vmu
)
4795 #ifndef IMAP_STORAGE
4796 int res
= 0, nummsg
;
4799 if (vms
->lastmsg
<= -1)
4803 #ifndef IMAP_STORAGE
4804 /* Get the deleted messages fixed */
4805 if (vm_lock_path(vms
->curdir
))
4806 return ERROR_LOCK_PATH
;
4808 for (x
= 0; x
< vmu
->maxmsg
; x
++) {
4809 if (!vms
->deleted
[x
] && (strcasecmp(vms
->curbox
, "INBOX") || !vms
->heard
[x
])) {
4810 /* Save this message. It's not in INBOX or hasn't been heard */
4811 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, x
);
4812 if (!EXISTS(vms
->curdir
, x
, vms
->fn
, NULL
))
4815 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
4816 if (strcmp(vms
->fn
, vms
->fn2
)) {
4817 RENAME(vms
->curdir
, x
, vmu
->mailbox
,vmu
->context
, vms
->curdir
, vms
->curmsg
, vms
->fn
, vms
->fn2
);
4819 } else if (!strcasecmp(vms
->curbox
, "INBOX") && vms
->heard
[x
] && !vms
->deleted
[x
]) {
4820 /* Move to old folder before deleting */
4821 res
= save_to_folder(vmu
, vms
, x
, 1);
4822 if (res
== ERROR_LOCK_PATH
) {
4823 /* If save failed do not delete the message */
4824 vms
->deleted
[x
] = 0;
4831 /* Delete ALL remaining messages */
4833 for (x
= vms
->curmsg
+ 1; x
<= nummsg
; x
++) {
4834 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, x
);
4835 if (EXISTS(vms
->curdir
, x
, vms
->fn
, NULL
))
4836 DELETE(vms
->curdir
, x
, vms
->fn
);
4838 ast_unlock_path(vms
->curdir
);
4841 for (x
=0;x
< vmu
->maxmsg
;x
++) {
4842 if (vms
->deleted
[x
]) {
4843 if(option_debug
> 2)
4844 ast_log(LOG_DEBUG
,"IMAP delete of %d\n",x
);
4845 IMAP_DELETE(vms
->curdir
, x
, vms
->fn
, vms
);
4853 memset(vms
->deleted
, 0, vmu
->maxmsg
* sizeof(int));
4855 memset(vms
->heard
, 0, vmu
->maxmsg
* sizeof(int));
4860 /* In Greek even though we CAN use a syntax like "friends messages"
4861 * ("filika mynhmata") it is not elegant. This also goes for "work/family messages"
4862 * ("ergasiaka/oikogeniaka mynhmata"). Therefore it is better to use a reversed
4863 * syntax for the above three categories which is more elegant.
4866 static int vm_play_folder_name_gr(struct ast_channel
*chan
, char *mbox
)
4871 buf
= alloca(strlen(mbox
)+2);
4875 if (!strcasecmp(mbox
, "vm-INBOX") || !strcasecmp(mbox
, "vm-Old")){
4876 cmd
= ast_play_and_wait(chan
, buf
); /* "NEA / PALIA" */
4877 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages"); /* "messages" -> "MYNHMATA" */
4879 cmd
= ast_play_and_wait(chan
, "vm-messages"); /* "messages" -> "MYNHMATA" */
4880 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
4884 static int vm_play_folder_name_pl(struct ast_channel
*chan
, char *mbox
)
4888 if (!strcasecmp(mbox
, "vm-INBOX") || !strcasecmp(mbox
, "vm-Old")) {
4889 if (!strcasecmp(mbox
, "vm-INBOX"))
4890 cmd
= ast_play_and_wait(chan
, "vm-new-e");
4892 cmd
= ast_play_and_wait(chan
, "vm-old-e");
4893 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages");
4895 cmd
= ast_play_and_wait(chan
, "vm-messages");
4896 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
4900 static int vm_play_folder_name_ua(struct ast_channel
*chan
, char *mbox
)
4904 if (!strcasecmp(mbox
, "vm-Family") || !strcasecmp(mbox
, "vm-Friends") || !strcasecmp(mbox
, "vm-Work")){
4905 cmd
= ast_play_and_wait(chan
, "vm-messages");
4906 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
4908 cmd
= ast_play_and_wait(chan
, mbox
);
4909 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages");
4913 static int vm_play_folder_name(struct ast_channel
*chan
, char *mbox
)
4917 if (!strcasecmp(chan
->language
, "it") || !strcasecmp(chan
->language
, "es") || !strcasecmp(chan
->language
, "pt") || !strcasecmp(chan
->language
, "pt_BR")) { /* Italian, Spanish, French or Portuguese syntax */
4918 cmd
= ast_play_and_wait(chan
, "vm-messages"); /* "messages */
4919 return cmd
? cmd
: ast_play_and_wait(chan
, mbox
);
4920 } else if (!strcasecmp(chan
->language
, "gr")){
4921 return vm_play_folder_name_gr(chan
, mbox
);
4922 } else if (!strcasecmp(chan
->language
, "pl")){
4923 return vm_play_folder_name_pl(chan
, mbox
);
4924 } else if (!strcasecmp(chan
->language
, "ua")){ /* Ukrainian syntax */
4925 return vm_play_folder_name_ua(chan
, mbox
);
4926 } else { /* Default English */
4927 cmd
= ast_play_and_wait(chan
, mbox
);
4928 return cmd
? cmd
: ast_play_and_wait(chan
, "vm-messages"); /* "messages */
4933 In greek the plural for old/new is
4934 different so we need the following files
4935 We also need vm-denExeteMynhmata because
4936 this syntax is different.
4938 -> vm-Olds.wav : "Palia"
4939 -> vm-INBOXs.wav : "Nea"
4940 -> vm-denExeteMynhmata : "den exete mynhmata"
4944 static int vm_intro_gr(struct ast_channel
*chan
, struct vm_state
*vms
)
4948 if (vms
->newmessages
) {
4949 res
= ast_play_and_wait(chan
, "vm-youhave");
4951 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, NULL
);
4953 if ((vms
->newmessages
== 1)) {
4954 res
= ast_play_and_wait(chan
, "vm-INBOX");
4956 res
= ast_play_and_wait(chan
, "vm-message");
4958 res
= ast_play_and_wait(chan
, "vm-INBOXs");
4960 res
= ast_play_and_wait(chan
, "vm-messages");
4963 } else if (vms
->oldmessages
){
4964 res
= ast_play_and_wait(chan
, "vm-youhave");
4966 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, NULL
);
4967 if ((vms
->oldmessages
== 1)){
4968 res
= ast_play_and_wait(chan
, "vm-Old");
4970 res
= ast_play_and_wait(chan
, "vm-message");
4972 res
= ast_play_and_wait(chan
, "vm-Olds");
4974 res
= ast_play_and_wait(chan
, "vm-messages");
4976 } else if (!vms
->oldmessages
&& !vms
->newmessages
)
4977 res
= ast_play_and_wait(chan
, "vm-denExeteMynhmata");
4981 /* Default English syntax */
4982 static int vm_intro_en(struct ast_channel
*chan
, struct vm_state
*vms
)
4986 /* Introduce messages they have */
4987 res
= ast_play_and_wait(chan
, "vm-youhave");
4989 if (vms
->newmessages
) {
4990 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
4992 res
= ast_play_and_wait(chan
, "vm-INBOX");
4993 if (vms
->oldmessages
&& !res
)
4994 res
= ast_play_and_wait(chan
, "vm-and");
4996 if ((vms
->newmessages
== 1))
4997 res
= ast_play_and_wait(chan
, "vm-message");
4999 res
= ast_play_and_wait(chan
, "vm-messages");
5003 if (!res
&& vms
->oldmessages
) {
5004 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5006 res
= ast_play_and_wait(chan
, "vm-Old");
5008 if (vms
->oldmessages
== 1)
5009 res
= ast_play_and_wait(chan
, "vm-message");
5011 res
= ast_play_and_wait(chan
, "vm-messages");
5015 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5016 res
= ast_play_and_wait(chan
, "vm-no");
5018 res
= ast_play_and_wait(chan
, "vm-messages");
5025 /* ITALIAN syntax */
5026 static int vm_intro_it(struct ast_channel
*chan
, struct vm_state
*vms
)
5028 /* Introduce messages they have */
5030 if (!vms
->oldmessages
&& !vms
->newmessages
)
5031 res
= ast_play_and_wait(chan
, "vm-no") ||
5032 ast_play_and_wait(chan
, "vm-message");
5034 res
= ast_play_and_wait(chan
, "vm-youhave");
5035 if (!res
&& vms
->newmessages
) {
5036 res
= (vms
->newmessages
== 1) ?
5037 ast_play_and_wait(chan
, "digits/un") ||
5038 ast_play_and_wait(chan
, "vm-nuovo") ||
5039 ast_play_and_wait(chan
, "vm-message") :
5040 /* 2 or more new messages */
5041 say_and_wait(chan
, vms
->newmessages
, chan
->language
) ||
5042 ast_play_and_wait(chan
, "vm-nuovi") ||
5043 ast_play_and_wait(chan
, "vm-messages");
5044 if (!res
&& vms
->oldmessages
)
5045 res
= ast_play_and_wait(chan
, "vm-and");
5047 if (!res
&& vms
->oldmessages
) {
5048 res
= (vms
->oldmessages
== 1) ?
5049 ast_play_and_wait(chan
, "digits/un") ||
5050 ast_play_and_wait(chan
, "vm-vecchio") ||
5051 ast_play_and_wait(chan
, "vm-message") :
5052 /* 2 or more old messages */
5053 say_and_wait(chan
, vms
->oldmessages
, chan
->language
) ||
5054 ast_play_and_wait(chan
, "vm-vecchi") ||
5055 ast_play_and_wait(chan
, "vm-messages");
5057 return res
? -1 : 0;
5061 static int vm_intro_pl(struct ast_channel
*chan
, struct vm_state
*vms
)
5063 /* Introduce messages they have */
5067 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5068 res
= ast_play_and_wait(chan
, "vm-no");
5069 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5072 res
= ast_play_and_wait(chan
, "vm-youhave");
5075 if (vms
->newmessages
) {
5076 num
= div(vms
->newmessages
, 10);
5077 if (vms
->newmessages
== 1) {
5078 res
= ast_play_and_wait(chan
, "digits/1-a");
5079 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-a");
5080 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5081 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
5084 res
= ast_play_and_wait(chan
, "digits/2-ie");
5086 res
= say_and_wait(chan
, vms
->newmessages
- 2 , chan
->language
);
5087 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
5090 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5092 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-e");
5093 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5095 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5096 res
= res
? res
: ast_play_and_wait(chan
, "vm-new-ych");
5097 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5099 if (!res
&& vms
->oldmessages
)
5100 res
= ast_play_and_wait(chan
, "vm-and");
5102 if (!res
&& vms
->oldmessages
) {
5103 num
= div(vms
->oldmessages
, 10);
5104 if (vms
->oldmessages
== 1) {
5105 res
= ast_play_and_wait(chan
, "digits/1-a");
5106 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-a");
5107 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5108 } else if (num
.rem
> 1 && num
.rem
< 5 && num
.quot
!= 1) {
5111 res
= ast_play_and_wait(chan
, "digits/2-ie");
5113 res
= say_and_wait(chan
, vms
->oldmessages
- 2 , chan
->language
);
5114 res
= res
? res
: ast_play_and_wait(chan
, "digits/2-ie");
5117 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5119 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-e");
5120 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5122 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5123 res
= res
? res
: ast_play_and_wait(chan
, "vm-old-ych");
5124 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5131 /* SWEDISH syntax */
5132 static int vm_intro_se(struct ast_channel
*chan
, struct vm_state
*vms
)
5134 /* Introduce messages they have */
5137 res
= ast_play_and_wait(chan
, "vm-youhave");
5141 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5142 res
= ast_play_and_wait(chan
, "vm-no");
5143 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5147 if (vms
->newmessages
) {
5148 if ((vms
->newmessages
== 1)) {
5149 res
= ast_play_and_wait(chan
, "digits/ett");
5150 res
= res
? res
: ast_play_and_wait(chan
, "vm-nytt");
5151 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5153 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5154 res
= res
? res
: ast_play_and_wait(chan
, "vm-nya");
5155 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5157 if (!res
&& vms
->oldmessages
)
5158 res
= ast_play_and_wait(chan
, "vm-and");
5160 if (!res
&& vms
->oldmessages
) {
5161 if (vms
->oldmessages
== 1) {
5162 res
= ast_play_and_wait(chan
, "digits/ett");
5163 res
= res
? res
: ast_play_and_wait(chan
, "vm-gammalt");
5164 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5166 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5167 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamla");
5168 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5175 /* NORWEGIAN syntax */
5176 static int vm_intro_no(struct ast_channel
*chan
,struct vm_state
*vms
)
5178 /* Introduce messages they have */
5181 res
= ast_play_and_wait(chan
, "vm-youhave");
5185 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5186 res
= ast_play_and_wait(chan
, "vm-no");
5187 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5191 if (vms
->newmessages
) {
5192 if ((vms
->newmessages
== 1)) {
5193 res
= ast_play_and_wait(chan
, "digits/1");
5194 res
= res
? res
: ast_play_and_wait(chan
, "vm-ny");
5195 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5197 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5198 res
= res
? res
: ast_play_and_wait(chan
, "vm-nye");
5199 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5201 if (!res
&& vms
->oldmessages
)
5202 res
= ast_play_and_wait(chan
, "vm-and");
5204 if (!res
&& vms
->oldmessages
) {
5205 if (vms
->oldmessages
== 1) {
5206 res
= ast_play_and_wait(chan
, "digits/1");
5207 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamel");
5208 res
= res
? res
: ast_play_and_wait(chan
, "vm-message");
5210 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5211 res
= res
? res
: ast_play_and_wait(chan
, "vm-gamle");
5212 res
= res
? res
: ast_play_and_wait(chan
, "vm-messages");
5220 static int vm_intro_de(struct ast_channel
*chan
,struct vm_state
*vms
)
5222 /* Introduce messages they have */
5224 res
= ast_play_and_wait(chan
, "vm-youhave");
5226 if (vms
->newmessages
) {
5227 if ((vms
->newmessages
== 1))
5228 res
= ast_play_and_wait(chan
, "digits/1F");
5230 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5232 res
= ast_play_and_wait(chan
, "vm-INBOX");
5233 if (vms
->oldmessages
&& !res
)
5234 res
= ast_play_and_wait(chan
, "vm-and");
5236 if ((vms
->newmessages
== 1))
5237 res
= ast_play_and_wait(chan
, "vm-message");
5239 res
= ast_play_and_wait(chan
, "vm-messages");
5243 if (!res
&& vms
->oldmessages
) {
5244 if (vms
->oldmessages
== 1)
5245 res
= ast_play_and_wait(chan
, "digits/1F");
5247 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5249 res
= ast_play_and_wait(chan
, "vm-Old");
5251 if (vms
->oldmessages
== 1)
5252 res
= ast_play_and_wait(chan
, "vm-message");
5254 res
= ast_play_and_wait(chan
, "vm-messages");
5258 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5259 res
= ast_play_and_wait(chan
, "vm-no");
5261 res
= ast_play_and_wait(chan
, "vm-messages");
5268 /* SPANISH syntax */
5269 static int vm_intro_es(struct ast_channel
*chan
,struct vm_state
*vms
)
5271 /* Introduce messages they have */
5273 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5274 res
= ast_play_and_wait(chan
, "vm-youhaveno");
5276 res
= ast_play_and_wait(chan
, "vm-messages");
5278 res
= ast_play_and_wait(chan
, "vm-youhave");
5281 if (vms
->newmessages
) {
5283 if ((vms
->newmessages
== 1)) {
5284 res
= ast_play_and_wait(chan
, "digits/1M");
5286 res
= ast_play_and_wait(chan
, "vm-message");
5288 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5290 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5292 res
= ast_play_and_wait(chan
, "vm-messages");
5294 res
= ast_play_and_wait(chan
, "vm-INBOX");
5297 if (vms
->oldmessages
&& !res
)
5298 res
= ast_play_and_wait(chan
, "vm-and");
5300 if (vms
->oldmessages
) {
5302 if (vms
->oldmessages
== 1) {
5303 res
= ast_play_and_wait(chan
, "digits/1M");
5305 res
= ast_play_and_wait(chan
, "vm-message");
5307 res
= ast_play_and_wait(chan
, "vm-Olds");
5309 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5311 res
= ast_play_and_wait(chan
, "vm-messages");
5313 res
= ast_play_and_wait(chan
, "vm-Old");
5321 /* BRAZILIAN PORTUGUESE syntax */
5322 static int vm_intro_pt_BR(struct ast_channel
*chan
,struct vm_state
*vms
) {
5323 /* Introduce messages they have */
5325 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5326 res
= ast_play_and_wait(chan
, "vm-nomessages");
5330 res
= ast_play_and_wait(chan
, "vm-youhave");
5332 if (vms
->newmessages
) {
5334 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5335 if ((vms
->newmessages
== 1)) {
5337 res
= ast_play_and_wait(chan
, "vm-message");
5339 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5343 res
= ast_play_and_wait(chan
, "vm-messages");
5345 res
= ast_play_and_wait(chan
, "vm-INBOX");
5347 if (vms
->oldmessages
&& !res
)
5348 res
= ast_play_and_wait(chan
, "vm-and");
5350 if (vms
->oldmessages
) {
5352 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5353 if (vms
->oldmessages
== 1) {
5355 res
= ast_play_and_wait(chan
, "vm-message");
5357 res
= ast_play_and_wait(chan
, "vm-Olds");
5361 res
= ast_play_and_wait(chan
, "vm-messages");
5363 res
= ast_play_and_wait(chan
, "vm-Old");
5370 static int vm_intro_fr(struct ast_channel
*chan
,struct vm_state
*vms
)
5372 /* Introduce messages they have */
5374 res
= ast_play_and_wait(chan
, "vm-youhave");
5376 if (vms
->newmessages
) {
5377 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5379 res
= ast_play_and_wait(chan
, "vm-INBOX");
5380 if (vms
->oldmessages
&& !res
)
5381 res
= ast_play_and_wait(chan
, "vm-and");
5383 if ((vms
->newmessages
== 1))
5384 res
= ast_play_and_wait(chan
, "vm-message");
5386 res
= ast_play_and_wait(chan
, "vm-messages");
5390 if (!res
&& vms
->oldmessages
) {
5391 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5393 res
= ast_play_and_wait(chan
, "vm-Old");
5395 if (vms
->oldmessages
== 1)
5396 res
= ast_play_and_wait(chan
, "vm-message");
5398 res
= ast_play_and_wait(chan
, "vm-messages");
5402 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5403 res
= ast_play_and_wait(chan
, "vm-no");
5405 res
= ast_play_and_wait(chan
, "vm-messages");
5413 static int vm_intro_nl(struct ast_channel
*chan
,struct vm_state
*vms
)
5415 /* Introduce messages they have */
5417 res
= ast_play_and_wait(chan
, "vm-youhave");
5419 if (vms
->newmessages
) {
5420 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5422 if (vms
->newmessages
== 1)
5423 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5425 res
= ast_play_and_wait(chan
, "vm-INBOX");
5427 if (vms
->oldmessages
&& !res
)
5428 res
= ast_play_and_wait(chan
, "vm-and");
5430 if ((vms
->newmessages
== 1))
5431 res
= ast_play_and_wait(chan
, "vm-message");
5433 res
= ast_play_and_wait(chan
, "vm-messages");
5437 if (!res
&& vms
->oldmessages
) {
5438 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5440 if (vms
->oldmessages
== 1)
5441 res
= ast_play_and_wait(chan
, "vm-Olds");
5443 res
= ast_play_and_wait(chan
, "vm-Old");
5446 if (vms
->oldmessages
== 1)
5447 res
= ast_play_and_wait(chan
, "vm-message");
5449 res
= ast_play_and_wait(chan
, "vm-messages");
5453 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5454 res
= ast_play_and_wait(chan
, "vm-no");
5456 res
= ast_play_and_wait(chan
, "vm-messages");
5463 /* PORTUGUESE syntax */
5464 static int vm_intro_pt(struct ast_channel
*chan
,struct vm_state
*vms
)
5466 /* Introduce messages they have */
5468 res
= ast_play_and_wait(chan
, "vm-youhave");
5470 if (vms
->newmessages
) {
5471 res
= ast_say_number(chan
, vms
->newmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5473 if ((vms
->newmessages
== 1)) {
5474 res
= ast_play_and_wait(chan
, "vm-message");
5476 res
= ast_play_and_wait(chan
, "vm-INBOXs");
5478 res
= ast_play_and_wait(chan
, "vm-messages");
5480 res
= ast_play_and_wait(chan
, "vm-INBOX");
5483 if (vms
->oldmessages
&& !res
)
5484 res
= ast_play_and_wait(chan
, "vm-and");
5486 if (!res
&& vms
->oldmessages
) {
5487 res
= ast_say_number(chan
, vms
->oldmessages
, AST_DIGIT_ANY
, chan
->language
, "f");
5489 if (vms
->oldmessages
== 1) {
5490 res
= ast_play_and_wait(chan
, "vm-message");
5492 res
= ast_play_and_wait(chan
, "vm-Olds");
5494 res
= ast_play_and_wait(chan
, "vm-messages");
5496 res
= ast_play_and_wait(chan
, "vm-Old");
5501 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5502 res
= ast_play_and_wait(chan
, "vm-no");
5504 res
= ast_play_and_wait(chan
, "vm-messages");
5513 /* in czech there must be declension of word new and message
5514 * czech : english : czech : english
5515 * --------------------------------------------------------
5516 * vm-youhave : you have
5517 * vm-novou : one new : vm-zpravu : message
5518 * vm-nove : 2-4 new : vm-zpravy : messages
5519 * vm-novych : 5-infinite new : vm-zprav : messages
5520 * vm-starou : one old
5521 * vm-stare : 2-4 old
5522 * vm-starych : 5-infinite old
5523 * jednu : one - falling 4.
5524 * vm-no : no ( no messages )
5527 static int vm_intro_cz(struct ast_channel
*chan
,struct vm_state
*vms
)
5530 res
= ast_play_and_wait(chan
, "vm-youhave");
5532 if (vms
->newmessages
) {
5533 if (vms
->newmessages
== 1) {
5534 res
= ast_play_and_wait(chan
, "digits/jednu");
5536 res
= say_and_wait(chan
, vms
->newmessages
, chan
->language
);
5539 if ((vms
->newmessages
== 1))
5540 res
= ast_play_and_wait(chan
, "vm-novou");
5541 if ((vms
->newmessages
) > 1 && (vms
->newmessages
< 5))
5542 res
= ast_play_and_wait(chan
, "vm-nove");
5543 if (vms
->newmessages
> 4)
5544 res
= ast_play_and_wait(chan
, "vm-novych");
5546 if (vms
->oldmessages
&& !res
)
5547 res
= ast_play_and_wait(chan
, "vm-and");
5549 if ((vms
->newmessages
== 1))
5550 res
= ast_play_and_wait(chan
, "vm-zpravu");
5551 if ((vms
->newmessages
) > 1 && (vms
->newmessages
< 5))
5552 res
= ast_play_and_wait(chan
, "vm-zpravy");
5553 if (vms
->newmessages
> 4)
5554 res
= ast_play_and_wait(chan
, "vm-zprav");
5557 if (!res
&& vms
->oldmessages
) {
5558 res
= say_and_wait(chan
, vms
->oldmessages
, chan
->language
);
5560 if ((vms
->oldmessages
== 1))
5561 res
= ast_play_and_wait(chan
, "vm-starou");
5562 if ((vms
->oldmessages
) > 1 && (vms
->oldmessages
< 5))
5563 res
= ast_play_and_wait(chan
, "vm-stare");
5564 if (vms
->oldmessages
> 4)
5565 res
= ast_play_and_wait(chan
, "vm-starych");
5568 if ((vms
->oldmessages
== 1))
5569 res
= ast_play_and_wait(chan
, "vm-zpravu");
5570 if ((vms
->oldmessages
) > 1 && (vms
->oldmessages
< 5))
5571 res
= ast_play_and_wait(chan
, "vm-zpravy");
5572 if (vms
->oldmessages
> 4)
5573 res
= ast_play_and_wait(chan
, "vm-zprav");
5577 if (!vms
->oldmessages
&& !vms
->newmessages
) {
5578 res
= ast_play_and_wait(chan
, "vm-no");
5580 res
= ast_play_and_wait(chan
, "vm-zpravy");
5587 static int get_lastdigits(int num
)
5590 return (num
< 20) ? num
: num
% 10;
5593 static int vm_intro_ru(struct ast_channel
*chan
,struct vm_state
*vms
)
5599 res
= ast_play_and_wait(chan
, "vm-youhave");
5600 if (!res
&& vms
->newmessages
) {
5601 lastnum
= get_lastdigits(vms
->newmessages
);
5602 dcnum
= vms
->newmessages
- lastnum
;
5604 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5605 if (!res
&& lastnum
) {
5607 res
= ast_play_and_wait(chan
, "digits/ru/odno");
5609 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5613 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-novoe" : "vm-novyh");
5615 if (!res
&& vms
->oldmessages
)
5616 res
= ast_play_and_wait(chan
, "vm-and");
5619 if (!res
&& vms
->oldmessages
) {
5620 lastnum
= get_lastdigits(vms
->oldmessages
);
5621 dcnum
= vms
->oldmessages
- lastnum
;
5623 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5624 if (!res
&& lastnum
) {
5626 res
= ast_play_and_wait(chan
, "digits/ru/odno");
5628 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5632 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-staroe" : "vm-staryh");
5635 if (!res
&& !vms
->newmessages
&& !vms
->oldmessages
) {
5637 res
= ast_play_and_wait(chan
, "vm-no");
5643 res
= ast_play_and_wait(chan
, "vm-soobshenie");
5648 res
= ast_play_and_wait(chan
, "vm-soobsheniya");
5651 res
= ast_play_and_wait(chan
, "vm-soobsheniy");
5659 /* UKRAINIAN syntax */
5660 /* in ukrainian the syntax is different so we need the following files
5661 * --------------------------------------------------------
5662 * /digits/ua/1e 'odne'
5667 static int vm_intro_ua(struct ast_channel
*chan
,struct vm_state
*vms
)
5673 res
= ast_play_and_wait(chan
, "vm-youhave");
5674 if (!res
&& vms
->newmessages
) {
5675 lastnum
= get_lastdigits(vms
->newmessages
);
5676 dcnum
= vms
->newmessages
- lastnum
;
5678 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5679 if (!res
&& lastnum
) {
5681 res
= ast_play_and_wait(chan
, "digits/ua/1e");
5683 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5687 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-nove" : "vm-INBOX");
5689 if (!res
&& vms
->oldmessages
)
5690 res
= ast_play_and_wait(chan
, "vm-and");
5693 if (!res
&& vms
->oldmessages
) {
5694 lastnum
= get_lastdigits(vms
->oldmessages
);
5695 dcnum
= vms
->oldmessages
- lastnum
;
5697 res
= say_and_wait(chan
, dcnum
, chan
->language
);
5698 if (!res
&& lastnum
) {
5700 res
= ast_play_and_wait(chan
, "digits/ua/1e");
5702 res
= say_and_wait(chan
, lastnum
, chan
->language
);
5706 res
= ast_play_and_wait(chan
, (lastnum
== 1) ? "vm-stare" : "vm-Old");
5709 if (!res
&& !vms
->newmessages
&& !vms
->oldmessages
) {
5711 res
= ast_play_and_wait(chan
, "vm-no");
5720 res
= ast_play_and_wait(chan
, "vm-message");
5723 res
= ast_play_and_wait(chan
, "vm-messages");
5732 static int vm_intro(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
)
5736 /* Notify the user that the temp greeting is set and give them the option to remove it */
5737 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5738 if (ast_test_flag(vmu
, VM_TEMPGREETWARN
)) {
5739 if (ast_fileexists(prefile
, NULL
, NULL
) > 0)
5740 ast_play_and_wait(chan
, "vm-tempgreetactive");
5743 /* Play voicemail intro - syntax is different for different languages */
5744 if (!strcasecmp(chan
->language
, "de")) { /* GERMAN syntax */
5745 return vm_intro_de(chan
, vms
);
5746 } else if (!strcasecmp(chan
->language
, "es")) { /* SPANISH syntax */
5747 return vm_intro_es(chan
, vms
);
5748 } else if (!strcasecmp(chan
->language
, "it")) { /* ITALIAN syntax */
5749 return vm_intro_it(chan
, vms
);
5750 } else if (!strcasecmp(chan
->language
, "fr")) { /* FRENCH syntax */
5751 return vm_intro_fr(chan
, vms
);
5752 } else if (!strcasecmp(chan
->language
, "nl")) { /* DUTCH syntax */
5753 return vm_intro_nl(chan
, vms
);
5754 } else if (!strcasecmp(chan
->language
, "pt")) { /* PORTUGUESE syntax */
5755 return vm_intro_pt(chan
, vms
);
5756 } else if (!strcasecmp(chan
->language
, "pt_BR")) { /* BRAZILIAN PORTUGUESE syntax */
5757 return vm_intro_pt_BR(chan
, vms
);
5758 } else if (!strcasecmp(chan
->language
, "cz")) { /* CZECH syntax */
5759 return vm_intro_cz(chan
, vms
);
5760 } else if (!strcasecmp(chan
->language
, "gr")) { /* GREEK syntax */
5761 return vm_intro_gr(chan
, vms
);
5762 } else if (!strcasecmp(chan
->language
, "pl")) { /* POLISH syntax */
5763 return vm_intro_pl(chan
, vms
);
5764 } else if (!strcasecmp(chan
->language
, "se")) { /* SWEDISH syntax */
5765 return vm_intro_se(chan
, vms
);
5766 } else if (!strcasecmp(chan
->language
, "no")) { /* NORWEGIAN syntax */
5767 return vm_intro_no(chan
, vms
);
5768 } else if (!strcasecmp(chan
->language
, "ru")) { /* RUSSIAN syntax */
5769 return vm_intro_ru(chan
, vms
);
5770 } else if (!strcasecmp(chan
->language
, "ua")) { /* UKRAINIAN syntax */
5771 return vm_intro_ua(chan
, vms
);
5772 } else { /* Default to ENGLISH */
5773 return vm_intro_en(chan
, vms
);
5777 static int vm_instructions(struct ast_channel
*chan
, struct vm_state
*vms
, int skipadvanced
)
5780 /* Play instructions and wait for new command */
5782 if (vms
->starting
) {
5783 if (vms
->lastmsg
> -1) {
5784 res
= ast_play_and_wait(chan
, "vm-onefor");
5786 res
= vm_play_folder_name(chan
, vms
->vmbox
);
5789 res
= ast_play_and_wait(chan
, "vm-opts");
5792 res
= ast_play_and_wait(chan
, "vm-prev");
5793 if (!res
&& !skipadvanced
)
5794 res
= ast_play_and_wait(chan
, "vm-advopts");
5796 res
= ast_play_and_wait(chan
, "vm-repeat");
5797 if (!res
&& (vms
->curmsg
!= vms
->lastmsg
))
5798 res
= ast_play_and_wait(chan
, "vm-next");
5800 if (!vms
->deleted
[vms
->curmsg
])
5801 res
= ast_play_and_wait(chan
, "vm-delete");
5803 res
= ast_play_and_wait(chan
, "vm-undelete");
5805 res
= ast_play_and_wait(chan
, "vm-toforward");
5807 res
= ast_play_and_wait(chan
, "vm-savemessage");
5811 res
= ast_play_and_wait(chan
, "vm-helpexit");
5813 res
= ast_waitfordigit(chan
, 6000);
5816 if (vms
->repeats
> 2) {
5824 static int vm_newuser(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
5829 char newpassword
[80] = "";
5830 char newpassword2
[80] = "";
5831 char prefile
[PATH_MAX
] = "";
5832 unsigned char buf
[256];
5835 if (ast_adsi_available(chan
)) {
5836 bytes
+= adsi_logo(buf
+ bytes
);
5837 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "New User Setup", "");
5838 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
5839 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
5840 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
5841 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
5844 /* First, have the user change their password
5845 so they won't get here again */
5847 newpassword
[1] = '\0';
5848 newpassword
[0] = cmd
= ast_play_and_wait(chan
,"vm-newpassword");
5850 newpassword
[0] = '\0';
5851 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5853 cmd
= ast_readstring(chan
,newpassword
+ strlen(newpassword
),sizeof(newpassword
)-1,2000,10000,"#");
5854 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5856 newpassword2
[1] = '\0';
5857 newpassword2
[0] = cmd
= ast_play_and_wait(chan
,"vm-reenterpassword");
5859 newpassword2
[0] = '\0';
5860 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5862 cmd
= ast_readstring(chan
,newpassword2
+ strlen(newpassword2
),sizeof(newpassword2
)-1,2000,10000,"#");
5863 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5865 if (!strcmp(newpassword
, newpassword2
))
5867 ast_log(LOG_NOTICE
,"Password mismatch for user %s (%s != %s)\n", vms
->username
, newpassword
, newpassword2
);
5868 cmd
= ast_play_and_wait(chan
, "vm-mismatch");
5872 if (ast_strlen_zero(ext_pass_cmd
))
5873 vm_change_password(vmu
,newpassword
);
5875 vm_change_password_shell(vmu
,newpassword
);
5876 if (option_debug
> 2)
5877 ast_log(LOG_DEBUG
,"User %s set password to %s of length %d\n",vms
->username
,newpassword
,(int)strlen(newpassword
));
5878 cmd
= ast_play_and_wait(chan
,"vm-passchanged");
5880 /* If forcename is set, have the user record their name */
5881 if (ast_test_flag(vmu
, VM_FORCENAME
)) {
5882 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5883 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
5884 #ifndef IMAP_STORAGE
5885 cmd
= play_record_review(chan
, "vm-rec-name", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5887 cmd
= play_record_review(chan
, "vm-rec-name", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5889 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5894 /* If forcegreetings is set, have the user record their greetings */
5895 if (ast_test_flag(vmu
, VM_FORCEGREET
)) {
5896 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5897 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
5898 #ifndef IMAP_STORAGE
5899 cmd
= play_record_review(chan
, "vm-rec-unv", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5901 cmd
= play_record_review(chan
, "vm-rec-unv", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5903 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5907 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5908 if (ast_fileexists(prefile
, NULL
, NULL
) < 1) {
5909 #ifndef IMAP_STORAGE
5910 cmd
= play_record_review(chan
, "vm-rec-busy", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5912 cmd
= play_record_review(chan
, "vm-rec-busy", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5914 if (cmd
< 0 || cmd
== 't' || cmd
== '#')
5922 static int vm_options(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
5927 char newpassword
[80] = "";
5928 char newpassword2
[80] = "";
5929 char prefile
[PATH_MAX
] = "";
5930 unsigned char buf
[256];
5933 if (ast_adsi_available(chan
))
5935 bytes
+= adsi_logo(buf
+ bytes
);
5936 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Options Menu", "");
5937 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
5938 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
5939 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
5940 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
5942 while ((cmd
>= 0) && (cmd
!= 't')) {
5947 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/unavail", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5948 #ifndef IMAP_STORAGE
5949 cmd
= play_record_review(chan
,"vm-rec-unv",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5951 cmd
= play_record_review(chan
,"vm-rec-unv",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5955 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/busy", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5956 #ifndef IMAP_STORAGE
5957 cmd
= play_record_review(chan
,"vm-rec-busy",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5959 cmd
= play_record_review(chan
,"vm-rec-busy",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5963 snprintf(prefile
,sizeof(prefile
), "%s%s/%s/greet", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
5964 #ifndef IMAP_STORAGE
5965 cmd
= play_record_review(chan
,"vm-rec-name",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
5967 cmd
= play_record_review(chan
,"vm-rec-name",prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
5971 cmd
= vm_tempgreeting(chan
, vmu
, vms
, fmtc
, record_gain
);
5974 if (vmu
->password
[0] == '-') {
5975 cmd
= ast_play_and_wait(chan
, "vm-no");
5978 newpassword
[1] = '\0';
5979 newpassword
[0] = cmd
= ast_play_and_wait(chan
,"vm-newpassword");
5981 newpassword
[0] = '\0';
5985 if ((cmd
= ast_readstring(chan
,newpassword
+ strlen(newpassword
),sizeof(newpassword
)-1,2000,10000,"#")) < 0) {
5989 newpassword2
[1] = '\0';
5990 newpassword2
[0] = cmd
= ast_play_and_wait(chan
,"vm-reenterpassword");
5992 newpassword2
[0] = '\0';
5997 if ((cmd
= ast_readstring(chan
,newpassword2
+ strlen(newpassword2
),sizeof(newpassword2
)-1,2000,10000,"#"))) {
6001 if (strcmp(newpassword
, newpassword2
)) {
6002 ast_log(LOG_NOTICE
,"Password mismatch for user %s (%s != %s)\n", vms
->username
, newpassword
, newpassword2
);
6003 cmd
= ast_play_and_wait(chan
, "vm-mismatch");
6006 if (ast_strlen_zero(ext_pass_cmd
))
6007 vm_change_password(vmu
,newpassword
);
6009 vm_change_password_shell(vmu
,newpassword
);
6010 if (option_debug
> 2)
6011 ast_log(LOG_DEBUG
,"User %s set password to %s of length %d\n",vms
->username
,newpassword
,(int)strlen(newpassword
));
6012 cmd
= ast_play_and_wait(chan
,"vm-passchanged");
6018 cmd
= ast_play_and_wait(chan
,"vm-options");
6020 cmd
= ast_waitfordigit(chan
,6000);
6032 static int vm_tempgreeting(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, struct vm_state
*vms
, char *fmtc
, signed char record_gain
)
6038 char prefile
[PATH_MAX
] = "";
6039 unsigned char buf
[256];
6040 char dest
[PATH_MAX
];
6043 if (ast_adsi_available(chan
)) {
6044 bytes
+= adsi_logo(buf
+ bytes
);
6045 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 3, ADSI_JUST_CENT
, 0, "Temp Greeting Menu", "");
6046 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_COMM_PAGE
, 4, ADSI_JUST_CENT
, 0, "Not Done", "");
6047 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_COMM_PAGE
, 1);
6048 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
6049 ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
);
6052 snprintf(prefile
, sizeof(prefile
), "%s%s/%s/temp", VM_SPOOL_DIR
, vmu
->context
, vms
->username
);
6053 if ((res
= create_dirpath(dest
, sizeof(dest
), vmu
->context
, vms
->username
, "temp"))) {
6054 ast_log(LOG_WARNING
, "Failed to create directory (%s).\n", prefile
);
6057 while((cmd
>= 0) && (cmd
!= 't')) {
6060 RETRIEVE(prefile
, -1);
6061 if (ast_fileexists(prefile
, NULL
, NULL
) <= 0) {
6062 #ifndef IMAP_STORAGE
6063 play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6065 play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6071 #ifndef IMAP_STORAGE
6072 cmd
= play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, NULL
);
6074 cmd
= play_record_review(chan
, "vm-rec-temp", prefile
, maxgreet
, fmtc
, 0, vmu
, &duration
, NULL
, record_gain
, vms
);
6078 DELETE(prefile
, -1, prefile
);
6079 ast_play_and_wait(chan
, "vm-tempremoved");
6086 cmd
= ast_play_and_wait(chan
,
6087 ast_fileexists(prefile
, NULL
, NULL
) > 0 ? /* XXX always true ? */
6088 "vm-tempgreeting2" : "vm-tempgreeting");
6090 cmd
= ast_waitfordigit(chan
,6000);
6097 DISPOSE(prefile
, -1);
6106 static int vm_browse_messages_gr(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6110 if (vms
->lastmsg
> -1) {
6111 cmd
= play_message(chan
, vmu
, vms
);
6113 cmd
= ast_play_and_wait(chan
, "vm-youhaveno");
6114 if (!strcasecmp(vms
->vmbox
, "vm-INBOX") ||!strcasecmp(vms
->vmbox
, "vm-Old")){
6116 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%ss", vms
->curbox
);
6117 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6120 cmd
= ast_play_and_wait(chan
, "vm-messages");
6123 cmd
= ast_play_and_wait(chan
, "vm-messages");
6125 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6126 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6133 /* Default English syntax */
6134 static int vm_browse_messages_en(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6138 if (vms
->lastmsg
> -1) {
6139 cmd
= play_message(chan
, vmu
, vms
);
6141 cmd
= ast_play_and_wait(chan
, "vm-youhave");
6143 cmd
= ast_play_and_wait(chan
, "vm-no");
6145 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6146 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6149 cmd
= ast_play_and_wait(chan
, "vm-messages");
6154 /* ITALIAN syntax */
6155 static int vm_browse_messages_it(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6159 if (vms
->lastmsg
> -1) {
6160 cmd
= play_message(chan
, vmu
, vms
);
6162 cmd
= ast_play_and_wait(chan
, "vm-no");
6164 cmd
= ast_play_and_wait(chan
, "vm-message");
6166 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6167 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6173 /* SPANISH syntax */
6174 static int vm_browse_messages_es(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6178 if (vms
->lastmsg
> -1) {
6179 cmd
= play_message(chan
, vmu
, vms
);
6181 cmd
= ast_play_and_wait(chan
, "vm-youhaveno");
6183 cmd
= ast_play_and_wait(chan
, "vm-messages");
6185 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6186 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6192 /* PORTUGUESE syntax */
6193 static int vm_browse_messages_pt(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6197 if (vms
->lastmsg
> -1) {
6198 cmd
= play_message(chan
, vmu
, vms
);
6200 cmd
= ast_play_and_wait(chan
, "vm-no");
6202 snprintf(vms
->fn
, sizeof(vms
->fn
), "vm-%s", vms
->curbox
);
6203 cmd
= ast_play_and_wait(chan
, vms
->fn
);
6206 cmd
= ast_play_and_wait(chan
, "vm-messages");
6211 static int vm_browse_messages(struct ast_channel
*chan
, struct vm_state
*vms
, struct ast_vm_user
*vmu
)
6213 if (!strcasecmp(chan
->language
, "es")) { /* SPANISH */
6214 return vm_browse_messages_es(chan
, vms
, vmu
);
6215 } else if (!strcasecmp(chan
->language
, "it")) { /* ITALIAN */
6216 return vm_browse_messages_it(chan
, vms
, vmu
);
6217 } else if (!strcasecmp(chan
->language
, "pt") || !strcasecmp(chan
->language
, "pt_BR")) { /* PORTUGUESE */
6218 return vm_browse_messages_pt(chan
, vms
, vmu
);
6219 } else if (!strcasecmp(chan
->language
, "gr")){
6220 return vm_browse_messages_gr(chan
, vms
, vmu
); /* GREEK */
6221 } else { /* Default to English syntax */
6222 return vm_browse_messages_en(chan
, vms
, vmu
);
6226 static int vm_authenticate(struct ast_channel
*chan
, char *mailbox
, int mailbox_size
,
6227 struct ast_vm_user
*res_vmu
, const char *context
, const char *prefix
,
6228 int skipuser
, int maxlogins
, int silent
)
6230 int useadsi
=0, valid
=0, logretries
=0;
6231 char password
[AST_MAX_EXTENSION
]="", *passptr
;
6232 struct ast_vm_user vmus
, *vmu
= NULL
;
6234 /* If ADSI is supported, setup login screen */
6235 adsi_begin(chan
, &useadsi
);
6236 if (!skipuser
&& useadsi
)
6238 if (!silent
&& !skipuser
&& ast_streamfile(chan
, "vm-login", chan
->language
)) {
6239 ast_log(LOG_WARNING
, "Couldn't stream login file\n");
6243 /* Authenticate them and get their mailbox/password */
6245 while (!valid
&& (logretries
< maxlogins
)) {
6246 /* Prompt for, and read in the username */
6247 if (!skipuser
&& ast_readstring(chan
, mailbox
, mailbox_size
- 1, 2000, 10000, "#") < 0) {
6248 ast_log(LOG_WARNING
, "Couldn't read username\n");
6251 if (ast_strlen_zero(mailbox
)) {
6252 if (chan
->cid
.cid_num
) {
6253 ast_copy_string(mailbox
, chan
->cid
.cid_num
, mailbox_size
);
6255 if (option_verbose
> 2)
6256 ast_verbose(VERBOSE_PREFIX_3
"Username not entered\n");
6261 adsi_password(chan
);
6263 if (!ast_strlen_zero(prefix
)) {
6264 char fullusername
[80] = "";
6265 ast_copy_string(fullusername
, prefix
, sizeof(fullusername
));
6266 strncat(fullusername
, mailbox
, sizeof(fullusername
) - 1 - strlen(fullusername
));
6267 ast_copy_string(mailbox
, fullusername
, mailbox_size
);
6271 ast_log(LOG_DEBUG
, "Before find user for mailbox %s\n",mailbox
);
6272 vmu
= find_user(&vmus
, context
, mailbox
);
6273 if (vmu
&& (vmu
->password
[0] == '\0' || (vmu
->password
[0] == '-' && vmu
->password
[1] == '\0'))) {
6274 /* saved password is blank, so don't bother asking */
6277 if (ast_streamfile(chan
, "vm-password", chan
->language
)) {
6278 ast_log(LOG_WARNING
, "Unable to stream password file\n");
6281 if (ast_readstring(chan
, password
, sizeof(password
) - 1, 2000, 10000, "#") < 0) {
6282 ast_log(LOG_WARNING
, "Unable to read password\n");
6288 passptr
= vmu
->password
;
6289 if (passptr
[0] == '-') passptr
++;
6291 if (vmu
&& !strcmp(passptr
, password
))
6294 if (option_verbose
> 2)
6295 ast_verbose( VERBOSE_PREFIX_3
"Incorrect password '%s' for user '%s' (context = %s)\n", password
, mailbox
, context
? context
: "default");
6296 if (!ast_strlen_zero(prefix
))
6301 if (skipuser
|| logretries
>= maxlogins
) {
6302 if (ast_streamfile(chan
, "vm-incorrect", chan
->language
)) {
6303 ast_log(LOG_WARNING
, "Unable to stream incorrect message\n");
6309 if (ast_streamfile(chan
, "vm-incorrect-mailbox", chan
->language
)) {
6310 ast_log(LOG_WARNING
, "Unable to stream incorrect mailbox message\n");
6314 if (ast_waitstream(chan
, "")) /* Channel is hung up */
6318 if (!valid
&& (logretries
>= maxlogins
)) {
6319 ast_stopstream(chan
);
6320 ast_play_and_wait(chan
, "vm-goodbye");
6323 if (vmu
&& !skipuser
) {
6324 memcpy(res_vmu
, vmu
, sizeof(struct ast_vm_user
));
6329 static int vm_execmain(struct ast_channel
*chan
, void *data
)
6331 /* XXX This is, admittedly, some pretty horrendus code. For some
6332 reason it just seemed a lot easier to do with GOTO's. I feel
6333 like I'm back in my GWBASIC days. XXX */
6337 struct ast_module_user
*u
;
6338 char prefixstr
[80] ="";
6339 char ext_context
[256]="";
6343 struct vm_state vms
;
6344 struct ast_vm_user
*vmu
= NULL
, vmus
;
6347 struct ast_flags flags
= { 0 };
6348 signed char record_gain
= 0;
6350 int play_folder
= 0;
6354 u
= ast_module_user_add(chan
);
6356 /* Add the vm_state to the active list and keep it active */
6357 memset(&vms
, 0, sizeof(vms
));
6360 memset(&vmus
, 0, sizeof(vmus
));
6362 if (chan
->_state
!= AST_STATE_UP
) {
6364 ast_log(LOG_DEBUG
, "Before ast_answer\n");
6368 if (!ast_strlen_zero(data
)) {
6369 char *opts
[OPT_ARG_ARRAY_SIZE
];
6371 AST_DECLARE_APP_ARGS(args
,
6376 parse
= ast_strdupa(data
);
6378 AST_STANDARD_APP_ARGS(args
, parse
);
6380 if (args
.argc
== 2) {
6381 if (ast_app_parse_options(vm_app_options
, &flags
, opts
, args
.argv1
)) {
6382 ast_module_user_remove(u
);
6385 if (ast_test_flag(&flags
, OPT_RECORDGAIN
)) {
6387 if (!ast_strlen_zero(opts
[OPT_ARG_RECORDGAIN
])) {
6388 if (sscanf(opts
[OPT_ARG_RECORDGAIN
], "%d", &gain
) != 1) {
6389 ast_log(LOG_WARNING
, "Invalid value '%s' provided for record gain option\n", opts
[OPT_ARG_RECORDGAIN
]);
6390 ast_module_user_remove(u
);
6393 record_gain
= (signed char) gain
;
6396 ast_log(LOG_WARNING
, "Invalid Gain level set with option g\n");
6399 if (ast_test_flag(&flags
, OPT_AUTOPLAY
) ) {
6401 if (opts
[OPT_ARG_PLAYFOLDER
]) {
6402 if (sscanf(opts
[OPT_ARG_PLAYFOLDER
], "%d", &play_folder
) != 1) {
6403 ast_log(LOG_WARNING
, "Invalid value '%s' provided for folder autoplay option\n", opts
[OPT_ARG_PLAYFOLDER
]);
6406 ast_log(LOG_WARNING
, "Invalid folder set with option a\n");
6408 if ( play_folder
> 9 || play_folder
< 0) {
6409 ast_log(LOG_WARNING
, "Invalid value '%d' provided for folder autoplay option\n", play_folder
);
6414 /* old style options parsing */
6415 while (*(args
.argv0
)) {
6416 if (*(args
.argv0
) == 's')
6417 ast_set_flag(&flags
, OPT_SILENT
);
6418 else if (*(args
.argv0
) == 'p')
6419 ast_set_flag(&flags
, OPT_PREPEND_MAILBOX
);
6427 valid
= ast_test_flag(&flags
, OPT_SILENT
);
6429 if ((context
= strchr(args
.argv0
, '@')))
6432 if (ast_test_flag(&flags
, OPT_PREPEND_MAILBOX
))
6433 ast_copy_string(prefixstr
, args
.argv0
, sizeof(prefixstr
));
6435 ast_copy_string(vms
.username
, args
.argv0
, sizeof(vms
.username
));
6437 if (!ast_strlen_zero(vms
.username
) && (vmu
= find_user(&vmus
, context
,vms
.username
)))
6444 res
= vm_authenticate(chan
, vms
.username
, sizeof(vms
.username
), &vmus
, context
, prefixstr
, skipuser
, maxlogins
, 0);
6447 ast_log(LOG_DEBUG
, "After vm_authenticate\n");
6456 /* If ADSI is supported, setup login screen */
6457 adsi_begin(chan
, &useadsi
);
6460 vms
.interactive
= 1;
6462 vmstate_insert(&vms
);
6463 init_vm_state(&vms
);
6468 if (!(vms
.deleted
= ast_calloc(vmu
->maxmsg
, sizeof(int)))) {
6469 /* TODO: Handle memory allocation failure */
6471 if (!(vms
.heard
= ast_calloc(vmu
->maxmsg
, sizeof(int)))) {
6472 /* TODO: Handle memory allocation failure */
6475 /* Set language from config to override channel language */
6476 if (!ast_strlen_zero(vmu
->language
))
6477 ast_string_field_set(chan
, language
, vmu
->language
);
6478 #ifndef IMAP_STORAGE
6479 create_dirpath(vms
.curdir
, sizeof(vms
.curdir
), vmu
->context
, vms
.username
, "");
6481 /* Retrieve old and new message counts */
6483 ast_log(LOG_DEBUG
, "Before open_mailbox\n");
6484 res
= open_mailbox(&vms
, vmu
, 1);
6485 if (res
== ERROR_LOCK_PATH
)
6487 vms
.oldmessages
= vms
.lastmsg
+ 1;
6488 if (option_debug
> 2)
6489 ast_log(LOG_DEBUG
, "Number of old messages: %d\n",vms
.oldmessages
);
6490 /* Start in INBOX */
6491 res
= open_mailbox(&vms
, vmu
, 0);
6492 if (res
== ERROR_LOCK_PATH
)
6494 vms
.newmessages
= vms
.lastmsg
+ 1;
6495 if (option_debug
> 2)
6496 ast_log(LOG_DEBUG
, "Number of new messages: %d\n",vms
.newmessages
);
6498 /* Select proper mailbox FIRST!! */
6500 res
= open_mailbox(&vms
, vmu
, play_folder
);
6501 if (res
== ERROR_LOCK_PATH
)
6504 /* If there are no new messages, inform the user and hangup */
6505 if (vms
.lastmsg
== -1) {
6506 cmd
= vm_browse_messages(chan
, &vms
, vmu
);
6511 if (!vms
.newmessages
&& vms
.oldmessages
) {
6512 /* If we only have old messages start here */
6513 res
= open_mailbox(&vms
, vmu
, 1);
6515 if (res
== ERROR_LOCK_PATH
)
6521 adsi_status(chan
, &vms
);
6524 /* Check to see if this is a new user */
6525 if (!strcasecmp(vmu
->mailbox
, vmu
->password
) &&
6526 (ast_test_flag(vmu
, VM_FORCENAME
| VM_FORCEGREET
))) {
6527 if (ast_play_and_wait(chan
, "vm-newuser") == -1)
6528 ast_log(LOG_WARNING
, "Couldn't stream new user file\n");
6529 cmd
= vm_newuser(chan
, vmu
, &vms
, vmfmts
, record_gain
);
6530 if ((cmd
== 't') || (cmd
== '#')) {
6534 } else if (cmd
< 0) {
6541 if(option_debug
> 2)
6542 ast_log(LOG_DEBUG
, "Checking quotas: comparing %u to %u\n",vms
.quota_usage
,vms
.quota_limit
);
6543 if (vms
.quota_limit
&& vms
.quota_usage
>= vms
.quota_limit
) {
6545 ast_log(LOG_DEBUG
, "*** QUOTA EXCEEDED!!\n");
6546 cmd
= ast_play_and_wait(chan
, "vm-mailboxfull");
6552 cmd
= vm_intro(chan
, vmu
, &vms
);
6557 while ((cmd
> -1) && (cmd
!= 't') && (cmd
!= '#')) {
6564 cmd
= vm_browse_messages(chan
, &vms
, vmu
);
6566 case '2': /* Change folders */
6568 adsi_folders(chan
, 0, "Change to folder...");
6569 cmd
= get_folder2(chan
, "vm-changeto", 0);
6572 } else if (cmd
> 0) {
6574 res
= close_mailbox(&vms
, vmu
);
6575 if (res
== ERROR_LOCK_PATH
)
6577 res
= open_mailbox(&vms
, vmu
, cmd
);
6578 if (res
== ERROR_LOCK_PATH
)
6584 adsi_status2(chan
, &vms
);
6587 cmd
= vm_play_folder_name(chan
, vms
.vmbox
);
6591 case '3': /* Advanced options */
6594 while ((cmd
> -1) && (cmd
!= 't') && (cmd
!= '#')) {
6596 case '1': /* Reply */
6597 if (vms
.lastmsg
> -1 && !vms
.starting
) {
6598 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 1, record_gain
);
6599 if (cmd
== ERROR_LOCK_PATH
) {
6604 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6607 case '2': /* Callback */
6608 if (option_verbose
> 2 && !vms
.starting
)
6609 ast_verbose( VERBOSE_PREFIX_3
"Callback Requested\n");
6610 if (!ast_strlen_zero(vmu
->callback
) && vms
.lastmsg
> -1 && !vms
.starting
) {
6611 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 2, record_gain
);
6615 } else if (cmd
== ERROR_LOCK_PATH
) {
6621 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6624 case '3': /* Envelope */
6625 if (vms
.lastmsg
> -1 && !vms
.starting
) {
6626 cmd
= advanced_options(chan
, vmu
, &vms
, vms
.curmsg
, 3, record_gain
);
6627 if (cmd
== ERROR_LOCK_PATH
) {
6632 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6635 case '4': /* Dialout */
6636 if (!ast_strlen_zero(vmu
->dialout
)) {
6637 cmd
= dialout(chan
, vmu
, NULL
, vmu
->dialout
);
6644 cmd
= ast_play_and_wait(chan
, "vm-sorry");
6648 case '5': /* Leave VoiceMail */
6649 if (ast_test_flag(vmu
, VM_SVMAIL
)) {
6650 cmd
= forward_message(chan
, context
, &vms
, vmu
, vmfmts
, 1, record_gain
);
6651 if (cmd
== ERROR_LOCK_PATH
) {
6653 ast_log(LOG_WARNING
, "forward_message failed to lock path.\n");
6657 cmd
= ast_play_and_wait(chan
,"vm-sorry");
6661 case '*': /* Return to main menu */
6667 if (!vms
.starting
) {
6668 cmd
= ast_play_and_wait(chan
, "vm-toreply");
6670 if (!ast_strlen_zero(vmu
->callback
) && !vms
.starting
&& !cmd
) {
6671 cmd
= ast_play_and_wait(chan
, "vm-tocallback");
6673 if (!cmd
&& !vms
.starting
) {
6674 cmd
= ast_play_and_wait(chan
, "vm-tohearenv");
6676 if (!ast_strlen_zero(vmu
->dialout
) && !cmd
) {
6677 cmd
= ast_play_and_wait(chan
, "vm-tomakecall");
6679 if (ast_test_flag(vmu
, VM_SVMAIL
) && !cmd
)
6680 cmd
=ast_play_and_wait(chan
, "vm-leavemsg");
6682 cmd
= ast_play_and_wait(chan
, "vm-starmain");
6684 cmd
= ast_waitfordigit(chan
,6000);
6687 if (vms
.repeats
> 3)
6697 if (vms
.curmsg
> 0) {
6699 cmd
= play_message(chan
, vmu
, &vms
);
6701 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6705 if (vms
.curmsg
< vms
.lastmsg
) {
6707 cmd
= play_message(chan
, vmu
, &vms
);
6709 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6713 if (vms
.curmsg
>= 0 && vms
.curmsg
<= vms
.lastmsg
) {
6714 vms
.deleted
[vms
.curmsg
] = !vms
.deleted
[vms
.curmsg
];
6716 adsi_delete(chan
, &vms
);
6717 if (vms
.deleted
[vms
.curmsg
]) {
6718 if (play_folder
== 0)
6720 else if (play_folder
== 1)
6722 cmd
= ast_play_and_wait(chan
, "vm-deleted");
6725 if (play_folder
== 0)
6727 else if (play_folder
== 1)
6729 cmd
= ast_play_and_wait(chan
, "vm-undeleted");
6731 if (ast_test_flag((&globalflags
), VM_SKIPAFTERCMD
)) {
6732 if (vms
.curmsg
< vms
.lastmsg
) {
6734 cmd
= play_message(chan
, vmu
, &vms
);
6736 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6739 } else /* Delete not valid if we haven't selected a message */
6747 if (vms
.lastmsg
> -1) {
6748 cmd
= forward_message(chan
, context
, &vms
, vmu
, vmfmts
, 0, record_gain
);
6749 if (cmd
== ERROR_LOCK_PATH
) {
6754 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6757 if (vms
.curmsg
< 0 || vms
.curmsg
> vms
.lastmsg
) {
6758 /* No message selected */
6763 adsi_folders(chan
, 1, "Save to folder...");
6764 cmd
= get_folder2(chan
, "vm-savefolder", 1);
6765 box
= 0; /* Shut up compiler */
6769 } else if (cmd
> 0) {
6770 box
= cmd
= cmd
- '0';
6771 cmd
= save_to_folder(vmu
, &vms
, vms
.curmsg
, cmd
);
6772 if (cmd
== ERROR_LOCK_PATH
) {
6776 } else if (cmd
== 10) {
6780 vms
.deleted
[vms
.curmsg
] = 1;
6782 vms
.deleted
[vms
.curmsg
] = 0;
6783 vms
.heard
[vms
.curmsg
] = 0;
6786 make_file(vms
.fn
, sizeof(vms
.fn
), vms
.curdir
, vms
.curmsg
);
6788 adsi_message(chan
, &vms
);
6789 snprintf(vms
.fn
, sizeof(vms
.fn
), "vm-%s", mbox(box
));
6791 cmd
= ast_play_and_wait(chan
, "vm-message");
6793 cmd
= say_and_wait(chan
, vms
.curmsg
+ 1, chan
->language
);
6795 cmd
= ast_play_and_wait(chan
, "vm-savedto");
6797 cmd
= vm_play_folder_name(chan
, vms
.fn
);
6799 cmd
= ast_play_and_wait(chan
, "vm-mailboxfull");
6801 if (ast_test_flag((&globalflags
), VM_SKIPAFTERCMD
)) {
6802 if (vms
.curmsg
< vms
.lastmsg
) {
6804 cmd
= play_message(chan
, vmu
, &vms
);
6806 cmd
= ast_play_and_wait(chan
, "vm-nomore");
6811 if (!vms
.starting
) {
6812 cmd
= ast_play_and_wait(chan
, "vm-onefor");
6814 cmd
= vm_play_folder_name(chan
, vms
.vmbox
);
6816 cmd
= ast_play_and_wait(chan
, "vm-opts");
6818 cmd
= vm_instructions(chan
, &vms
, 1);
6823 cmd
= vm_options(chan
, vmu
, &vms
, vmfmts
, record_gain
);
6825 adsi_status(chan
, &vms
);
6827 default: /* Nothing */
6828 cmd
= vm_instructions(chan
, &vms
, 0);
6832 if ((cmd
== 't') || (cmd
== '#')) {
6842 ast_stopstream(chan
);
6846 res
= ast_play_and_wait(chan
, "vm-dialout");
6848 res
= ast_play_and_wait(chan
, "vm-goodbye");
6853 ast_adsi_unload_session(chan
);
6856 close_mailbox(&vms
, vmu
);
6858 snprintf(ext_context
, sizeof(ext_context
), "%s@%s", vms
.username
, vmu
->context
);
6859 manager_event(EVENT_FLAG_CALL
, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context
, has_voicemail(ext_context
, NULL
));
6860 run_externnotify(vmu
->context
, vmu
->mailbox
);
6863 /* expunge message - use UID Expunge if supported on IMAP server*/
6864 if(option_debug
> 2)
6865 ast_log(LOG_DEBUG
, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted
,expungeonhangup
);
6866 if (vmu
&& deleted
== 1 && expungeonhangup
== 1) {
6867 #ifdef HAVE_IMAP_TK2006
6868 if (LEVELUIDPLUS (vms
.mailstream
)) {
6869 mail_expunge_full(vms
.mailstream
,NIL
,EX_UID
);
6872 mail_expunge(vms
.mailstream
);
6874 /* before we delete the state, we should copy pertinent info
6875 * back to the persistent model */
6876 vmstate_delete(&vms
);
6884 ast_module_user_remove(u
);
6889 static int vm_exec(struct ast_channel
*chan
, void *data
)
6892 struct ast_module_user
*u
;
6894 struct leave_vm_options leave_options
;
6895 struct ast_flags flags
= { 0 };
6896 static int deprecate_warning
= 0;
6897 char *opts
[OPT_ARG_ARRAY_SIZE
];
6898 AST_DECLARE_APP_ARGS(args
,
6903 u
= ast_module_user_add(chan
);
6905 memset(&leave_options
, 0, sizeof(leave_options
));
6907 if (chan
->_state
!= AST_STATE_UP
)
6910 if (!ast_strlen_zero(data
)) {
6911 tmp
= ast_strdupa(data
);
6912 AST_STANDARD_APP_ARGS(args
, tmp
);
6913 if (args
.argc
== 2) {
6914 if (ast_app_parse_options(vm_app_options
, &flags
, opts
, args
.argv1
)) {
6915 ast_module_user_remove(u
);
6918 ast_copy_flags(&leave_options
, &flags
, OPT_SILENT
| OPT_BUSY_GREETING
| OPT_UNAVAIL_GREETING
| OPT_PRIORITY_JUMP
);
6919 if (ast_test_flag(&flags
, OPT_RECORDGAIN
)) {
6922 if (sscanf(opts
[OPT_ARG_RECORDGAIN
], "%d", &gain
) != 1) {
6923 ast_log(LOG_WARNING
, "Invalid value '%s' provided for record gain option\n", opts
[OPT_ARG_RECORDGAIN
]);
6924 ast_module_user_remove(u
);
6927 leave_options
.record_gain
= (signed char) gain
;
6931 /* old style options parsing */
6933 char *orig_argv0
= args
.argv0
;
6934 while (*(args
.argv0
)) {
6935 if (*(args
.argv0
) == 's') {
6937 ast_set_flag(&leave_options
, OPT_SILENT
);
6938 } else if (*(args
.argv0
) == 'b') {
6940 ast_set_flag(&leave_options
, OPT_BUSY_GREETING
);
6941 } else if (*(args
.argv0
) == 'u') {
6943 ast_set_flag(&leave_options
, OPT_UNAVAIL_GREETING
);
6944 } else if (*(args
.argv0
) == 'j') {
6946 ast_set_flag(&leave_options
, OPT_PRIORITY_JUMP
);
6951 if (!deprecate_warning
&& old
) {
6952 deprecate_warning
= 1;
6953 ast_log(LOG_WARNING
, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0
);
6954 ast_log(LOG_WARNING
, "Please move all leading options to the second argument.\n");
6959 res
= ast_app_getdata(chan
, "vm-whichbox", tmp
, sizeof(tmp
) - 1, 0);
6961 ast_module_user_remove(u
);
6964 if (ast_strlen_zero(tmp
)) {
6965 ast_module_user_remove(u
);
6968 args
.argv0
= ast_strdupa(tmp
);
6971 res
= leave_voicemail(chan
, args
.argv0
, &leave_options
);
6973 if (res
== ERROR_LOCK_PATH
) {
6974 ast_log(LOG_ERROR
, "Could not leave voicemail. The path is already locked.\n");
6975 /*Send the call to n+101 priority, where n is the current priority*/
6976 if (ast_test_flag(&leave_options
, OPT_PRIORITY_JUMP
) || ast_opt_priority_jumping
)
6977 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101))
6978 ast_log(LOG_WARNING
, "Extension %s, priority %d doesn't exist.\n", chan
->exten
, chan
->priority
+ 101);
6979 pbx_builtin_setvar_helper(chan
, "VMSTATUS", "FAILED");
6983 ast_module_user_remove(u
);
6988 static struct ast_vm_user
*find_or_create(char *context
, char *mbox
)
6990 struct ast_vm_user
*vmu
;
6991 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
6992 if (ast_test_flag((&globalflags
), VM_SEARCH
) && !strcasecmp(mbox
, vmu
->mailbox
))
6994 if (context
&& (!strcasecmp(context
, vmu
->context
)) && (!strcasecmp(mbox
, vmu
->mailbox
)))
6999 if ((vmu
= ast_calloc(1, sizeof(*vmu
)))) {
7000 ast_copy_string(vmu
->context
, context
, sizeof(vmu
->context
));
7001 ast_copy_string(vmu
->mailbox
, mbox
, sizeof(vmu
->mailbox
));
7002 AST_LIST_INSERT_TAIL(&users
, vmu
, list
);
7008 static int append_mailbox(char *context
, char *mbox
, char *data
)
7010 /* Assumes lock is already held */
7014 struct ast_vm_user
*vmu
;
7016 tmp
= ast_strdupa(data
);
7018 if ((vmu
= find_or_create(context
, mbox
))) {
7019 populate_defaults(vmu
);
7022 if ((s
= strsep(&stringp
, ",")))
7023 ast_copy_string(vmu
->password
, s
, sizeof(vmu
->password
));
7024 if (stringp
&& (s
= strsep(&stringp
, ",")))
7025 ast_copy_string(vmu
->fullname
, s
, sizeof(vmu
->fullname
));
7026 if (stringp
&& (s
= strsep(&stringp
, ",")))
7027 ast_copy_string(vmu
->email
, s
, sizeof(vmu
->email
));
7028 if (stringp
&& (s
= strsep(&stringp
, ",")))
7029 ast_copy_string(vmu
->pager
, s
, sizeof(vmu
->pager
));
7030 if (stringp
&& (s
= strsep(&stringp
, ",")))
7031 apply_options(vmu
, s
);
7036 static int vm_box_exists(struct ast_channel
*chan
, void *data
)
7038 struct ast_module_user
*u
;
7039 struct ast_vm_user svm
;
7040 char *context
, *box
;
7041 int priority_jump
= 0;
7042 AST_DECLARE_APP_ARGS(args
,
7044 AST_APP_ARG(options
);
7047 if (ast_strlen_zero(data
)) {
7048 ast_log(LOG_ERROR
, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
7052 u
= ast_module_user_add(chan
);
7054 box
= ast_strdupa(data
);
7056 AST_STANDARD_APP_ARGS(args
, box
);
7059 if (strchr(args
.options
, 'j'))
7063 if ((context
= strchr(args
.mbox
, '@'))) {
7068 if (find_user(&svm
, context
, args
.mbox
)) {
7069 pbx_builtin_setvar_helper(chan
, "VMBOXEXISTSSTATUS", "SUCCESS");
7070 if (priority_jump
|| ast_opt_priority_jumping
)
7071 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101))
7072 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);
7074 pbx_builtin_setvar_helper(chan
, "VMBOXEXISTSSTATUS", "FAILED");
7075 ast_module_user_remove(u
);
7079 static int vmauthenticate(struct ast_channel
*chan
, void *data
)
7081 struct ast_module_user
*u
;
7082 char *s
= data
, *user
=NULL
, *context
=NULL
, mailbox
[AST_MAX_EXTENSION
] = "";
7083 struct ast_vm_user vmus
;
7084 char *options
= NULL
;
7085 int silent
= 0, skipuser
= 0;
7088 u
= ast_module_user_add(chan
);
7092 user
= strsep(&s
, "|");
7093 options
= strsep(&s
, "|");
7096 user
= strsep(&s
, "@");
7097 context
= strsep(&s
, "");
7098 if (!ast_strlen_zero(user
))
7100 ast_copy_string(mailbox
, user
, sizeof(mailbox
));
7105 silent
= (strchr(options
, 's')) != NULL
;
7108 if (!vm_authenticate(chan
, mailbox
, sizeof(mailbox
), &vmus
, context
, NULL
, skipuser
, 3, silent
)) {
7109 pbx_builtin_setvar_helper(chan
, "AUTH_MAILBOX", mailbox
);
7110 pbx_builtin_setvar_helper(chan
, "AUTH_CONTEXT", vmus
.context
);
7111 ast_play_and_wait(chan
, "auth-thankyou");
7115 ast_module_user_remove(u
);
7119 static char voicemail_show_users_help
[] =
7120 "Usage: voicemail show users [for <context>]\n"
7121 " Lists all mailboxes currently set up\n";
7123 static char voicemail_show_zones_help
[] =
7124 "Usage: voicemail show zones\n"
7125 " Lists zone message formats\n";
7127 static int handle_voicemail_show_users(int fd
, int argc
, char *argv
[])
7129 struct ast_vm_user
*vmu
;
7130 char *output_format
= "%-10s %-5s %-25s %-10s %6s\n";
7132 if ((argc
< 3) || (argc
> 5) || (argc
== 4)) return RESULT_SHOWUSAGE
;
7133 else if ((argc
== 5) && strcmp(argv
[3],"for")) return RESULT_SHOWUSAGE
;
7135 AST_LIST_LOCK(&users
);
7136 if (!AST_LIST_EMPTY(&users
)) {
7138 ast_cli(fd
, output_format
, "Context", "Mbox", "User", "Zone", "NewMsg");
7141 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7142 if (!strcmp(argv
[4],vmu
->context
))
7146 ast_cli(fd
, output_format
, "Context", "Mbox", "User", "Zone", "NewMsg");
7148 ast_cli(fd
, "No such voicemail context \"%s\"\n", argv
[4]);
7149 AST_LIST_UNLOCK(&users
);
7150 return RESULT_FAILURE
;
7153 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7154 int newmsgs
= 0, oldmsgs
= 0;
7155 char count
[12], tmp
[256] = "";
7157 if ((argc
== 3) || ((argc
== 5) && !strcmp(argv
[4],vmu
->context
))) {
7158 snprintf(tmp
, sizeof(tmp
), "%s@%s", vmu
->mailbox
, ast_strlen_zero(vmu
->context
) ? "default" : vmu
->context
);
7159 inboxcount(tmp
, &newmsgs
, &oldmsgs
);
7160 snprintf(count
,sizeof(count
),"%d",newmsgs
);
7161 ast_cli(fd
, output_format
, vmu
->context
, vmu
->mailbox
, vmu
->fullname
, vmu
->zonetag
, count
);
7165 ast_cli(fd
, "There are no voicemail users currently defined\n");
7166 AST_LIST_UNLOCK(&users
);
7167 return RESULT_FAILURE
;
7169 AST_LIST_UNLOCK(&users
);
7170 return RESULT_SUCCESS
;
7173 static int handle_voicemail_show_zones(int fd
, int argc
, char *argv
[])
7175 struct vm_zone
*zone
;
7176 char *output_format
= "%-15s %-20s %-45s\n";
7177 int res
= RESULT_SUCCESS
;
7180 return RESULT_SHOWUSAGE
;
7182 AST_LIST_LOCK(&zones
);
7183 if (!AST_LIST_EMPTY(&zones
)) {
7184 ast_cli(fd
, output_format
, "Zone", "Timezone", "Message Format");
7185 AST_LIST_TRAVERSE(&zones
, zone
, list
) {
7186 ast_cli(fd
, output_format
, zone
->name
, zone
->timezone
, zone
->msg_format
);
7189 ast_cli(fd
, "There are no voicemail zones currently defined\n");
7190 res
= RESULT_FAILURE
;
7192 AST_LIST_UNLOCK(&zones
);
7197 static char *complete_voicemail_show_users(const char *line
, const char *word
, int pos
, int state
)
7201 struct ast_vm_user
*vmu
;
7202 const char *context
= "";
7204 /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
7208 return (state
== 0) ? ast_strdup("for") : NULL
;
7209 wordlen
= strlen(word
);
7210 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
7211 if (!strncasecmp(word
, vmu
->context
, wordlen
)) {
7212 if (context
&& strcmp(context
, vmu
->context
) && ++which
> state
)
7213 return ast_strdup(vmu
->context
);
7214 /* ignore repeated contexts ? */
7215 context
= vmu
->context
;
7221 static struct ast_cli_entry cli_show_voicemail_users_deprecated
= {
7222 { "show", "voicemail", "users", NULL
},
7223 handle_voicemail_show_users
, NULL
,
7224 NULL
, complete_voicemail_show_users
};
7226 static struct ast_cli_entry cli_show_voicemail_zones_deprecated
= {
7227 { "show", "voicemail", "zones", NULL
},
7228 handle_voicemail_show_zones
, NULL
,
7231 static struct ast_cli_entry cli_voicemail
[] = {
7232 { { "voicemail", "show", "users", NULL
},
7233 handle_voicemail_show_users
, "List defined voicemail boxes",
7234 voicemail_show_users_help
, complete_voicemail_show_users
, &cli_show_voicemail_users_deprecated
},
7236 { { "voicemail", "show", "zones", NULL
},
7237 handle_voicemail_show_zones
, "List zone message formats",
7238 voicemail_show_zones_help
, NULL
, &cli_show_voicemail_zones_deprecated
},
7241 static int load_config(void)
7243 struct ast_vm_user
*cur
;
7244 struct vm_zone
*zcur
;
7245 struct ast_config
*cfg
, *ucfg
;
7247 struct ast_variable
*var
;
7248 const char *notifystr
= NULL
;
7249 const char *smdistr
= NULL
;
7250 const char *astattach
;
7251 const char *astsearch
;
7252 const char *astsaycid
;
7253 const char *send_voicemail
;
7255 const char *imap_server
;
7256 const char *imap_port
;
7257 const char *imap_flags
;
7258 const char *imap_folder
;
7259 const char *auth_user
;
7260 const char *auth_password
;
7261 const char *expunge_on_hangup
;
7263 const char *astcallop
;
7264 const char *astreview
;
7265 const char *asttempgreetwarn
;
7266 const char *astskipcmd
;
7267 const char *asthearenv
;
7268 const char *astsaydurationinfo
;
7269 const char *astsaydurationminfo
;
7270 const char *silencestr
;
7271 const char *maxmsgstr
;
7272 const char *astdirfwd
;
7273 const char *thresholdstr
;
7275 const char *astemail
;
7276 const char *ucontext
;
7277 const char *astmailcmd
= SENDMAIL
;
7278 const char *astforcename
;
7279 const char *astforcegreet
;
7282 const char *dialoutcxt
= NULL
;
7283 const char *callbackcxt
= NULL
;
7284 const char *exitcxt
= NULL
;
7286 const char *emaildateformatstr
;
7287 const char *volgainstr
;
7291 cfg
= ast_config_load(VOICEMAIL_CONFIG
);
7293 AST_LIST_LOCK(&users
);
7294 while ((cur
= AST_LIST_REMOVE_HEAD(&users
, list
))) {
7295 ast_set_flag(cur
, VM_ALLOCED
);
7299 AST_LIST_LOCK(&zones
);
7300 while ((zcur
= AST_LIST_REMOVE_HEAD(&zones
, list
)))
7302 AST_LIST_UNLOCK(&zones
);
7304 memset(ext_pass_cmd
, 0, sizeof(ext_pass_cmd
));
7307 /* General settings */
7309 if (!(ucontext
= ast_variable_retrieve(cfg
, "general", "userscontext")))
7310 ucontext
= "default";
7311 ast_copy_string(userscontext
, ucontext
, sizeof(userscontext
));
7312 /* Attach voice message to mail message ? */
7313 if (!(astattach
= ast_variable_retrieve(cfg
, "general", "attach")))
7315 ast_set2_flag((&globalflags
), ast_true(astattach
), VM_ATTACH
);
7317 if (!(astsearch
= ast_variable_retrieve(cfg
, "general", "searchcontexts")))
7319 ast_set2_flag((&globalflags
), ast_true(astsearch
), VM_SEARCH
);
7322 if ((volgainstr
= ast_variable_retrieve(cfg
, "general", "volgain")))
7323 sscanf(volgainstr
, "%lf", &volgain
);
7326 strcpy(odbc_database
, "asterisk");
7327 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "odbcstorage"))) {
7328 ast_copy_string(odbc_database
, thresholdstr
, sizeof(odbc_database
));
7330 strcpy(odbc_table
, "voicemessages");
7331 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "odbctable"))) {
7332 ast_copy_string(odbc_table
, thresholdstr
, sizeof(odbc_table
));
7336 strcpy(mailcmd
, SENDMAIL
);
7337 if ((astmailcmd
= ast_variable_retrieve(cfg
, "general", "mailcmd")))
7338 ast_copy_string(mailcmd
, astmailcmd
, sizeof(mailcmd
)); /* User setting */
7341 if ((silencestr
= ast_variable_retrieve(cfg
, "general", "maxsilence"))) {
7342 maxsilence
= atoi(silencestr
);
7347 if (!(maxmsgstr
= ast_variable_retrieve(cfg
, "general", "maxmsg"))) {
7350 maxmsg
= atoi(maxmsgstr
);
7352 ast_log(LOG_WARNING
, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr
, MAXMSG
);
7354 } else if (maxmsg
> MAXMSGLIMIT
) {
7355 ast_log(LOG_WARNING
, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT
, maxmsgstr
);
7356 maxmsg
= MAXMSGLIMIT
;
7360 /* Load date format config for voicemail mail */
7361 if ((emaildateformatstr
= ast_variable_retrieve(cfg
, "general", "emaildateformat"))) {
7362 ast_copy_string(emaildateformat
, emaildateformatstr
, sizeof(emaildateformat
));
7365 /* External password changing command */
7366 if ((extpc
= ast_variable_retrieve(cfg
, "general", "externpass"))) {
7367 ast_copy_string(ext_pass_cmd
,extpc
,sizeof(ext_pass_cmd
));
7370 /* IMAP server address */
7371 if ((imap_server
= ast_variable_retrieve(cfg
, "general", "imapserver"))) {
7372 ast_copy_string(imapserver
, imap_server
, sizeof(imapserver
));
7374 ast_copy_string(imapserver
,"localhost", sizeof(imapserver
));
7376 /* IMAP server port */
7377 if ((imap_port
= ast_variable_retrieve(cfg
, "general", "imapport"))) {
7378 ast_copy_string(imapport
, imap_port
, sizeof(imapport
));
7380 ast_copy_string(imapport
,"143", sizeof(imapport
));
7382 /* IMAP server flags */
7383 if ((imap_flags
= ast_variable_retrieve(cfg
, "general", "imapflags"))) {
7384 ast_copy_string(imapflags
, imap_flags
, sizeof(imapflags
));
7386 /* IMAP server master username */
7387 if ((auth_user
= ast_variable_retrieve(cfg
, "general", "authuser"))) {
7388 ast_copy_string(authuser
, auth_user
, sizeof(authuser
));
7390 /* IMAP server master password */
7391 if ((auth_password
= ast_variable_retrieve(cfg
, "general", "authpassword"))) {
7392 ast_copy_string(authpassword
, auth_password
, sizeof(authpassword
));
7394 /* Expunge on exit */
7395 if ((expunge_on_hangup
= ast_variable_retrieve(cfg
, "general", "expungeonhangup"))) {
7396 if(ast_false(expunge_on_hangup
))
7397 expungeonhangup
= 0;
7399 expungeonhangup
= 1;
7401 expungeonhangup
= 1;
7403 /* IMAP voicemail folder */
7404 if ((imap_folder
= ast_variable_retrieve(cfg
, "general", "imapfolder"))) {
7405 ast_copy_string(imapfolder
, imap_folder
, sizeof(imapfolder
));
7407 ast_copy_string(imapfolder
,"INBOX", sizeof(imapfolder
));
7410 /* External voicemail notify application */
7412 if ((notifystr
= ast_variable_retrieve(cfg
, "general", "externnotify"))) {
7413 ast_copy_string(externnotify
, notifystr
, sizeof(externnotify
));
7414 if (option_debug
> 2)
7415 ast_log(LOG_DEBUG
, "found externnotify: %s\n", externnotify
);
7416 if (!strcasecmp(externnotify
, "smdi")) {
7418 ast_log(LOG_DEBUG
, "Using SMDI for external voicemail notification\n");
7419 if ((smdistr
= ast_variable_retrieve(cfg
, "general", "smdiport"))) {
7420 smdi_iface
= ast_smdi_interface_find(smdistr
);
7423 ast_log(LOG_DEBUG
, "No SMDI interface set, trying default (/dev/ttyS0)\n");
7424 smdi_iface
= ast_smdi_interface_find("/dev/ttyS0");
7428 ast_log(LOG_ERROR
, "No valid SMDI interface specfied, disabling external voicemail notification\n");
7429 externnotify
[0] = '\0';
7431 if (option_debug
> 2)
7432 ast_log(LOG_DEBUG
, "Using SMDI port %s\n", smdi_iface
->name
);
7436 externnotify
[0] = '\0';
7439 /* Silence treshold */
7440 silencethreshold
= 256;
7441 if ((thresholdstr
= ast_variable_retrieve(cfg
, "general", "silencethreshold")))
7442 silencethreshold
= atoi(thresholdstr
);
7444 if (!(astemail
= ast_variable_retrieve(cfg
, "general", "serveremail")))
7445 astemail
= ASTERISK_USERNAME
;
7446 ast_copy_string(serveremail
, astemail
, sizeof(serveremail
));
7449 if ((s
= ast_variable_retrieve(cfg
, "general", "maxmessage"))) {
7450 if (sscanf(s
, "%d", &x
) == 1) {
7453 ast_log(LOG_WARNING
, "Invalid max message time length\n");
7458 if ((s
= ast_variable_retrieve(cfg
, "general", "minmessage"))) {
7459 if (sscanf(s
, "%d", &x
) == 1) {
7461 if (maxsilence
<= vmminmessage
)
7462 ast_log(LOG_WARNING
, "maxsilence should be less than minmessage or you may get empty messages\n");
7464 ast_log(LOG_WARNING
, "Invalid min message time length\n");
7467 fmt
= ast_variable_retrieve(cfg
, "general", "format");
7470 ast_copy_string(vmfmts
, fmt
, sizeof(vmfmts
));
7473 if ((s
= ast_variable_retrieve(cfg
, "general", "maxgreet"))) {
7474 if (sscanf(s
, "%d", &x
) == 1) {
7477 ast_log(LOG_WARNING
, "Invalid max message greeting length\n");
7481 if ((s
= ast_variable_retrieve(cfg
, "general", "skipms"))) {
7482 if (sscanf(s
, "%d", &x
) == 1) {
7485 ast_log(LOG_WARNING
, "Invalid skipms value\n");
7490 if ((s
= ast_variable_retrieve(cfg
, "general", "maxlogins"))) {
7491 if (sscanf(s
, "%d", &x
) == 1) {
7494 ast_log(LOG_WARNING
, "Invalid max failed login attempts\n");
7498 /* Force new user to record name ? */
7499 if (!(astforcename
= ast_variable_retrieve(cfg
, "general", "forcename")))
7500 astforcename
= "no";
7501 ast_set2_flag((&globalflags
), ast_true(astforcename
), VM_FORCENAME
);
7503 /* Force new user to record greetings ? */
7504 if (!(astforcegreet
= ast_variable_retrieve(cfg
, "general", "forcegreetings")))
7505 astforcegreet
= "no";
7506 ast_set2_flag((&globalflags
), ast_true(astforcegreet
), VM_FORCEGREET
);
7508 if ((s
= ast_variable_retrieve(cfg
, "general", "cidinternalcontexts"))){
7509 if (option_debug
> 2)
7510 ast_log(LOG_DEBUG
,"VM_CID Internal context string: %s\n",s
);
7511 stringp
= ast_strdupa(s
);
7512 for (x
= 0 ; x
< MAX_NUM_CID_CONTEXTS
; x
++){
7513 if (!ast_strlen_zero(stringp
)) {
7514 q
= strsep(&stringp
,",");
7515 while ((*q
== ' ')||(*q
== '\t')) /* Eat white space between contexts */
7517 ast_copy_string(cidinternalcontexts
[x
], q
, sizeof(cidinternalcontexts
[x
]));
7518 if (option_debug
> 2)
7519 ast_log(LOG_DEBUG
,"VM_CID Internal context %d: %s\n", x
, cidinternalcontexts
[x
]);
7521 cidinternalcontexts
[x
][0] = '\0';
7525 if (!(astreview
= ast_variable_retrieve(cfg
, "general", "review"))){
7527 ast_log(LOG_DEBUG
,"VM Review Option disabled globally\n");
7530 ast_set2_flag((&globalflags
), ast_true(astreview
), VM_REVIEW
);
7532 /*Temperary greeting reminder */
7533 if (!(asttempgreetwarn
= ast_variable_retrieve(cfg
, "general", "tempgreetwarn"))) {
7535 ast_log(LOG_DEBUG
, "VM Temperary Greeting Reminder Option disabled globally\n");
7536 asttempgreetwarn
= "no";
7539 ast_log(LOG_DEBUG
, "VM Temperary Greeting Reminder Option enabled globally\n");
7541 ast_set2_flag((&globalflags
), ast_true(asttempgreetwarn
), VM_TEMPGREETWARN
);
7543 if (!(astcallop
= ast_variable_retrieve(cfg
, "general", "operator"))){
7545 ast_log(LOG_DEBUG
,"VM Operator break disabled globally\n");
7548 ast_set2_flag((&globalflags
), ast_true(astcallop
), VM_OPERATOR
);
7550 if (!(astsaycid
= ast_variable_retrieve(cfg
, "general", "saycid"))) {
7552 ast_log(LOG_DEBUG
,"VM CID Info before msg disabled globally\n");
7555 ast_set2_flag((&globalflags
), ast_true(astsaycid
), VM_SAYCID
);
7557 if (!(send_voicemail
= ast_variable_retrieve(cfg
,"general", "sendvoicemail"))){
7559 ast_log(LOG_DEBUG
,"Send Voicemail msg disabled globally\n");
7560 send_voicemail
= "no";
7562 ast_set2_flag((&globalflags
), ast_true(send_voicemail
), VM_SVMAIL
);
7564 if (!(asthearenv
= ast_variable_retrieve(cfg
, "general", "envelope"))) {
7566 ast_log(LOG_DEBUG
,"ENVELOPE before msg enabled globally\n");
7569 ast_set2_flag((&globalflags
), ast_true(asthearenv
), VM_ENVELOPE
);
7571 if (!(astsaydurationinfo
= ast_variable_retrieve(cfg
, "general", "sayduration"))) {
7573 ast_log(LOG_DEBUG
,"Duration info before msg enabled globally\n");
7574 astsaydurationinfo
= "yes";
7576 ast_set2_flag((&globalflags
), ast_true(astsaydurationinfo
), VM_SAYDURATION
);
7578 saydurationminfo
= 2;
7579 if ((astsaydurationminfo
= ast_variable_retrieve(cfg
, "general", "saydurationm"))) {
7580 if (sscanf(astsaydurationminfo
, "%d", &x
) == 1) {
7581 saydurationminfo
= x
;
7583 ast_log(LOG_WARNING
, "Invalid min duration for say duration\n");
7587 if (!(astskipcmd
= ast_variable_retrieve(cfg
, "general", "nextaftercmd"))) {
7589 ast_log(LOG_DEBUG
,"We are not going to skip to the next msg after save/delete\n");
7592 ast_set2_flag((&globalflags
), ast_true(astskipcmd
), VM_SKIPAFTERCMD
);
7594 if ((dialoutcxt
= ast_variable_retrieve(cfg
, "general", "dialout"))) {
7595 ast_copy_string(dialcontext
, dialoutcxt
, sizeof(dialcontext
));
7597 ast_log(LOG_DEBUG
, "found dialout context: %s\n", dialcontext
);
7599 dialcontext
[0] = '\0';
7602 if ((callbackcxt
= ast_variable_retrieve(cfg
, "general", "callback"))) {
7603 ast_copy_string(callcontext
, callbackcxt
, sizeof(callcontext
));
7605 ast_log(LOG_DEBUG
, "found callback context: %s\n", callcontext
);
7607 callcontext
[0] = '\0';
7610 if ((exitcxt
= ast_variable_retrieve(cfg
, "general", "exitcontext"))) {
7611 ast_copy_string(exitcontext
, exitcxt
, sizeof(exitcontext
));
7613 ast_log(LOG_DEBUG
, "found operator context: %s\n", exitcontext
);
7615 exitcontext
[0] = '\0';
7618 if (!(astdirfwd
= ast_variable_retrieve(cfg
, "general", "usedirectory")))
7620 ast_set2_flag((&globalflags
), ast_true(astdirfwd
), VM_DIRECFORWARD
);
7621 if ((ucfg
= ast_config_load("users.conf"))) {
7622 for (cat
= ast_category_browse(ucfg
, NULL
); cat
; cat
= ast_category_browse(ucfg
, cat
)) {
7623 if (!ast_true(ast_config_option(ucfg
, cat
, "hasvoicemail")))
7625 if ((cur
= find_or_create(userscontext
, cat
))) {
7626 populate_defaults(cur
);
7627 apply_options_full(cur
, ast_variable_browse(ucfg
, cat
));
7628 ast_copy_string(cur
->context
, userscontext
, sizeof(cur
->context
));
7631 ast_config_destroy(ucfg
);
7633 cat
= ast_category_browse(cfg
, NULL
);
7635 if (strcasecmp(cat
, "general")) {
7636 var
= ast_variable_browse(cfg
, cat
);
7637 if (strcasecmp(cat
, "zonemessages")) {
7638 /* Process mailboxes in this context */
7640 append_mailbox(cat
, var
->name
, var
->value
);
7644 /* Timezones in this context */
7647 if ((z
= ast_malloc(sizeof(*z
)))) {
7648 char *msg_format
, *timezone
;
7649 msg_format
= ast_strdupa(var
->value
);
7650 timezone
= strsep(&msg_format
, "|");
7652 ast_copy_string(z
->name
, var
->name
, sizeof(z
->name
));
7653 ast_copy_string(z
->timezone
, timezone
, sizeof(z
->timezone
));
7654 ast_copy_string(z
->msg_format
, msg_format
, sizeof(z
->msg_format
));
7655 AST_LIST_LOCK(&zones
);
7656 AST_LIST_INSERT_HEAD(&zones
, z
, list
);
7657 AST_LIST_UNLOCK(&zones
);
7659 ast_log(LOG_WARNING
, "Invalid timezone definition at line %d\n", var
->lineno
);
7664 AST_LIST_UNLOCK(&users
);
7665 ast_config_destroy(cfg
);
7672 cat
= ast_category_browse(cfg
, cat
);
7674 memset(fromstring
,0,sizeof(fromstring
));
7675 memset(pagerfromstring
,0,sizeof(pagerfromstring
));
7676 memset(emailtitle
,0,sizeof(emailtitle
));
7677 strcpy(charset
, "ISO-8859-1");
7684 emailsubject
= NULL
;
7692 pagersubject
= NULL
;
7694 if ((s
= ast_variable_retrieve(cfg
, "general", "pbxskip")))
7695 ast_set2_flag((&globalflags
), ast_true(s
), VM_PBXSKIP
);
7696 if ((s
= ast_variable_retrieve(cfg
, "general", "fromstring")))
7697 ast_copy_string(fromstring
,s
,sizeof(fromstring
));
7698 if ((s
= ast_variable_retrieve(cfg
, "general", "pagerfromstring")))
7699 ast_copy_string(pagerfromstring
,s
,sizeof(pagerfromstring
));
7700 if ((s
= ast_variable_retrieve(cfg
, "general", "charset")))
7701 ast_copy_string(charset
,s
,sizeof(charset
));
7702 if ((s
= ast_variable_retrieve(cfg
, "general", "adsifdn"))) {
7703 sscanf(s
, "%2x%2x%2x%2x", &tmpadsi
[0], &tmpadsi
[1], &tmpadsi
[2], &tmpadsi
[3]);
7704 for (x
= 0; x
< 4; x
++) {
7705 memcpy(&adsifdn
[x
], &tmpadsi
[x
], 1);
7708 if ((s
= ast_variable_retrieve(cfg
, "general", "adsisec"))) {
7709 sscanf(s
, "%2x%2x%2x%2x", &tmpadsi
[0], &tmpadsi
[1], &tmpadsi
[2], &tmpadsi
[3]);
7710 for (x
= 0; x
< 4; x
++) {
7711 memcpy(&adsisec
[x
], &tmpadsi
[x
], 1);
7714 if ((s
= ast_variable_retrieve(cfg
, "general", "adsiver")))
7718 if ((s
= ast_variable_retrieve(cfg
, "general", "emailtitle"))) {
7719 ast_log(LOG_NOTICE
, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
7720 ast_copy_string(emailtitle
,s
,sizeof(emailtitle
));
7722 if ((s
= ast_variable_retrieve(cfg
, "general", "emailsubject")))
7723 emailsubject
= ast_strdup(s
);
7724 if ((s
= ast_variable_retrieve(cfg
, "general", "emailbody"))) {
7725 char *tmpread
, *tmpwrite
;
7726 emailbody
= ast_strdup(s
);
7728 /* substitute strings \t and \n into the appropriate characters */
7729 tmpread
= tmpwrite
= emailbody
;
7730 while ((tmpwrite
= strchr(tmpread
,'\\'))) {
7731 switch (tmpwrite
[1]) {
7733 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7737 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7741 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7745 ast_log(LOG_NOTICE
, "Substitution routine does not support this character: %c\n", tmpwrite
[1]);
7747 tmpread
= tmpwrite
+ 1;
7750 if ((s
= ast_variable_retrieve(cfg
, "general", "pagersubject")))
7751 pagersubject
= ast_strdup(s
);
7752 if ((s
= ast_variable_retrieve(cfg
, "general", "pagerbody"))) {
7753 char *tmpread
, *tmpwrite
;
7754 pagerbody
= ast_strdup(s
);
7756 /* substitute strings \t and \n into the appropriate characters */
7757 tmpread
= tmpwrite
= pagerbody
;
7758 while ((tmpwrite
= strchr(tmpread
, '\\'))) {
7759 switch (tmpwrite
[1]) {
7761 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7765 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7769 memmove(tmpwrite
+ 1, tmpwrite
+ 2, strlen(tmpwrite
+ 2) + 1);
7773 ast_log(LOG_NOTICE
, "Substitution routine does not support this character: %c\n", tmpwrite
[1]);
7775 tmpread
= tmpwrite
+ 1;
7778 AST_LIST_UNLOCK(&users
);
7779 ast_config_destroy(cfg
);
7782 AST_LIST_UNLOCK(&users
);
7783 ast_log(LOG_WARNING
, "Failed to load configuration file.\n");
7788 static int reload(void)
7790 return(load_config());
7793 static int unload_module(void)
7797 res
= ast_unregister_application(app
);
7798 res
|= ast_unregister_application(app2
);
7799 res
|= ast_unregister_application(app3
);
7800 res
|= ast_unregister_application(app4
);
7801 ast_cli_unregister_multiple(cli_voicemail
, sizeof(cli_voicemail
) / sizeof(struct ast_cli_entry
));
7802 ast_uninstall_vm_functions();
7804 ast_module_user_hangup_all();
7809 static int load_module(void)
7812 my_umask
= umask(0);
7814 res
= ast_register_application(app
, vm_exec
, synopsis_vm
, descrip_vm
);
7815 res
|= ast_register_application(app2
, vm_execmain
, synopsis_vmain
, descrip_vmain
);
7816 res
|= ast_register_application(app3
, vm_box_exists
, synopsis_vm_box_exists
, descrip_vm_box_exists
);
7817 res
|= ast_register_application(app4
, vmauthenticate
, synopsis_vmauthenticate
, descrip_vmauthenticate
);
7821 if ((res
=load_config())) {
7825 ast_cli_register_multiple(cli_voicemail
, sizeof(cli_voicemail
) / sizeof(struct ast_cli_entry
));
7827 /* compute the location of the voicemail spool directory */
7828 snprintf(VM_SPOOL_DIR
, sizeof(VM_SPOOL_DIR
), "%s/voicemail/", ast_config_AST_SPOOL_DIR
);
7830 ast_install_vm_functions(has_voicemail
, inboxcount
, messagecount
);
7835 static int dialout(struct ast_channel
*chan
, struct ast_vm_user
*vmu
, char *num
, char *outgoing_context
)
7838 char destination
[80] = "";
7842 if (option_verbose
> 2)
7843 ast_verbose( VERBOSE_PREFIX_3
"Destination number will be entered manually\n");
7844 while (retries
< 3 && cmd
!= 't') {
7845 destination
[1] = '\0';
7846 destination
[0] = cmd
= ast_play_and_wait(chan
,"vm-enter-num-to-call");
7848 destination
[0] = cmd
= ast_play_and_wait(chan
, "vm-then-pound");
7850 destination
[0] = cmd
= ast_play_and_wait(chan
, "vm-star-cancel");
7852 cmd
= ast_waitfordigit(chan
, 6000);
7854 destination
[0] = cmd
;
7863 if (option_verbose
> 2)
7864 ast_verbose( VERBOSE_PREFIX_3
"User hit '*' to cancel outgoing call\n");
7867 if ((cmd
= ast_readstring(chan
,destination
+ strlen(destination
),sizeof(destination
)-1,6000,10000,"#")) < 0)
7878 if (option_verbose
> 2)
7879 ast_verbose( VERBOSE_PREFIX_3
"Destination number is CID number '%s'\n", num
);
7880 ast_copy_string(destination
, num
, sizeof(destination
));
7883 if (!ast_strlen_zero(destination
)) {
7884 if (destination
[strlen(destination
) -1 ] == '*')
7886 if (option_verbose
> 2)
7887 ast_verbose( VERBOSE_PREFIX_3
"Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination
, outgoing_context
, chan
->context
);
7888 ast_copy_string(chan
->exten
, destination
, sizeof(chan
->exten
));
7889 ast_copy_string(chan
->context
, outgoing_context
, sizeof(chan
->context
));
7896 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
)
7900 char origtimeS
[256],cidS
[256],contextS
[256];
7901 char *header_content
,*temp
;
7903 char filename
[PATH_MAX
];
7904 struct ast_config
*msg_cfg
= NULL
;
7905 const char *origtime
, *context
;
7906 char *cid
, *name
, *num
;
7912 /* get the message info!! */
7913 if(option_debug
> 2)
7914 ast_log (LOG_DEBUG
,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms
->curmsg
, vms
->msgArray
[vms
->curmsg
]);
7915 if (vms
->msgArray
[vms
->curmsg
] == 0) {
7916 ast_log (LOG_WARNING
,"Trying to access unknown message\n");
7920 /* This will only work for new messages... */
7921 header_content
= mail_fetchheader (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
]);
7922 /* empty string means no valid header */
7923 if (ast_strlen_zero(header_content
)) {
7924 ast_log (LOG_ERROR
,"Could not fetch header for message number %ld\n",vms
->msgArray
[vms
->curmsg
]);
7928 /* Get info from headers!! */
7929 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Caller-ID-Num:");
7932 ast_copy_string(cidS
,temp
, sizeof(cidS
));
7937 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Context:");
7940 ast_copy_string(contextS
,temp
, sizeof(contextS
));
7944 context
= &contextS
[0];
7945 temp
= get_header_by_tag(header_content
, "X-Asterisk-VM-Orig-time:");
7948 ast_copy_string(origtimeS
,temp
, sizeof(origtimeS
));
7950 origtimeS
[0] = '\0';
7952 origtime
= &origtimeS
[0];
7954 ast_copy_string(filename
, "IMAP_STORAGE", sizeof(filename
));
7956 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, msg
);
7958 /* Retrieve info from VM attribute file */
7960 make_file(vms
->fn2
, sizeof(vms
->fn2
), vms
->curdir
, vms
->curmsg
);
7961 snprintf(filename
,sizeof(filename
), "%s.txt", vms
->fn2
);
7962 RETRIEVE(vms
->curdir
, vms
->curmsg
);
7963 msg_cfg
= ast_config_load(filename
);
7964 DISPOSE(vms
->curdir
, vms
->curmsg
);
7966 ast_log(LOG_WARNING
, "No message attribute file?!! (%s)\n", filename
);
7970 if (!(origtime
= ast_variable_retrieve(msg_cfg
, "message", "origtime"))) {
7971 ast_config_destroy(msg_cfg
);
7975 cid
= ast_strdupa(ast_variable_retrieve(msg_cfg
, "message", "callerid"));
7977 context
= ast_variable_retrieve(msg_cfg
, "message", "context");
7978 if (!strncasecmp("macro",context
,5)) /* Macro names in contexts are useless for our needs */
7979 context
= ast_variable_retrieve(msg_cfg
, "message","macrocontext");
7984 res
= play_message_datetime(chan
, vmu
, origtime
, filename
);
7986 res
= play_message_callerid(chan
, vms
, cid
, context
, 0);
7991 case 2: /* Call back */
7993 if (ast_strlen_zero(cid
))
7996 ast_callerid_parse(cid
, &name
, &num
);
7997 while ((res
> -1) && (res
!= 't')) {
8001 /* Dial the CID number */
8002 res
= dialout(chan
, vmu
, num
, vmu
->callback
);
8004 ast_config_destroy(msg_cfg
);
8013 /* Want to enter a different number, can only do this if there's a dialout context for this user */
8014 if (!ast_strlen_zero(vmu
->dialout
)) {
8015 res
= dialout(chan
, vmu
, NULL
, vmu
->dialout
);
8017 ast_config_destroy(msg_cfg
);
8021 if (option_verbose
> 2)
8022 ast_verbose( VERBOSE_PREFIX_3
"Caller can not specify callback number - no dialout context available\n");
8023 res
= ast_play_and_wait(chan
, "vm-sorry");
8025 ast_config_destroy(msg_cfg
);
8039 res
= ast_play_and_wait(chan
, "vm-sorry");
8044 if (option_verbose
> 2)
8045 ast_verbose( VERBOSE_PREFIX_3
"Confirm CID number '%s' is number to use for callback\n", num
);
8046 res
= ast_play_and_wait(chan
, "vm-num-i-have");
8048 res
= play_message_callerid(chan
, vms
, num
, vmu
->context
, 1);
8050 res
= ast_play_and_wait(chan
, "vm-tocallnum");
8051 /* Only prompt for a caller-specified number if there is a dialout context specified */
8052 if (!ast_strlen_zero(vmu
->dialout
)) {
8054 res
= ast_play_and_wait(chan
, "vm-calldiffnum");
8057 res
= ast_play_and_wait(chan
, "vm-nonumber");
8058 if (!ast_strlen_zero(vmu
->dialout
)) {
8060 res
= ast_play_and_wait(chan
, "vm-toenternumber");
8064 res
= ast_play_and_wait(chan
, "vm-star-cancel");
8066 res
= ast_waitfordigit(chan
, 6000);
8077 else if (res
== '*')
8083 /* Send reply directly to sender */
8084 if (ast_strlen_zero(cid
))
8087 ast_callerid_parse(cid
, &name
, &num
);
8089 if (option_verbose
> 2)
8090 ast_verbose(VERBOSE_PREFIX_3
"No CID number available, no reply sent\n");
8092 res
= ast_play_and_wait(chan
, "vm-nonumber");
8093 ast_config_destroy(msg_cfg
);
8096 struct ast_vm_user vmu2
;
8097 if (find_user(&vmu2
, vmu
->context
, num
)) {
8098 struct leave_vm_options leave_options
;
8099 char mailbox
[AST_MAX_EXTENSION
* 2 + 2];
8100 snprintf(mailbox
, sizeof(mailbox
), "%s@%s", num
, vmu
->context
);
8102 if (option_verbose
> 2)
8103 ast_verbose(VERBOSE_PREFIX_3
"Leaving voicemail for '%s' in context '%s'\n", num
, vmu
->context
);
8105 memset(&leave_options
, 0, sizeof(leave_options
));
8106 leave_options
.record_gain
= record_gain
;
8107 res
= leave_voicemail(chan
, mailbox
, &leave_options
);
8110 ast_config_destroy(msg_cfg
);
8113 /* Sender has no mailbox, can't reply */
8114 if (option_verbose
> 2)
8115 ast_verbose( VERBOSE_PREFIX_3
"No mailbox number '%s' in context '%s', no reply sent\n", num
, vmu
->context
);
8116 ast_play_and_wait(chan
, "vm-nobox");
8118 ast_config_destroy(msg_cfg
);
8127 #ifndef IMAP_STORAGE
8128 ast_config_destroy(msg_cfg
);
8131 make_file(vms
->fn
, sizeof(vms
->fn
), vms
->curdir
, msg
);
8132 vms
->heard
[msg
] = 1;
8133 res
= wait_file(chan
, vms
, vms
->fn
);
8139 static int play_record_review(struct ast_channel
*chan
, char *playfile
, char *recordfile
, int maxtime
, char *fmt
,
8140 int outsidecaller
, struct ast_vm_user
*vmu
, int *duration
, const char *unlockdir
,
8141 signed char record_gain
, struct vm_state
*vms
)
8143 /* Record message & let caller review or re-record it, or set options if applicable */
8146 int max_attempts
= 3;
8149 int message_exists
= 0;
8150 signed char zero_gain
= 0;
8151 char tempfile
[PATH_MAX
];
8152 char *acceptdtmf
= "#";
8153 char *canceldtmf
= "";
8155 /* Note that urgent and private are for flagging messages as such in the future */
8157 /* barf if no pointer passed to store duration in */
8158 if (duration
== NULL
) {
8159 ast_log(LOG_WARNING
, "Error play_record_review called without duration pointer\n");
8164 snprintf(tempfile
, sizeof(tempfile
), "%s.tmp", recordfile
);
8166 ast_copy_string(tempfile
, recordfile
, sizeof(tempfile
));
8168 cmd
= '3'; /* Want to start by recording */
8170 while ((cmd
>= 0) && (cmd
!= 't')) {
8173 if (!message_exists
) {
8174 /* In this case, 1 is to record a message */
8178 /* Otherwise 1 is to save the existing message */
8179 if (option_verbose
> 2)
8180 ast_verbose(VERBOSE_PREFIX_3
"Saving message as is\n");
8182 ast_filerename(tempfile
, recordfile
, NULL
);
8183 ast_stream_and_wait(chan
, "vm-msgsaved", chan
->language
, "");
8184 if (!outsidecaller
) {
8185 STORE(recordfile
, vmu
->mailbox
, vmu
->context
, -1, chan
, vmu
, fmt
, *duration
, vms
);
8186 DISPOSE(recordfile
, -1);
8193 if (option_verbose
> 2)
8194 ast_verbose(VERBOSE_PREFIX_3
"Reviewing the message\n");
8195 cmd
= ast_stream_and_wait(chan
, tempfile
, chan
->language
, AST_DIGIT_ANY
);
8200 if (recorded
== 1) {
8201 if (option_verbose
> 2)
8202 ast_verbose(VERBOSE_PREFIX_3
"Re-recording the message\n");
8204 if (option_verbose
> 2)
8205 ast_verbose(VERBOSE_PREFIX_3
"Recording the message\n");
8207 if (recorded
&& outsidecaller
) {
8208 cmd
= ast_play_and_wait(chan
, INTRO
);
8209 cmd
= ast_play_and_wait(chan
, "beep");
8212 /* 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 */
8214 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &record_gain
, sizeof(record_gain
), 0);
8215 if (ast_test_flag(vmu
, VM_OPERATOR
))
8217 cmd
= ast_play_and_record_full(chan
, playfile
, tempfile
, maxtime
, fmt
, duration
, silencethreshold
, maxsilence
, unlockdir
, acceptdtmf
, canceldtmf
);
8219 ast_channel_setoption(chan
, AST_OPTION_RXGAIN
, &zero_gain
, sizeof(zero_gain
), 0);
8221 /* User has hung up, no options to give */
8222 if (!outsidecaller
) {
8223 /* user was recording a greeting and they hung up, so let's delete the recording. */
8224 ast_filedelete(tempfile
, NULL
);
8230 } else if (cmd
== '*') {
8234 else if (vmu
->review
&& (*duration
< 5)) {
8235 /* Message is too short */
8236 if (option_verbose
> 2)
8237 ast_verbose(VERBOSE_PREFIX_3
"Message too short\n");
8238 cmd
= ast_play_and_wait(chan
, "vm-tooshort");
8239 cmd
= ast_filedelete(tempfile
, NULL
);
8242 else if (vmu
->review
&& (cmd
== 2 && *duration
< (maxsilence
+ 3))) {
8243 /* Message is all silence */
8244 if (option_verbose
> 2)
8245 ast_verbose(VERBOSE_PREFIX_3
"Nothing recorded\n");
8246 cmd
= ast_filedelete(tempfile
, NULL
);
8247 cmd
= ast_play_and_wait(chan
, "vm-nothingrecorded");
8249 cmd
= ast_play_and_wait(chan
, "vm-speakup");
8254 /* If all is well, a message exists */
8267 cmd
= ast_play_and_wait(chan
, "vm-sorry");
8270 /* XXX Commented out for the moment because of the dangers of deleting
8271 a message while recording (can put the message numbers out of sync) */
8273 /* Cancel recording, delete message, offer to take another message*/
8274 cmd
= ast_play_and_wait(chan
, "vm-deleted");
8275 cmd
= ast_filedelete(tempfile
, NULL
);
8276 if (outsidecaller
) {
8277 res
= vm_exec(chan
, NULL
);
8284 if (!ast_test_flag(vmu
, VM_OPERATOR
)) {
8285 cmd
= ast_play_and_wait(chan
, "vm-sorry");
8288 if (message_exists
|| recorded
) {
8289 cmd
= ast_play_and_wait(chan
, "vm-saveoper");
8291 cmd
= ast_waitfordigit(chan
, 3000);
8293 ast_play_and_wait(chan
, "vm-msgsaved");
8296 ast_play_and_wait(chan
, "vm-deleted");
8297 DELETE(recordfile
, -1, recordfile
);
8303 /* If the caller is an ouside caller, and the review option is enabled,
8304 allow them to review the message, but let the owner of the box review
8306 if (outsidecaller
&& !ast_test_flag(vmu
, VM_REVIEW
))
8308 if (message_exists
) {
8309 cmd
= ast_play_and_wait(chan
, "vm-review");
8312 cmd
= ast_play_and_wait(chan
, "vm-torerecord");
8314 cmd
= ast_waitfordigit(chan
, 600);
8317 if (!cmd
&& outsidecaller
&& ast_test_flag(vmu
, VM_OPERATOR
)) {
8318 cmd
= ast_play_and_wait(chan
, "vm-reachoper");
8320 cmd
= ast_waitfordigit(chan
, 600);
8324 cmd
= ast_play_and_wait(chan
, "vm-tocancelmsg");
8327 cmd
= ast_waitfordigit(chan
, 6000);
8331 if (attempts
> max_attempts
) {
8337 ast_play_and_wait(chan
, "vm-goodbye");
8345 static void write_file(char *filename
, char *buffer
, unsigned long len
)
8349 output
= fopen (filename
, "w");
8350 fwrite (buffer
, len
, 1, output
);
8354 void mm_searched(MAILSTREAM
*stream
, unsigned long number
)
8356 struct vm_state
*vms
;
8359 mailbox
= stream
->mailbox
;
8360 user
= get_user_by_mailbox(mailbox
);
8361 vms
= get_vm_state_by_imapuser(user
,2);
8363 if(option_debug
> 2)
8364 ast_log (LOG_DEBUG
, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number
,vms
->vmArrayIndex
,vms
->interactive
);
8365 vms
->msgArray
[vms
->vmArrayIndex
++] = number
;
8367 ast_log (LOG_ERROR
, "No state found.\n");
8372 #if 0 /*No need for this. */
8374 * Accepts: MAIL stream
8376 static void status(MAILSTREAM
*stream
)
8379 char *s
, date
[MAILTMPLEN
];
8381 AUTHENTICATOR
*auth
;
8383 ast_log (LOG_NOTICE
,"%s\n",date
);
8385 if (stream
->mailbox
)
8386 ast_log (LOG_NOTICE
," %s mailbox: %s, %lu messages, %lu recent\n",
8387 stream
->dtb
->name
, stream
->mailbox
, stream
->nmsgs
,stream
->recent
);
8389 ast_log (LOG_NOTICE
,"No mailbox is open on this stream\n");
8390 if (stream
->user_flags
[0]) {
8391 ast_log (LOG_NOTICE
,"Keywords: %s\n", stream
->user_flags
[0]);
8392 for (i
= 1; i
< NUSERFLAGS
&& stream
->user_flags
[i
]; ++i
)
8393 ast_log (LOG_NOTICE
," %s\n", stream
->user_flags
[i
]);
8395 if (!strcmp (stream
->dtb
->name
, "imap")) {
8396 if (LEVELIMAP4rev1 (stream
))
8397 s
= "IMAP4rev1 (RFC 3501)";
8398 else if (LEVEL1730 (stream
))
8399 s
= "IMAP4 (RFC 1730)";
8400 else if (LEVELIMAP2bis (stream
))
8402 else if (LEVEL1176 (stream
))
8403 s
= "IMAP2 (RFC 1176)";
8405 s
= "IMAP2 (RFC 1064)";
8406 ast_log (LOG_NOTICE
,"%s server %s\n", s
, imap_host (stream
));
8407 if (LEVELIMAP4 (stream
)) {
8408 if ((i
= (imap_cap(stream
)->auth
))) {
8410 ast_log (LOG_NOTICE
,"Mutually-supported SASL mechanisms:\n");
8411 while ((auth
= mail_lookup_auth (find_rightmost_bit (&i
) + 1))) {
8412 ast_log (LOG_NOTICE
," %s\n", auth
->name
);
8413 if (!strcmp (auth
->name
, "PLAIN"))
8414 s
= "\n [LOGIN will not be listed here if PLAIN is supported]\n";
8416 ast_log (LOG_NOTICE
,s
);
8418 ast_log (LOG_NOTICE
,"Supported standard extensions:\n");
8419 if (LEVELACL (stream
))
8420 ast_log (LOG_NOTICE
," Access Control lists (RFC 2086)\n");
8421 if (LEVELQUOTA (stream
))
8422 ast_log (LOG_NOTICE
," Quotas (RFC 2087)\n");
8423 if (LEVELLITERALPLUS (stream
))
8424 ast_log (LOG_NOTICE
," Non-synchronizing literals (RFC 2088)\n");
8425 if (LEVELIDLE (stream
))
8426 ast_log (LOG_NOTICE
," IDLE unsolicited update (RFC 2177)\n");
8427 if (LEVELMBX_REF (stream
))
8428 ast_log (LOG_NOTICE
," Mailbox referrals (RFC 2193)\n");
8429 if (LEVELLOG_REF (stream
))
8430 ast_log (LOG_NOTICE
," Login referrals (RFC 2221)\n");
8431 if (LEVELANONYMOUS (stream
))
8432 ast_log (LOG_NOTICE
," Anonymous access (RFC 2245)\n");
8433 if (LEVELNAMESPACE (stream
))
8434 ast_log (LOG_NOTICE
," Multiple namespaces (RFC 2342)\n");
8435 if (LEVELUIDPLUS (stream
))
8436 ast_log (LOG_NOTICE
," Extended UID behavior (RFC 2359)\n");
8437 if (LEVELSTARTTLS (stream
))
8438 ast_log (LOG_NOTICE
," Transport Layer Security (RFC 2595)\n");
8439 if (LEVELLOGINDISABLED (stream
))
8440 ast_log (LOG_NOTICE
," LOGIN command disabled (RFC 2595)\n");
8441 if (LEVELID (stream
))
8442 ast_log (LOG_NOTICE
," Implementation identity negotiation (RFC 2971)\n");
8443 if (LEVELCHILDREN (stream
))
8444 ast_log (LOG_NOTICE
," LIST children announcement (RFC 3348)\n");
8445 if (LEVELMULTIAPPEND (stream
))
8446 ast_log (LOG_NOTICE
," Atomic multiple APPEND (RFC 3502)\n");
8447 if (LEVELBINARY (stream
))
8448 ast_log (LOG_NOTICE
," Binary body content (RFC 3516)\n");
8449 ast_log (LOG_NOTICE
,"Supported draft extensions:\n");
8450 if (LEVELUNSELECT (stream
))
8451 ast_log (LOG_NOTICE
," Mailbox unselect\n");
8452 if (LEVELSASLIR (stream
))
8453 ast_log (LOG_NOTICE
," SASL initial client response\n");
8454 if (LEVELSORT (stream
))
8455 ast_log (LOG_NOTICE
," Server-based sorting\n");
8456 if (LEVELTHREAD (stream
)) {
8457 ast_log (LOG_NOTICE
," Server-based threading:\n");
8458 for (thr
= imap_cap(stream
)->threader
; thr
; thr
= thr
->next
)
8459 ast_log (LOG_NOTICE
," %s\n", thr
->name
);
8461 if (LEVELSCAN (stream
))
8462 ast_log (LOG_NOTICE
," Mailbox text scan\n");
8463 if ((i
= imap_cap(stream
)->extlevel
)) {
8464 ast_log (LOG_NOTICE
,"Supported BODYSTRUCTURE extensions:\n");
8467 ast_log (LOG_NOTICE
," location\n");
8469 ast_log (LOG_NOTICE
," language\n");
8471 ast_log (LOG_NOTICE
," disposition\n");
8473 ast_log (LOG_NOTICE
," MD5\n");
8477 ast_log (LOG_NOTICE
,"\n");
8483 static struct ast_vm_user
*find_user_realtime_imapuser(const char *imapuser
)
8485 struct ast_variable
*var
;
8486 struct ast_vm_user
*vmu
;
8488 vmu
= ast_calloc(1, sizeof *vmu
);
8491 ast_set_flag(vmu
, VM_ALLOCED
);
8492 populate_defaults(vmu
);
8494 var
= ast_load_realtime("voicemail", "imapuser", imapuser
, NULL
);
8496 apply_options_full(vmu
, var
);
8497 ast_variables_destroy(var
);
8505 /* Interfaces to C-client */
8507 void mm_exists(MAILSTREAM
* stream
, unsigned long number
)
8509 /* mail_ping will callback here if new mail! */
8510 if(option_debug
> 3)
8511 ast_log (LOG_DEBUG
, "Entering EXISTS callback for message %ld\n", number
);
8512 if (number
== 0) return;
8517 void mm_expunged(MAILSTREAM
* stream
, unsigned long number
)
8519 /* mail_ping will callback here if expunged mail! */
8520 if(option_debug
> 3)
8521 ast_log (LOG_DEBUG
, "Entering EXPUNGE callback for message %ld\n", number
);
8522 if (number
== 0) return;
8527 void mm_flags(MAILSTREAM
* stream
, unsigned long number
)
8529 /* mail_ping will callback here if read mail! */
8530 if(option_debug
> 3)
8531 ast_log (LOG_DEBUG
, "Entering FLAGS callback for message %ld\n", number
);
8532 if (number
== 0) return;
8537 void mm_notify(MAILSTREAM
* stream
, char *string
, long errflg
)
8539 mm_log (string
, errflg
);
8543 void mm_list(MAILSTREAM
* stream
, int delim
, char *mailbox
, long attributes
)
8545 if (delimiter
== '\0') {
8548 if (option_debug
> 4) {
8549 ast_log(LOG_DEBUG
, "Delimiter set to %c and mailbox %s\n",delim
, mailbox
);
8550 if (attributes
& LATT_NOINFERIORS
)
8551 ast_log(LOG_DEBUG
, "no inferiors\n");
8552 if (attributes
& LATT_NOSELECT
)
8553 ast_log(LOG_DEBUG
, "no select\n");
8554 if (attributes
& LATT_MARKED
)
8555 ast_log(LOG_DEBUG
, "marked\n");
8556 if (attributes
& LATT_UNMARKED
)
8557 ast_log(LOG_DEBUG
, "unmarked\n");
8562 void mm_lsub(MAILSTREAM
* stream
, int delimiter
, char *mailbox
, long attributes
)
8564 if (option_debug
> 4) {
8565 ast_log(LOG_DEBUG
, "Delimiter set to %c and mailbox %s\n",delimiter
, mailbox
);
8566 if (attributes
& LATT_NOINFERIORS
)
8567 ast_log(LOG_DEBUG
, "no inferiors\n");
8568 if (attributes
& LATT_NOSELECT
)
8569 ast_log(LOG_DEBUG
, "no select\n");
8570 if (attributes
& LATT_MARKED
)
8571 ast_log(LOG_DEBUG
, "marked\n");
8572 if (attributes
& LATT_UNMARKED
)
8573 ast_log(LOG_DEBUG
, "unmarked\n");
8578 void mm_status(MAILSTREAM
* stream
, char *mailbox
, MAILSTATUS
* status
)
8580 ast_log (LOG_NOTICE
," Mailbox %s", mailbox
);
8581 if (status
->flags
& SA_MESSAGES
)
8582 ast_log (LOG_NOTICE
,", %lu messages", status
->messages
);
8583 if (status
->flags
& SA_RECENT
)
8584 ast_log (LOG_NOTICE
,", %lu recent", status
->recent
);
8585 if (status
->flags
& SA_UNSEEN
)
8586 ast_log (LOG_NOTICE
,", %lu unseen", status
->unseen
);
8587 if (status
->flags
& SA_UIDVALIDITY
)
8588 ast_log (LOG_NOTICE
,", %lu UID validity", status
->uidvalidity
);
8589 if (status
->flags
& SA_UIDNEXT
)
8590 ast_log (LOG_NOTICE
,", %lu next UID", status
->uidnext
);
8591 ast_log (LOG_NOTICE
,"\n");
8595 void mm_log(char *string
, long errflg
)
8597 switch ((short) errflg
) {
8600 ast_log(LOG_DEBUG
,"IMAP Info: %s\n", string
);
8604 ast_log (LOG_WARNING
,"IMAP Warning: %s\n", string
);
8607 ast_log (LOG_ERROR
,"IMAP Error: %s\n", string
);
8613 void mm_dlog(char *string
)
8615 ast_log (LOG_NOTICE
, "%s\n", string
);
8619 void mm_login(NETMBX
* mb
, char *user
, char *pwd
, long trial
)
8621 struct ast_vm_user
*vmu
;
8623 if(option_debug
> 3)
8624 ast_log(LOG_DEBUG
, "Entering callback mm_login\n");
8626 ast_copy_string(user
, mb
->user
, MAILTMPLEN
);
8628 /* We should only do this when necessary */
8629 if (!ast_strlen_zero(authpassword
)) {
8630 ast_copy_string(pwd
, authpassword
, MAILTMPLEN
);
8632 AST_LIST_TRAVERSE(&users
, vmu
, list
) {
8633 if(!strcasecmp(mb
->user
, vmu
->imapuser
)) {
8634 ast_copy_string(pwd
, vmu
->imappassword
, MAILTMPLEN
);
8639 if ((vmu
= find_user_realtime_imapuser(mb
->user
))) {
8640 ast_copy_string(pwd
, vmu
->imappassword
, MAILTMPLEN
);
8648 void mm_critical(MAILSTREAM
* stream
)
8653 void mm_nocritical(MAILSTREAM
* stream
)
8658 long mm_diskerror(MAILSTREAM
* stream
, long errcode
, long serious
)
8660 kill (getpid (), SIGSTOP
);
8665 void mm_fatal(char *string
)
8667 ast_log(LOG_ERROR
,"IMAP access FATAL error: %s\n", string
);
8670 /* C-client callback to handle quota */
8671 static void mm_parsequota(MAILSTREAM
*stream
, unsigned char *msg
, QUOTALIST
*pquota
)
8673 struct vm_state
*vms
;
8676 unsigned long usage
= 0;
8677 unsigned long limit
= 0;
8680 usage
= pquota
->usage
;
8681 limit
= pquota
->limit
;
8682 pquota
= pquota
->next
;
8685 mailbox
= stream
->mailbox
;
8686 user
= get_user_by_mailbox(mailbox
);
8687 vms
= get_vm_state_by_imapuser(user
,2);
8689 if(option_debug
> 2)
8690 ast_log (LOG_DEBUG
, "User %s usage is %lu, limit is %lu\n",user
,usage
,limit
);
8691 vms
->quota_usage
= usage
;
8692 vms
->quota_limit
= limit
;
8694 ast_log (LOG_ERROR
, "No state found.\n");
8698 static char *get_header_by_tag(char *header
, char *tag
)
8704 if (!header
|| !tag
)
8707 taglen
= strlen(tag
) + 1;
8711 start
= strstr(header
, tag
);
8715 ast_mutex_lock(&imaptemp_lock
);
8716 ast_copy_string(imaptemp
, start
+taglen
, sizeof(imaptemp
));
8717 ast_mutex_unlock(&imaptemp_lock
);
8718 if ((eol_pnt
= strchr(imaptemp
,'\r')) || (eol_pnt
= strchr(imaptemp
,'\n')))
8723 static char *get_user_by_mailbox(char *mailbox
)
8725 char *start
, *quote
;
8731 start
= strstr(mailbox
,"/user=");
8735 ast_mutex_lock(&imaptemp_lock
);
8736 ast_copy_string(imaptemp
, start
+6, sizeof(imaptemp
));
8737 ast_mutex_unlock(&imaptemp_lock
);
8739 quote
= strchr(imaptemp
,'\"');
8740 if (!quote
) { /* if username is not in quotes */
8741 eol_pnt
= strchr(imaptemp
,'/');
8743 eol_pnt
= strchr(imaptemp
,'}');
8748 eol_pnt
= strchr(imaptemp
+1,'\"');
8754 static struct vm_state
*get_vm_state_by_imapuser(char *user
, int interactive
)
8756 struct vmstate
*vlist
= NULL
;
8761 if (vlist
->vms
->imapuser
) {
8762 if (!strcmp(vlist
->vms
->imapuser
,user
)) {
8763 if (interactive
== 2) {
8765 } else if (vlist
->vms
->interactive
== interactive
) {
8770 if(option_debug
> 2)
8771 ast_log(LOG_DEBUG
, " error: imapuser is NULL for %s\n",user
);
8774 if(option_debug
> 2)
8775 ast_log(LOG_DEBUG
, " error: vms is NULL for %s\n",user
);
8777 vlist
= vlist
->next
;
8779 if(option_debug
> 2)
8780 ast_log(LOG_DEBUG
, "%s not found in vmstates\n",user
);
8784 static struct vm_state
*get_vm_state_by_mailbox(const char *mailbox
, int interactive
)
8786 struct vmstate
*vlist
= NULL
;
8789 if(option_debug
> 2)
8790 ast_log(LOG_DEBUG
, "Mailbox set to %s\n",mailbox
);
8793 if (vlist
->vms
->username
) {
8794 if(option_debug
> 2)
8795 ast_log(LOG_DEBUG
, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox
,interactive
,vlist
->vms
->username
,vlist
->vms
->interactive
);
8796 if (!strcmp(vlist
->vms
->username
,mailbox
) && vlist
->vms
->interactive
== interactive
) {
8797 if(option_debug
> 2)
8798 ast_log(LOG_DEBUG
, " Found it!\n");
8802 if(option_debug
> 2)
8803 ast_log(LOG_DEBUG
, " error: username is NULL for %s\n",mailbox
);
8806 if(option_debug
> 2)
8807 ast_log(LOG_DEBUG
, " error: vms is NULL for %s\n",mailbox
);
8809 vlist
= vlist
->next
;
8811 if(option_debug
> 2)
8812 ast_log(LOG_DEBUG
, "%s not found in vmstates\n",mailbox
);
8816 static void vmstate_insert(struct vm_state
*vms
)
8819 struct vm_state
*altvms
;
8821 /* If interactive, it probably already exists, and we should
8822 use the one we already have since it is more up to date.
8823 We can compare the username to find the duplicate */
8824 if (vms
->interactive
== 1) {
8825 altvms
= get_vm_state_by_mailbox(vms
->username
,0);
8827 if(option_debug
> 2)
8828 ast_log(LOG_DEBUG
, "Duplicate mailbox %s, copying message info...\n",vms
->username
);
8829 vms
->newmessages
= altvms
->newmessages
;
8830 vms
->oldmessages
= altvms
->oldmessages
;
8831 if(option_debug
> 2)
8832 ast_log(LOG_DEBUG
, "check_msgArray before memcpy\n");
8833 check_msgArray(vms
);
8834 /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long)*256); */
8835 copy_msgArray(vms
, altvms
);
8836 if(option_debug
> 2)
8837 ast_log(LOG_DEBUG
, "check_msgArray after memcpy\n");
8838 check_msgArray(vms
);
8839 vms
->vmArrayIndex
= altvms
->vmArrayIndex
;
8840 vms
->lastmsg
= altvms
->lastmsg
;
8841 vms
->curmsg
= altvms
->curmsg
;
8842 /* get a pointer to the persistent store */
8843 vms
->persist_vms
= altvms
;
8844 /* Reuse the mailstream? */
8845 vms
->mailstream
= altvms
->mailstream
;
8846 /* vms->mailstream = NIL; */
8850 v
= (struct vmstate
*)malloc(sizeof(struct vmstate
));
8852 ast_log(LOG_ERROR
, "Out of memory\n");
8854 if(option_debug
> 2)
8855 ast_log(LOG_DEBUG
, "Inserting vm_state for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
8856 ast_mutex_lock(&vmstate_lock
);
8860 ast_mutex_unlock(&vmstate_lock
);
8863 static void vmstate_delete(struct vm_state
*vms
)
8865 struct vmstate
*vc
, *vf
= NULL
, *vl
= NULL
;
8866 struct vm_state
*altvms
;
8868 /* If interactive, we should copy pertainent info
8869 back to the persistent state (to make update immediate) */
8870 if (vms
->interactive
== 1) {
8871 altvms
= vms
->persist_vms
;
8873 if(option_debug
> 2)
8874 ast_log(LOG_DEBUG
, "Duplicate mailbox %s, copying message info...\n",vms
->username
);
8875 altvms
->newmessages
= vms
->newmessages
;
8876 altvms
->oldmessages
= vms
->oldmessages
;
8877 altvms
->updated
= 1;
8881 ast_mutex_lock(&vmstate_lock
);
8883 if(option_debug
> 2)
8884 ast_log(LOG_DEBUG
, "Removing vm_state for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
8886 if (vc
->vms
== vms
) {
8889 vl
->next
= vc
->next
;
8891 vmstates
= vc
->next
;
8898 ast_log(LOG_ERROR
, "No vmstate found for user:%s, mailbox %s\n",vms
->imapuser
,vms
->username
);
8902 ast_mutex_unlock(&vmstate_lock
);
8905 static void set_update(MAILSTREAM
* stream
)
8907 struct vm_state
*vms
;
8911 mailbox
= stream
->mailbox
;
8912 user
= get_user_by_mailbox(mailbox
);
8913 vms
= get_vm_state_by_imapuser(user
, 0);
8915 if(option_debug
> 2)
8916 ast_log (LOG_DEBUG
, "User %s mailbox set for update.\n",user
);
8917 vms
->updated
= 1; /* set updated flag since mailbox changed */
8919 if(option_debug
> 2)
8920 ast_log (LOG_WARNING
, "User %s mailbox not found for update.\n",user
);
8924 static void init_vm_state(struct vm_state
*vms
)
8927 vms
->vmArrayIndex
= 0;
8928 for (x
= 0; x
< 256; x
++) {
8929 vms
->msgArray
[x
] = 0;
8933 static void check_msgArray(struct vm_state
*vms
)
8936 for (x
= 0; x
<256; x
++) {
8937 if (vms
->msgArray
[x
]!=0) {
8939 ast_log (LOG_DEBUG
, "Item %d set to %ld\n",x
,vms
->msgArray
[x
]);
8944 static void copy_msgArray(struct vm_state
*dst
, struct vm_state
*src
)
8947 for (x
= 0; x
<256; x
++) {
8948 dst
->msgArray
[x
] = src
->msgArray
[x
];
8952 static int save_body(BODY
*body
, struct vm_state
*vms
, char *section
, char *format
)
8957 unsigned long newlen
;
8960 if (!body
|| body
== NIL
)
8962 body_content
= mail_fetchbody (vms
->mailstream
, vms
->msgArray
[vms
->curmsg
], section
, &len
);
8963 if (body_content
!= NIL
) {
8964 snprintf(filename
, sizeof(filename
), "%s.%s", vms
->fn
, format
);
8965 /* ast_log (LOG_DEBUG,body_content); */
8966 body_decoded
= rfc822_base64 ((unsigned char *)body_content
, len
, &newlen
);
8967 write_file (filename
, (char *) body_decoded
, newlen
);
8972 /* get delimiter via mm_list callback */
8973 static void get_mailbox_delimiter(MAILSTREAM
*stream
) {
8975 snprintf(tmp
, sizeof(tmp
), "{%s}", imapserver
);
8976 mail_list(stream
, tmp
, "*");
8979 #endif /* IMAP_STORAGE */
8981 /* This is a workaround so that menuselect displays a proper description
8982 * AST_MODULE_INFO(, , "Comedian Mail (Voicemail System)"
8985 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, tdesc
,
8986 .load
= load_module
,
8987 .unload
= unload_module
,