00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include "asterisk.h"
00065
00066 #ifdef IMAP_STORAGE
00067 #include <ctype.h>
00068 #include <signal.h>
00069 #include <pwd.h>
00070 #ifdef USE_SYSTEM_IMAP
00071 #include <imap/c-client.h>
00072 #include <imap/imap4r1.h>
00073 #include <imap/linkage.h>
00074 #elif defined (USE_SYSTEM_CCLIENT)
00075 #include <c-client/c-client.h>
00076 #include <c-client/imap4r1.h>
00077 #include <c-client/linkage.h>
00078 #else
00079 #include "c-client.h"
00080 #include "imap4r1.h"
00081 #include "linkage.h"
00082 #endif
00083 #endif
00084
00085 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 188776 $")
00086
00087 #include "asterisk/paths.h"
00088 #include <sys/time.h>
00089 #include <sys/stat.h>
00090 #include <sys/mman.h>
00091 #include <time.h>
00092 #include <dirent.h>
00093
00094 #include "asterisk/logger.h"
00095 #include "asterisk/lock.h"
00096 #include "asterisk/file.h"
00097 #include "asterisk/channel.h"
00098 #include "asterisk/pbx.h"
00099 #include "asterisk/config.h"
00100 #include "asterisk/say.h"
00101 #include "asterisk/module.h"
00102 #include "asterisk/adsi.h"
00103 #include "asterisk/app.h"
00104 #include "asterisk/manager.h"
00105 #include "asterisk/dsp.h"
00106 #include "asterisk/localtime.h"
00107 #include "asterisk/cli.h"
00108 #include "asterisk/utils.h"
00109 #include "asterisk/stringfields.h"
00110 #include "asterisk/smdi.h"
00111 #include "asterisk/event.h"
00112 #include "asterisk/taskprocessor.h"
00113
00114 #ifdef ODBC_STORAGE
00115 #include "asterisk/res_odbc.h"
00116 #endif
00117
00118 #ifdef IMAP_STORAGE
00119 #include "asterisk/threadstorage.h"
00120
00121 static char imapserver[48];
00122 static char imapport[8];
00123 static char imapflags[128];
00124 static char imapfolder[64];
00125 static char imapparentfolder[64] = "\0";
00126 static char greetingfolder[64];
00127 static char authuser[32];
00128 static char authpassword[42];
00129
00130 static int expungeonhangup = 1;
00131 static int imapgreetings = 0;
00132 static char delimiter = '\0';
00133
00134 struct vm_state;
00135 struct ast_vm_user;
00136
00137 AST_THREADSTORAGE(ts_vmstate);
00138
00139
00140 static int init_mailstream(struct vm_state *vms, int box);
00141 static void write_file(char *filename, char *buffer, unsigned long len);
00142 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00143 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu);
00144 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00145 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00146 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00147 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00148 static void vmstate_insert(struct vm_state *vms);
00149 static void vmstate_delete(struct vm_state *vms);
00150 static void set_update(MAILSTREAM * stream);
00151 static void init_vm_state(struct vm_state *vms);
00152 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00153 static void get_mailbox_delimiter(MAILSTREAM *stream);
00154 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00155 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00156 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, const char *flag);
00157 static void update_messages_by_imapuser(const char *user, unsigned long number);
00158 static int vm_delete(char *file);
00159
00160 static int imap_remove_file (char *dir, int msgnum);
00161 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00162 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00163 static void check_quota(struct vm_state *vms, char *mailbox);
00164 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00165 struct vmstate {
00166 struct vm_state *vms;
00167 AST_LIST_ENTRY(vmstate) list;
00168 };
00169
00170 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00171
00172 #endif
00173
00174 #define SMDI_MWI_WAIT_TIMEOUT 1000
00175
00176 #define COMMAND_TIMEOUT 5000
00177
00178 #define VOICEMAIL_DIR_MODE 0777
00179 #define VOICEMAIL_FILE_MODE 0666
00180 #define CHUNKSIZE 65536
00181
00182 #define VOICEMAIL_CONFIG "voicemail.conf"
00183 #define ASTERISK_USERNAME "asterisk"
00184
00185
00186
00187
00188 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00189 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00190 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00191 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00192 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00193 #define VALID_DTMF "1234567890*#"
00194
00195
00196
00197 #define SENDMAIL "/usr/sbin/sendmail -t"
00198
00199 #define INTRO "vm-intro"
00200
00201 #define MAXMSG 100
00202 #define MAXMSGLIMIT 9999
00203
00204 #define MINPASSWORD 0
00205
00206 #define BASELINELEN 72
00207 #define BASEMAXINLINE 256
00208 #define eol "\r\n"
00209
00210 #define MAX_DATETIME_FORMAT 512
00211 #define MAX_NUM_CID_CONTEXTS 10
00212
00213 #define VM_REVIEW (1 << 0)
00214 #define VM_OPERATOR (1 << 1)
00215 #define VM_SAYCID (1 << 2)
00216 #define VM_SVMAIL (1 << 3)
00217 #define VM_ENVELOPE (1 << 4)
00218 #define VM_SAYDURATION (1 << 5)
00219 #define VM_SKIPAFTERCMD (1 << 6)
00220 #define VM_FORCENAME (1 << 7)
00221 #define VM_FORCEGREET (1 << 8)
00222 #define VM_PBXSKIP (1 << 9)
00223 #define VM_DIRECFORWARD (1 << 10)
00224 #define VM_ATTACH (1 << 11)
00225 #define VM_DELETE (1 << 12)
00226 #define VM_ALLOCED (1 << 13)
00227 #define VM_SEARCH (1 << 14)
00228 #define VM_TEMPGREETWARN (1 << 15)
00229 #define VM_MOVEHEARD (1 << 16)
00230 #define VM_MESSAGEWRAP (1 << 17)
00231 #define VM_FWDURGAUTO (1 << 18)
00232 #define ERROR_LOCK_PATH -100
00233
00234
00235 enum {
00236 NEW_FOLDER,
00237 OLD_FOLDER,
00238 WORK_FOLDER,
00239 FAMILY_FOLDER,
00240 FRIENDS_FOLDER,
00241 GREETINGS_FOLDER
00242 } vm_box;
00243
00244 enum {
00245 OPT_SILENT = (1 << 0),
00246 OPT_BUSY_GREETING = (1 << 1),
00247 OPT_UNAVAIL_GREETING = (1 << 2),
00248 OPT_RECORDGAIN = (1 << 3),
00249 OPT_PREPEND_MAILBOX = (1 << 4),
00250 OPT_AUTOPLAY = (1 << 6),
00251 OPT_DTMFEXIT = (1 << 7),
00252 OPT_MESSAGE_Urgent = (1 << 8),
00253 OPT_MESSAGE_PRIORITY = (1 << 9)
00254 } vm_option_flags;
00255
00256 enum {
00257 OPT_ARG_RECORDGAIN = 0,
00258 OPT_ARG_PLAYFOLDER = 1,
00259 OPT_ARG_DTMFEXIT = 2,
00260
00261 OPT_ARG_ARRAY_SIZE = 3,
00262 } vm_option_args;
00263
00264 AST_APP_OPTIONS(vm_app_options, {
00265 AST_APP_OPTION('s', OPT_SILENT),
00266 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00267 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00268 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00269 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00270 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00271 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00272 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00273 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00274 });
00275
00276 static int load_config(int reload);
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 struct baseio {
00362 int iocp;
00363 int iolen;
00364 int linelength;
00365 int ateof;
00366 unsigned char iobuf[BASEMAXINLINE];
00367 };
00368
00369
00370
00371 struct ast_vm_user {
00372 char context[AST_MAX_CONTEXT];
00373 char mailbox[AST_MAX_EXTENSION];
00374 char password[80];
00375 char fullname[80];
00376 char email[80];
00377 char pager[80];
00378 char serveremail[80];
00379 char mailcmd[160];
00380 char language[MAX_LANGUAGE];
00381 char zonetag[80];
00382 char callback[80];
00383 char dialout[80];
00384 char uniqueid[80];
00385 char exit[80];
00386 char attachfmt[20];
00387 unsigned int flags;
00388 int saydurationm;
00389 int maxmsg;
00390 int maxdeletedmsg;
00391 int maxsecs;
00392 #ifdef IMAP_STORAGE
00393 char imapuser[80];
00394 char imappassword[80];
00395 char imapvmshareid[80];
00396 #endif
00397 double volgain;
00398 AST_LIST_ENTRY(ast_vm_user) list;
00399 };
00400
00401
00402 struct vm_zone {
00403 AST_LIST_ENTRY(vm_zone) list;
00404 char name[80];
00405 char timezone[80];
00406 char msg_format[512];
00407 };
00408
00409 #define VMSTATE_MAX_MSG_ARRAY 256
00410
00411
00412 struct vm_state {
00413 char curbox[80];
00414 char username[80];
00415 char context[80];
00416 char curdir[PATH_MAX];
00417 char vmbox[PATH_MAX];
00418 char fn[PATH_MAX];
00419 char intro[PATH_MAX];
00420 int *deleted;
00421 int *heard;
00422 int curmsg;
00423 int lastmsg;
00424 int newmessages;
00425 int oldmessages;
00426 int urgentmessages;
00427 int starting;
00428 int repeats;
00429 #ifdef IMAP_STORAGE
00430 ast_mutex_t lock;
00431 int updated;
00432 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00433 MAILSTREAM *mailstream;
00434 int vmArrayIndex;
00435 char imapuser[80];
00436 int interactive;
00437 char introfn[PATH_MAX];
00438 unsigned int quota_limit;
00439 unsigned int quota_usage;
00440 struct vm_state *persist_vms;
00441 #endif
00442 };
00443
00444 #ifdef ODBC_STORAGE
00445 static char odbc_database[80];
00446 static char odbc_table[80];
00447 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00448 #define DISPOSE(a,b) remove_file(a,b)
00449 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00450 #define EXISTS(a,b,c,d) (message_exists(a,b))
00451 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00452 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00453 #define DELETE(a,b,c,d) (delete_file(a,b))
00454 #else
00455 #ifdef IMAP_STORAGE
00456 #define DISPOSE(a,b) (imap_remove_file(a,b))
00457 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00458 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00459 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00460 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00461 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00462 #define DELETE(a,b,c,d) (vm_imap_delete(b,d))
00463 #else
00464 #define RETRIEVE(a,b,c,d)
00465 #define DISPOSE(a,b)
00466 #define STORE(a,b,c,d,e,f,g,h,i,j)
00467 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00468 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00469 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00470 #define DELETE(a,b,c,d) (vm_delete(c))
00471 #endif
00472 #endif
00473
00474 static char VM_SPOOL_DIR[PATH_MAX];
00475
00476 static char ext_pass_cmd[128];
00477 static char ext_pass_check_cmd[128];
00478
00479 static int my_umask;
00480
00481 #define PWDCHANGE_INTERNAL (1 << 1)
00482 #define PWDCHANGE_EXTERNAL (1 << 2)
00483 static int pwdchange = PWDCHANGE_INTERNAL;
00484
00485 #ifdef ODBC_STORAGE
00486 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00487 #else
00488 # ifdef IMAP_STORAGE
00489 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00490 # else
00491 # define tdesc "Comedian Mail (Voicemail System)"
00492 # endif
00493 #endif
00494
00495 static char userscontext[AST_MAX_EXTENSION] = "default";
00496
00497 static char *addesc = "Comedian Mail";
00498
00499 static char *synopsis_vm = "Leave a Voicemail message";
00500
00501 static char *descrip_vm =
00502 " VoiceMail(mailbox[@context][&mailbox[@context]][...][,options]): This\n"
00503 "application allows the calling party to leave a message for the specified\n"
00504 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00505 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00506 "specified mailbox does not exist.\n"
00507 " The Voicemail application will exit if any of the following DTMF digits are\n"
00508 "received:\n"
00509 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00510 " * - Jump to the 'a' extension in the current dialplan context.\n"
00511 " This application will set the following channel variable upon completion:\n"
00512 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00513 " application. The possible values are:\n"
00514 " SUCCESS | USEREXIT | FAILED\n\n"
00515 " Options:\n"
00516 " b - Play the 'busy' greeting to the calling party.\n"
00517 " d([c]) - Accept digits for a new extension in context c, if played during\n"
00518 " the greeting. Context defaults to the current context.\n"
00519 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00520 " message. The units are whole-number decibels (dB).\n"
00521 " Only works on supported technologies, which is DAHDI only.\n"
00522 " s - Skip the playback of instructions for leaving a message to the\n"
00523 " calling party.\n"
00524 " u - Play the 'unavailable' greeting.\n"
00525 " U - Mark message as Urgent.\n"
00526 " P - Mark message as PRIORITY.\n";
00527
00528 static char *synopsis_vmain = "Check Voicemail messages";
00529
00530 static char *descrip_vmain =
00531 " VoiceMailMain([mailbox][@context][,options]): This application allows the\n"
00532 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00533 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00534 "calling party will be prompted to enter one. If a context is not specified,\n"
00535 "the 'default' context will be used.\n\n"
00536 " Options:\n"
00537 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00538 " is entered by the caller.\n"
00539 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00540 " message. The units are whole-number decibels (dB).\n"
00541 " s - Skip checking the passcode for the mailbox.\n"
00542 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00543 " Defaults to INBOX\n";
00544
00545 static char *synopsis_vm_box_exists =
00546 "Check to see if Voicemail mailbox exists";
00547
00548 static char *descrip_vm_box_exists =
00549 " MailboxExists(mailbox[@context][,options]): Check to see if the specified\n"
00550 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00551 "will be used.\n"
00552 " This application will set the following channel variable upon completion:\n"
00553 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00554 " MailboxExists application. Possible values include:\n"
00555 " SUCCESS | FAILED\n\n"
00556 " Options: (none)\n";
00557
00558 static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
00559
00560 static char *descrip_vmauthenticate =
00561 " VMAuthenticate([mailbox][@context][,options]): This application behaves the\n"
00562 "same way as the Authenticate application, but the passwords are taken from\n"
00563 "voicemail.conf.\n"
00564 " If the mailbox is specified, only that mailbox's password will be considered\n"
00565 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00566 "be set with the authenticated mailbox.\n\n"
00567 " Options:\n"
00568 " s - Skip playing the initial prompts.\n";
00569
00570
00571 static char *app = "VoiceMail";
00572
00573
00574 static char *app2 = "VoiceMailMain";
00575
00576 static char *app3 = "MailboxExists";
00577 static char *app4 = "VMAuthenticate";
00578
00579 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00580 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00581 static char zonetag[80];
00582 static int maxsilence;
00583 static int maxmsg;
00584 static int maxdeletedmsg;
00585 static int silencethreshold = 128;
00586 static char serveremail[80];
00587 static char mailcmd[160];
00588 static char externnotify[160];
00589 static struct ast_smdi_interface *smdi_iface = NULL;
00590 static char vmfmts[80];
00591 static double volgain;
00592 static int vmminsecs;
00593 static int vmmaxsecs;
00594 static int maxgreet;
00595 static int skipms;
00596 static int maxlogins;
00597 static int minpassword;
00598
00599
00600
00601 static unsigned int poll_mailboxes;
00602
00603
00604 static unsigned int poll_freq;
00605
00606 #define DEFAULT_POLL_FREQ 30
00607
00608 AST_MUTEX_DEFINE_STATIC(poll_lock);
00609 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00610 static pthread_t poll_thread = AST_PTHREADT_NULL;
00611 static unsigned char poll_thread_run;
00612
00613
00614 static struct ast_event_sub *mwi_sub_sub;
00615
00616 static struct ast_event_sub *mwi_unsub_sub;
00617
00618
00619
00620
00621
00622
00623
00624
00625 struct mwi_sub {
00626 AST_RWLIST_ENTRY(mwi_sub) entry;
00627 int old_urgent;
00628 int old_new;
00629 int old_old;
00630 uint32_t uniqueid;
00631 char mailbox[1];
00632 };
00633
00634 struct mwi_sub_task {
00635 const char *mailbox;
00636 const char *context;
00637 uint32_t uniqueid;
00638 };
00639
00640 static struct ast_taskprocessor *mwi_subscription_tps;
00641
00642 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00643
00644
00645 static char listen_control_forward_key[12];
00646 static char listen_control_reverse_key[12];
00647 static char listen_control_pause_key[12];
00648 static char listen_control_restart_key[12];
00649 static char listen_control_stop_key[12];
00650
00651
00652 static char vm_password[80] = "vm-password";
00653 static char vm_newpassword[80] = "vm-newpassword";
00654 static char vm_passchanged[80] = "vm-passchanged";
00655 static char vm_reenterpassword[80] = "vm-reenterpassword";
00656 static char vm_mismatch[80] = "vm-mismatch";
00657 static char vm_invalid_password[80] = "vm-invalid-password";
00658
00659 static struct ast_flags globalflags = {0};
00660
00661 static int saydurationminfo;
00662
00663 static char dialcontext[AST_MAX_CONTEXT] = "";
00664 static char callcontext[AST_MAX_CONTEXT] = "";
00665 static char exitcontext[AST_MAX_CONTEXT] = "";
00666
00667 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00668
00669
00670 static char *emailbody = NULL;
00671 static char *emailsubject = NULL;
00672 static char *pagerbody = NULL;
00673 static char *pagersubject = NULL;
00674 static char fromstring[100];
00675 static char pagerfromstring[100];
00676 static char charset[32] = "ISO-8859-1";
00677
00678 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00679 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00680 static int adsiver = 1;
00681 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00682
00683
00684 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00685 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);
00686 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00687 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00688 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00689 signed char record_gain, struct vm_state *vms, char *flag);
00690 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00691 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00692 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00693 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00694 static void apply_options(struct ast_vm_user *vmu, const char *options);
00695 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00696 static int is_valid_dtmf(const char *key);
00697
00698 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00699 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00700 #endif
00701
00702 static char *strip_control(const char *input, char *buf, size_t buflen)
00703 {
00704 char *bufptr = buf;
00705 for (; *input; input++) {
00706 if (*input < 32) {
00707 continue;
00708 }
00709 *bufptr++ = *input;
00710 if (bufptr == buf + buflen - 1) {
00711 break;
00712 }
00713 }
00714 *bufptr = '\0';
00715 return buf;
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731 static void populate_defaults(struct ast_vm_user *vmu)
00732 {
00733 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00734 if (saydurationminfo)
00735 vmu->saydurationm = saydurationminfo;
00736 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00737 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00738 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00739 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00740 if (vmmaxsecs)
00741 vmu->maxsecs = vmmaxsecs;
00742 if (maxmsg)
00743 vmu->maxmsg = maxmsg;
00744 if (maxdeletedmsg)
00745 vmu->maxdeletedmsg = maxdeletedmsg;
00746 vmu->volgain = volgain;
00747 }
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00758 {
00759 int x;
00760 if (!strcasecmp(var, "attach")) {
00761 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00762 } else if (!strcasecmp(var, "attachfmt")) {
00763 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00764 } else if (!strcasecmp(var, "serveremail")) {
00765 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00766 } else if (!strcasecmp(var, "language")) {
00767 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00768 } else if (!strcasecmp(var, "tz")) {
00769 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00770 #ifdef IMAP_STORAGE
00771 } else if (!strcasecmp(var, "imapuser")) {
00772 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00773 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00774 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00775 } else if (!strcasecmp(var, "imapvmshareid")) {
00776 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00777 #endif
00778 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00779 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00780 } else if (!strcasecmp(var, "saycid")){
00781 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00782 } else if (!strcasecmp(var,"sendvoicemail")){
00783 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00784 } else if (!strcasecmp(var, "review")){
00785 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00786 } else if (!strcasecmp(var, "tempgreetwarn")){
00787 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00788 } else if (!strcasecmp(var, "messagewrap")){
00789 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
00790 } else if (!strcasecmp(var, "operator")) {
00791 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00792 } else if (!strcasecmp(var, "envelope")){
00793 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00794 } else if (!strcasecmp(var, "moveheard")){
00795 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
00796 } else if (!strcasecmp(var, "sayduration")){
00797 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00798 } else if (!strcasecmp(var, "saydurationm")){
00799 if (sscanf(value, "%d", &x) == 1) {
00800 vmu->saydurationm = x;
00801 } else {
00802 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
00803 }
00804 } else if (!strcasecmp(var, "forcename")){
00805 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00806 } else if (!strcasecmp(var, "forcegreetings")){
00807 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00808 } else if (!strcasecmp(var, "callback")) {
00809 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00810 } else if (!strcasecmp(var, "dialout")) {
00811 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00812 } else if (!strcasecmp(var, "exitcontext")) {
00813 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00814 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
00815 if (vmu->maxsecs <= 0) {
00816 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
00817 vmu->maxsecs = vmmaxsecs;
00818 } else {
00819 vmu->maxsecs = atoi(value);
00820 }
00821 if (!strcasecmp(var, "maxmessage"))
00822 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
00823 } else if (!strcasecmp(var, "maxmsg")) {
00824 vmu->maxmsg = atoi(value);
00825 if (vmu->maxmsg <= 0) {
00826 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
00827 vmu->maxmsg = MAXMSG;
00828 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00829 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00830 vmu->maxmsg = MAXMSGLIMIT;
00831 }
00832 } else if (!strcasecmp(var, "backupdeleted")) {
00833 if (sscanf(value, "%d", &x) == 1)
00834 vmu->maxdeletedmsg = x;
00835 else if (ast_true(value))
00836 vmu->maxdeletedmsg = MAXMSG;
00837 else
00838 vmu->maxdeletedmsg = 0;
00839
00840 if (vmu->maxdeletedmsg < 0) {
00841 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
00842 vmu->maxdeletedmsg = MAXMSG;
00843 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
00844 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
00845 vmu->maxdeletedmsg = MAXMSGLIMIT;
00846 }
00847 } else if (!strcasecmp(var, "volgain")) {
00848 sscanf(value, "%lf", &vmu->volgain);
00849 } else if (!strcasecmp(var, "options")) {
00850 apply_options(vmu, value);
00851 }
00852 }
00853
00854 static char *vm_check_password_shell(char *command, char *buf, size_t len)
00855 {
00856 int fds[2], pid = 0;
00857
00858 memset(buf, 0, len);
00859
00860 if (pipe(fds)) {
00861 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
00862 } else {
00863
00864 pid = ast_safe_fork(0);
00865
00866 if (pid < 0) {
00867
00868 close(fds[0]);
00869 close(fds[1]);
00870 snprintf(buf, len, "FAILURE: Fork failed");
00871 } else if (pid) {
00872
00873 close(fds[1]);
00874 if (read(fds[0], buf, len) < 0) {
00875 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00876 }
00877 close(fds[0]);
00878 } else {
00879
00880 AST_DECLARE_APP_ARGS(arg,
00881 AST_APP_ARG(v)[20];
00882 );
00883 char *mycmd = ast_strdupa(command);
00884
00885 close(fds[0]);
00886 dup2(fds[1], STDOUT_FILENO);
00887 close(fds[1]);
00888 ast_close_fds_above_n(STDOUT_FILENO);
00889
00890 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
00891
00892 execv(arg.v[0], arg.v);
00893 printf("FAILURE: %s", strerror(errno));
00894 _exit(0);
00895 }
00896 }
00897 return buf;
00898 }
00899
00900
00901
00902
00903
00904
00905
00906
00907 static int check_password(struct ast_vm_user *vmu, char *password)
00908 {
00909
00910 if (strlen(password) < minpassword)
00911 return 1;
00912 if (!ast_strlen_zero(ext_pass_check_cmd)) {
00913 char cmd[255], buf[255];
00914
00915 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
00916
00917 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
00918 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
00919 ast_debug(5, "Result: %s\n", buf);
00920 if (!strncasecmp(buf, "VALID", 5)) {
00921 ast_debug(3, "Passed password check: '%s'\n", buf);
00922 return 0;
00923 } else if (!strncasecmp(buf, "FAILURE", 7)) {
00924 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
00925 return 0;
00926 } else {
00927 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
00928 return 1;
00929 }
00930 }
00931 }
00932 return 0;
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00946 {
00947 int res;
00948 if (!ast_strlen_zero(vmu->uniqueid)) {
00949 if (strlen(password) > 10) {
00950 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
00951 }
00952 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, SENTINEL);
00953 if (res > 0) {
00954 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00955 res = 0;
00956 } else if (!res) {
00957 res = -1;
00958 }
00959 return res;
00960 }
00961 return -1;
00962 }
00963
00964
00965
00966
00967 static void apply_options(struct ast_vm_user *vmu, const char *options)
00968 {
00969 char *stringp;
00970 char *s;
00971 char *var, *value;
00972 stringp = ast_strdupa(options);
00973 while ((s = strsep(&stringp, "|"))) {
00974 value = s;
00975 if ((var = strsep(&value, "=")) && value) {
00976 apply_option(vmu, var, value);
00977 }
00978 }
00979 }
00980
00981
00982
00983
00984
00985
00986 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00987 {
00988 struct ast_variable *tmp;
00989 tmp = var;
00990 while (tmp) {
00991 if (!strcasecmp(tmp->name, "vmsecret")) {
00992 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00993 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00994 if (ast_strlen_zero(retval->password))
00995 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00996 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00997 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00998 } else if (!strcasecmp(tmp->name, "pager")) {
00999 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
01000 } else if (!strcasecmp(tmp->name, "email")) {
01001 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
01002 } else if (!strcasecmp(tmp->name, "fullname")) {
01003 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
01004 } else if (!strcasecmp(tmp->name, "context")) {
01005 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
01006 #ifdef IMAP_STORAGE
01007 } else if (!strcasecmp(tmp->name, "imapuser")) {
01008 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
01009 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
01010 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
01011 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01012 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01013 #endif
01014 } else
01015 apply_option(retval, tmp->name, tmp->value);
01016 tmp = tmp->next;
01017 }
01018 }
01019
01020
01021
01022
01023
01024
01025
01026
01027 static int is_valid_dtmf(const char *key)
01028 {
01029 int i;
01030 char *local_key = ast_strdupa(key);
01031
01032 for (i = 0; i < strlen(key); ++i) {
01033 if (!strchr(VALID_DTMF, *local_key)) {
01034 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01035 return 0;
01036 }
01037 local_key++;
01038 }
01039 return 1;
01040 }
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01053 {
01054 struct ast_variable *var;
01055 struct ast_vm_user *retval;
01056
01057 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01058 if (!ivm)
01059 ast_set_flag(retval, VM_ALLOCED);
01060 else
01061 memset(retval, 0, sizeof(*retval));
01062 if (mailbox)
01063 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01064 populate_defaults(retval);
01065 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01066 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01067 else
01068 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01069 if (var) {
01070 apply_options_full(retval, var);
01071 ast_variables_destroy(var);
01072 } else {
01073 if (!ivm)
01074 ast_free(retval);
01075 retval = NULL;
01076 }
01077 }
01078 return retval;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01090 {
01091
01092 struct ast_vm_user *vmu=NULL, *cur;
01093 AST_LIST_LOCK(&users);
01094
01095 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01096 context = "default";
01097
01098 AST_LIST_TRAVERSE(&users, cur, list) {
01099 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01100 break;
01101 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01102 break;
01103 }
01104 if (cur) {
01105
01106 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01107 memcpy(vmu, cur, sizeof(*vmu));
01108 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01109 AST_LIST_NEXT(vmu, list) = NULL;
01110 }
01111 } else
01112 vmu = find_user_realtime(ivm, context, mailbox);
01113 AST_LIST_UNLOCK(&users);
01114 return vmu;
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01128 {
01129
01130 struct ast_vm_user *cur;
01131 int res = -1;
01132 AST_LIST_LOCK(&users);
01133 AST_LIST_TRAVERSE(&users, cur, list) {
01134 if ((!context || !strcasecmp(context, cur->context)) &&
01135 (!strcasecmp(mailbox, cur->mailbox)))
01136 break;
01137 }
01138 if (cur) {
01139 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01140 res = 0;
01141 }
01142 AST_LIST_UNLOCK(&users);
01143 return res;
01144 }
01145
01146
01147
01148
01149
01150
01151
01152
01153 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01154 {
01155 struct ast_config *cfg=NULL;
01156 struct ast_variable *var=NULL;
01157 struct ast_category *cat=NULL;
01158 char *category=NULL, *value=NULL, *new=NULL;
01159 const char *tmp=NULL;
01160 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01161 if (!change_password_realtime(vmu, newpassword))
01162 return;
01163
01164
01165 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags))) {
01166 while ((category = ast_category_browse(cfg, category))) {
01167 if (!strcasecmp(category, vmu->context)) {
01168 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01169 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01170 break;
01171 }
01172 value = strstr(tmp,",");
01173 if (!value) {
01174 ast_log(AST_LOG_WARNING, "variable has bad format.\n");
01175 break;
01176 }
01177 new = alloca((strlen(value)+strlen(newpassword)+1));
01178 sprintf(new,"%s%s", newpassword, value);
01179 if (!(cat = ast_category_get(cfg, category))) {
01180 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01181 break;
01182 }
01183 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01184 }
01185 }
01186
01187 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01188 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01189 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01190 }
01191 category = NULL;
01192 var = NULL;
01193
01194
01195 if ((cfg = ast_config_load("users.conf", config_flags))) {
01196 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01197 while ((category = ast_category_browse(cfg, category))) {
01198 ast_debug(4, "users.conf: %s\n", category);
01199 if (!strcasecmp(category, vmu->mailbox)) {
01200 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01201 ast_debug(3, "looks like we need to make vmsecret!\n");
01202 var = ast_variable_new("vmsecret", newpassword, "");
01203 }
01204 new = alloca(strlen(newpassword)+1);
01205 sprintf(new, "%s", newpassword);
01206 if (!(cat = ast_category_get(cfg, category))) {
01207 ast_debug(4, "failed to get category!\n");
01208 break;
01209 }
01210 if (!var)
01211 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01212 else
01213 ast_variable_append(cat, var);
01214 }
01215 }
01216
01217 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01218 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01219 config_text_file_save("users.conf", cfg, "AppVoicemail");
01220 }
01221 }
01222
01223 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01224 {
01225 char buf[255];
01226 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
01227 if (!ast_safe_system(buf)) {
01228 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01229
01230 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01231 }
01232 }
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01245 {
01246 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259 static int make_file(char *dest, const int len, const char *dir, const int num)
01260 {
01261 return snprintf(dest, len, "%s/msg%04d", dir, num);
01262 }
01263
01264
01265 static FILE *vm_mkftemp(char *template)
01266 {
01267 FILE *p = NULL;
01268 int pfd = mkstemp(template);
01269 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01270 if (pfd > -1) {
01271 p = fdopen(pfd, "w+");
01272 if (!p) {
01273 close(pfd);
01274 pfd = -1;
01275 }
01276 }
01277 return p;
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01289 {
01290 mode_t mode = VOICEMAIL_DIR_MODE;
01291 int res;
01292
01293 make_dir(dest, len, context, ext, folder);
01294 if ((res = ast_mkdir(dest, mode))) {
01295 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01296 return -1;
01297 }
01298 return 0;
01299 }
01300
01301 static const char *mbox(int id)
01302 {
01303 static const char *msgs[] = {
01304 #ifdef IMAP_STORAGE
01305 imapfolder,
01306 #else
01307 "INBOX",
01308 #endif
01309 "Old",
01310 "Work",
01311 "Family",
01312 "Friends",
01313 "Cust1",
01314 "Cust2",
01315 "Cust3",
01316 "Cust4",
01317 "Cust5",
01318 "Deleted",
01319 "Urgent"
01320 };
01321 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown";
01322 }
01323
01324 static void free_user(struct ast_vm_user *vmu)
01325 {
01326 if (ast_test_flag(vmu, VM_ALLOCED))
01327 ast_free(vmu);
01328 }
01329
01330
01331
01332 #ifdef IMAP_STORAGE
01333 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu)
01334 {
01335 char arg[10];
01336 struct vm_state *vms;
01337 unsigned long messageNum;
01338
01339
01340 if (msgnum < 0) {
01341 return;
01342 }
01343
01344 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01345 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
01346 return;
01347 }
01348
01349
01350
01351 messageNum = vms->msgArray[msgnum];
01352 if (messageNum == 0) {
01353 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01354 return;
01355 }
01356 if (option_debug > 2)
01357 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01358
01359 snprintf (arg, sizeof(arg), "%lu",messageNum);
01360 ast_mutex_lock(&vms->lock);
01361 mail_setflag (vms->mailstream,arg,"\\DELETED");
01362 ast_mutex_unlock(&vms->lock);
01363 }
01364
01365 static int imap_retrieve_greeting (const char *dir, const int msgnum, struct ast_vm_user *vmu)
01366 {
01367 struct vm_state *vms_p;
01368 char *file, *filename;
01369 char *attachment;
01370 int ret = 0, i;
01371 BODY *body;
01372
01373
01374
01375
01376 if (msgnum > -1 || !imapgreetings) {
01377 return 0;
01378 } else {
01379 file = strrchr(ast_strdupa(dir), '/');
01380 if (file)
01381 *file++ = '\0';
01382 else {
01383 ast_debug (1, "Failed to procure file name from directory passed.\n");
01384 return -1;
01385 }
01386 }
01387
01388
01389 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) ||!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01390 ast_log(AST_LOG_ERROR, "Voicemail state not found!\n");
01391 return -1;
01392 }
01393
01394
01395 *vms_p->introfn = '\0';
01396
01397 ast_mutex_lock(&vms_p->lock);
01398 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01399 if (!vms_p->mailstream) {
01400 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01401 ast_mutex_unlock(&vms_p->lock);
01402 return -1;
01403 }
01404
01405
01406 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01407 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01408
01409 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01410 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01411 } else {
01412 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01413 ast_mutex_unlock(&vms_p->lock);
01414 return -1;
01415 }
01416 filename = strsep(&attachment, ".");
01417 if (!strcmp(filename, file)) {
01418 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01419 vms_p->msgArray[vms_p->curmsg] = i + 1;
01420 save_body(body, vms_p, "2", attachment, 0);
01421 ast_mutex_unlock(&vms_p->lock);
01422 return 0;
01423 }
01424 }
01425 ast_mutex_unlock(&vms_p->lock);
01426
01427 return -1;
01428 }
01429
01430 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01431 {
01432 BODY *body;
01433 char *header_content;
01434 char *attachedfilefmt;
01435 char buf[80];
01436 struct vm_state *vms;
01437 char text_file[PATH_MAX];
01438 FILE *text_file_ptr;
01439 int res = 0;
01440 struct ast_vm_user *vmu;
01441
01442 if (!(vmu = find_user(NULL, context, mailbox))) {
01443 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01444 return -1;
01445 }
01446
01447 if (msgnum < 0) {
01448 if (imapgreetings) {
01449 res = imap_retrieve_greeting(dir, msgnum, vmu);
01450 goto exit;
01451 } else {
01452 res = 0;
01453 goto exit;
01454 }
01455 }
01456
01457
01458
01459
01460 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01461
01462
01463
01464
01465
01466
01467
01468 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01469 res = -1;
01470 goto exit;
01471 }
01472
01473 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01474 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01475
01476
01477 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01478 res = 0;
01479 goto exit;
01480 }
01481
01482 if (option_debug > 2)
01483 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01484 if (vms->msgArray[msgnum] == 0) {
01485 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01486 res = -1;
01487 goto exit;
01488 }
01489
01490
01491 ast_mutex_lock(&vms->lock);
01492 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01493 ast_mutex_unlock(&vms->lock);
01494
01495 if (ast_strlen_zero(header_content)) {
01496 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01497 res = -1;
01498 goto exit;
01499 }
01500
01501 ast_mutex_lock(&vms->lock);
01502 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01503 ast_mutex_unlock(&vms->lock);
01504
01505
01506 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01507 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01508 } else {
01509 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01510 res = -1;
01511 goto exit;
01512 }
01513
01514
01515
01516 strsep(&attachedfilefmt, ".");
01517 if (!attachedfilefmt) {
01518 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01519 res = -1;
01520 goto exit;
01521 }
01522
01523 save_body(body, vms, "2", attachedfilefmt, 0);
01524 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01525 *vms->introfn = '\0';
01526 }
01527
01528
01529 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01530
01531 if (!(text_file_ptr = fopen(text_file, "w"))) {
01532 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01533 }
01534
01535 fprintf(text_file_ptr, "%s\n", "[message]");
01536
01537 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01538 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01539 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01540 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01541 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01542 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01543 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01544 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01545 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01546 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01547 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01548 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01549 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01550 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01551 fclose(text_file_ptr);
01552
01553 exit:
01554 free_user(vmu);
01555 return res;
01556 }
01557
01558 static int folder_int(const char *folder)
01559 {
01560
01561 if (!folder)
01562 return 0;
01563 #ifdef IMAP_STORAGE
01564 if (!strcasecmp(folder, imapfolder))
01565 #else
01566 if (!strcasecmp(folder, "INBOX"))
01567 #endif
01568 return 0;
01569 else if (!strcasecmp(folder, "Old"))
01570 return 1;
01571 else if (!strcasecmp(folder, "Work"))
01572 return 2;
01573 else if (!strcasecmp(folder, "Family"))
01574 return 3;
01575 else if (!strcasecmp(folder, "Friends"))
01576 return 4;
01577 else if (!strcasecmp(folder, "Cust1"))
01578 return 5;
01579 else if (!strcasecmp(folder, "Cust2"))
01580 return 6;
01581 else if (!strcasecmp(folder, "Cust3"))
01582 return 7;
01583 else if (!strcasecmp(folder, "Cust4"))
01584 return 8;
01585 else if (!strcasecmp(folder, "Cust5"))
01586 return 9;
01587 else
01588 return 0;
01589 }
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600 static int messagecount(const char *context, const char *mailbox, const char *folder)
01601 {
01602 SEARCHPGM *pgm;
01603 SEARCHHEADER *hdr;
01604
01605 struct ast_vm_user *vmu, vmus;
01606 struct vm_state *vms_p;
01607 int ret = 0;
01608 int fold = folder_int(folder);
01609 int urgent = 0;
01610
01611
01612 if (fold == 11) {
01613 fold = NEW_FOLDER;
01614 urgent = 1;
01615 }
01616
01617 if (ast_strlen_zero(mailbox))
01618 return 0;
01619
01620
01621 vmu = find_user(&vmus, context, mailbox);
01622 if (!vmu) {
01623 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
01624 return -1;
01625 } else {
01626
01627 if (vmu->imapuser[0] == '\0') {
01628 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01629 return -1;
01630 }
01631 }
01632
01633
01634 if (vmu->imapuser[0] == '\0') {
01635 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01636 free_user(vmu);
01637 return -1;
01638 }
01639
01640
01641 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01642 if (!vms_p) {
01643 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01644 }
01645 if (vms_p) {
01646 ast_debug(3, "Returning before search - user is logged in\n");
01647 if (fold == 0) {
01648 return vms_p->newmessages;
01649 }
01650 if (fold == 1) {
01651 return vms_p->oldmessages;
01652 }
01653 if (fold == 11) {
01654 return vms_p->urgentmessages;
01655 }
01656 }
01657
01658
01659 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01660 if (!vms_p) {
01661 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01662 }
01663
01664 if (!vms_p) {
01665 vms_p = create_vm_state_from_user(vmu);
01666 }
01667 ret = init_mailstream(vms_p, fold);
01668 if (!vms_p->mailstream) {
01669 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
01670 return -1;
01671 }
01672 if (ret == 0) {
01673 ast_mutex_lock(&vms_p->lock);
01674 pgm = mail_newsearchpgm ();
01675 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01676 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01677 pgm->header = hdr;
01678 if (fold != 1) {
01679 pgm->unseen = 1;
01680 pgm->seen = 0;
01681 }
01682
01683
01684
01685 else {
01686 pgm->unseen = 0;
01687 pgm->seen = 1;
01688 }
01689
01690 if (urgent) {
01691 pgm->flagged = 1;
01692 pgm->unflagged = 0;
01693 }
01694 pgm->undeleted = 1;
01695 pgm->deleted = 0;
01696
01697 vms_p->vmArrayIndex = 0;
01698 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01699 if (fold == 0 && urgent == 0)
01700 vms_p->newmessages = vms_p->vmArrayIndex;
01701 if (fold == 1)
01702 vms_p->oldmessages = vms_p->vmArrayIndex;
01703 if (fold == 0 && urgent == 1)
01704 vms_p->urgentmessages = vms_p->vmArrayIndex;
01705
01706 mail_free_searchpgm(&pgm);
01707 ast_mutex_unlock(&vms_p->lock);
01708 vms_p->updated = 0;
01709 return vms_p->vmArrayIndex;
01710 } else {
01711 ast_mutex_lock(&vms_p->lock);
01712 mail_ping(vms_p->mailstream);
01713 ast_mutex_unlock(&vms_p->lock);
01714 }
01715 return 0;
01716 }
01717
01718 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, const char *flag)
01719 {
01720 char *myserveremail = serveremail;
01721 char fn[PATH_MAX];
01722 char introfn[PATH_MAX];
01723 char mailbox[256];
01724 char *stringp;
01725 FILE *p=NULL;
01726 char tmp[80] = "/tmp/astmail-XXXXXX";
01727 long len;
01728 void *buf;
01729 int tempcopy = 0;
01730 STRING str;
01731 int ret;
01732 char *imap_flags = NIL;
01733
01734
01735 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
01736 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
01737 imap_flags="\\FLAGGED";
01738 }
01739
01740
01741 fmt = ast_strdupa(fmt);
01742 stringp = fmt;
01743 strsep(&stringp, "|");
01744
01745 if (!ast_strlen_zero(vmu->serveremail))
01746 myserveremail = vmu->serveremail;
01747
01748 if (msgnum > -1)
01749 make_file(fn, sizeof(fn), dir, msgnum);
01750 else
01751 ast_copy_string (fn, dir, sizeof(fn));
01752
01753 snprintf(introfn, sizeof(introfn), "%sintro", fn);
01754 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
01755 *introfn = '\0';
01756 }
01757
01758 if (ast_strlen_zero(vmu->email)) {
01759
01760
01761
01762
01763
01764 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01765 tempcopy = 1;
01766 }
01767
01768 if (!strcmp(fmt, "wav49"))
01769 fmt = "WAV";
01770 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
01771
01772
01773
01774 if (!(p = vm_mkftemp(tmp))) {
01775 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01776 if (tempcopy)
01777 *(vmu->email) = '\0';
01778 return -1;
01779 }
01780
01781 if (msgnum < 0 && imapgreetings) {
01782 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
01783 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
01784 return -1;
01785 }
01786 imap_delete_old_greeting(fn, vms);
01787 }
01788
01789 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
01790
01791 len = ftell(p);
01792 rewind(p);
01793 if (!(buf = ast_malloc(len + 1))) {
01794 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
01795 fclose(p);
01796 if (tempcopy)
01797 *(vmu->email) = '\0';
01798 return -1;
01799 }
01800 if (fread(buf, len, 1, p) < len) {
01801 if (ferror(p)) {
01802 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
01803 return -1;
01804 }
01805 }
01806 ((char *)buf)[len] = '\0';
01807 INIT(&str, mail_string, buf, len);
01808 ret = init_mailstream(vms, NEW_FOLDER);
01809 if (ret == 0) {
01810 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
01811 ast_mutex_lock(&vms->lock);
01812 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
01813 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01814 ast_mutex_unlock(&vms->lock);
01815 fclose(p);
01816 unlink(tmp);
01817 ast_free(buf);
01818 } else {
01819 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n",mailbox);
01820 fclose(p);
01821 unlink(tmp);
01822 ast_free(buf);
01823 return -1;
01824 }
01825 ast_debug(3, "%s stored\n", fn);
01826
01827 if (tempcopy)
01828 *(vmu->email) = '\0';
01829
01830 return 0;
01831
01832 }
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
01848 {
01849 char tmp[PATH_MAX] = "";
01850 char *mailboxnc;
01851 char *context;
01852 char *mb;
01853 char *cur;
01854 if (newmsgs)
01855 *newmsgs = 0;
01856 if (oldmsgs)
01857 *oldmsgs = 0;
01858 if (urgentmsgs)
01859 *urgentmsgs = 0;
01860
01861 ast_debug(3,"Mailbox is set to %s\n",mailbox_context);
01862
01863 if (ast_strlen_zero(mailbox_context))
01864 return 0;
01865
01866 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01867 context = strchr(tmp, '@');
01868 if (strchr(mailbox_context, ',')) {
01869 int tmpnew, tmpold, tmpurgent;
01870 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01871 mb = tmp;
01872 while ((cur = strsep(&mb, ", "))) {
01873 if (!ast_strlen_zero(cur)) {
01874 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01875 return -1;
01876 else {
01877 if (newmsgs)
01878 *newmsgs += tmpnew;
01879 if (oldmsgs)
01880 *oldmsgs += tmpold;
01881 if (urgentmsgs)
01882 *urgentmsgs += tmpurgent;
01883 }
01884 }
01885 }
01886 return 0;
01887 }
01888 if (context) {
01889 *context = '\0';
01890 mailboxnc = tmp;
01891 context++;
01892 } else {
01893 context = "default";
01894 mailboxnc = (char *)mailbox_context;
01895 }
01896 if (newmsgs) {
01897 if ((*newmsgs = messagecount(context, mailboxnc, imapfolder)) < 0)
01898 return -1;
01899 }
01900 if (oldmsgs) {
01901 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01902 return -1;
01903 }
01904 if (urgentmsgs) {
01905 if((*urgentmsgs = messagecount(context, mailboxnc, "Urgent")) < 0)
01906 return -1;
01907 }
01908 return 0;
01909 }
01910
01911 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01912 {
01913 return inboxcount2(mailbox_context, NULL, newmsgs, oldmsgs);
01914 }
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926 static int has_voicemail(const char *mailbox, const char *folder)
01927 {
01928 char tmp[256], *tmp2, *box, *context;
01929 ast_copy_string(tmp, mailbox, sizeof(tmp));
01930 tmp2 = tmp;
01931 if (strchr(tmp2, ',')) {
01932 while ((box = strsep(&tmp2, ","))) {
01933 if (!ast_strlen_zero(box)) {
01934 if (has_voicemail(box, folder))
01935 return 1;
01936 }
01937 }
01938 }
01939 if ((context= strchr(tmp, '@')))
01940 *context++ = '\0';
01941 else
01942 context = "default";
01943 return messagecount(context, tmp, folder) ? 1 : 0;
01944 }
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961 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, char *flag)
01962 {
01963 struct vm_state *sendvms = NULL, *destvms = NULL;
01964 char messagestring[10];
01965 if (msgnum >= recip->maxmsg) {
01966 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01967 return -1;
01968 }
01969 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01970 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01971 return -1;
01972 }
01973 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01974 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01975 return -1;
01976 }
01977 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01978 ast_mutex_lock(&sendvms->lock);
01979 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
01980 ast_mutex_unlock(&sendvms->lock);
01981 return 0;
01982 }
01983 ast_mutex_unlock(&sendvms->lock);
01984 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01985 return -1;
01986 }
01987
01988 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01989 {
01990 char tmp[256], *t = tmp;
01991 size_t left = sizeof(tmp);
01992
01993 if (box == OLD_FOLDER) {
01994 ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox));
01995 } else {
01996 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01997 }
01998
01999 if (box == NEW_FOLDER) {
02000 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02001 } else {
02002 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box));
02003 }
02004
02005
02006 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02007
02008
02009 if (!ast_strlen_zero(authuser))
02010 ast_build_string(&t, &left, "/authuser=%s", authuser);
02011
02012
02013 if (!ast_strlen_zero(imapflags))
02014 ast_build_string(&t, &left, "/%s", imapflags);
02015
02016
02017 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02018 if (box == NEW_FOLDER || box == OLD_FOLDER)
02019 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
02020 else if (box == GREETINGS_FOLDER)
02021 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02022 else {
02023 if (!ast_strlen_zero(imapparentfolder)) {
02024
02025 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box));
02026 } else {
02027 snprintf(spec, len, "%s%s", tmp, mbox(box));
02028 }
02029 }
02030 }
02031
02032 static int init_mailstream(struct vm_state *vms, int box)
02033 {
02034 MAILSTREAM *stream = NIL;
02035 long debug;
02036 char tmp[256];
02037
02038 if (!vms) {
02039 ast_log (LOG_ERROR,"vm_state is NULL!\n");
02040 return -1;
02041 }
02042 if (option_debug > 2)
02043 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
02044 if (vms->mailstream == NIL || !vms->mailstream) {
02045 if (option_debug)
02046 ast_log (LOG_DEBUG,"mailstream not set.\n");
02047 } else {
02048 stream = vms->mailstream;
02049 }
02050
02051 debug = NIL;
02052
02053 if (delimiter == '\0') {
02054 char *cp;
02055 #ifdef USE_SYSTEM_IMAP
02056 #include <imap/linkage.c>
02057 #elif defined(USE_SYSTEM_CCLIENT)
02058 #include <c-client/linkage.c>
02059 #else
02060 #include "linkage.c"
02061 #endif
02062
02063 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02064 ast_mutex_lock(&vms->lock);
02065 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02066 ast_mutex_unlock(&vms->lock);
02067 if (stream == NIL) {
02068 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02069 return -1;
02070 }
02071 get_mailbox_delimiter(stream);
02072
02073 for (cp = imapfolder; *cp; cp++)
02074 if (*cp == '/')
02075 *cp = delimiter;
02076 }
02077
02078 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02079 if (option_debug > 2)
02080 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
02081 ast_mutex_lock(&vms->lock);
02082 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02083 ast_mutex_unlock(&vms->lock);
02084 if (vms->mailstream == NIL) {
02085 return -1;
02086 } else {
02087 return 0;
02088 }
02089 }
02090
02091 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02092 {
02093 SEARCHPGM *pgm;
02094 SEARCHHEADER *hdr;
02095 int ret, urgent = 0;
02096
02097
02098 if (box == 11) {
02099 box = NEW_FOLDER;
02100 urgent = 1;
02101 }
02102
02103 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
02104 ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser);
02105
02106 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02107 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02108 return -1;
02109 }
02110
02111 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02112
02113
02114 if (box == 0) {
02115 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
02116 check_quota(vms,(char *)mbox(box));
02117 }
02118
02119 ast_mutex_lock(&vms->lock);
02120 pgm = mail_newsearchpgm();
02121
02122
02123 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02124 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02125 pgm->header = hdr;
02126 pgm->deleted = 0;
02127 pgm->undeleted = 1;
02128
02129
02130 if (box == NEW_FOLDER && urgent == 1) {
02131 pgm->unseen = 1;
02132 pgm->seen = 0;
02133 pgm->flagged = 1;
02134 pgm->unflagged = 0;
02135 } else if (box == NEW_FOLDER && urgent == 0) {
02136 pgm->unseen = 1;
02137 pgm->seen = 0;
02138 pgm->flagged = 0;
02139 pgm->unflagged = 1;
02140 } else if (box == OLD_FOLDER) {
02141 pgm->seen = 1;
02142 pgm->unseen = 0;
02143 }
02144
02145 ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
02146
02147 vms->vmArrayIndex = 0;
02148 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02149 vms->lastmsg = vms->vmArrayIndex - 1;
02150 mail_free_searchpgm(&pgm);
02151
02152 ast_mutex_unlock(&vms->lock);
02153 return 0;
02154 }
02155
02156 static void write_file(char *filename, char *buffer, unsigned long len)
02157 {
02158 FILE *output;
02159
02160 output = fopen (filename, "w");
02161 if (fwrite(buffer, len, 1, output) != 1) {
02162 if (ferror(output)) {
02163 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02164 }
02165 }
02166 fclose (output);
02167 }
02168
02169 static void update_messages_by_imapuser(const char *user, unsigned long number)
02170 {
02171 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02172
02173 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02174 return;
02175 }
02176
02177 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02178 vms->msgArray[vms->vmArrayIndex++] = number;
02179 }
02180
02181 void mm_searched(MAILSTREAM *stream, unsigned long number)
02182 {
02183 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02184
02185 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02186 return;
02187
02188 update_messages_by_imapuser(user, number);
02189 }
02190
02191 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02192 {
02193 struct ast_variable *var;
02194 struct ast_vm_user *vmu;
02195
02196 vmu = ast_calloc(1, sizeof *vmu);
02197 if (!vmu)
02198 return NULL;
02199 ast_set_flag(vmu, VM_ALLOCED);
02200 populate_defaults(vmu);
02201
02202 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02203 if (var) {
02204 apply_options_full(vmu, var);
02205 ast_variables_destroy(var);
02206 return vmu;
02207 } else {
02208 free(vmu);
02209 return NULL;
02210 }
02211 }
02212
02213
02214
02215 void mm_exists(MAILSTREAM * stream, unsigned long number)
02216 {
02217
02218 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02219 if (number == 0) return;
02220 set_update(stream);
02221 }
02222
02223
02224 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02225 {
02226
02227 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02228 if (number == 0) return;
02229 set_update(stream);
02230 }
02231
02232
02233 void mm_flags(MAILSTREAM * stream, unsigned long number)
02234 {
02235
02236 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02237 if (number == 0) return;
02238 set_update(stream);
02239 }
02240
02241
02242 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02243 {
02244 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02245 mm_log (string, errflg);
02246 }
02247
02248
02249 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02250 {
02251 if (delimiter == '\0') {
02252 delimiter = delim;
02253 }
02254
02255 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02256 if (attributes & LATT_NOINFERIORS)
02257 ast_debug(5, "no inferiors\n");
02258 if (attributes & LATT_NOSELECT)
02259 ast_debug(5, "no select\n");
02260 if (attributes & LATT_MARKED)
02261 ast_debug(5, "marked\n");
02262 if (attributes & LATT_UNMARKED)
02263 ast_debug(5, "unmarked\n");
02264 }
02265
02266
02267 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02268 {
02269 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02270 if (attributes & LATT_NOINFERIORS)
02271 ast_debug(5, "no inferiors\n");
02272 if (attributes & LATT_NOSELECT)
02273 ast_debug(5, "no select\n");
02274 if (attributes & LATT_MARKED)
02275 ast_debug(5, "marked\n");
02276 if (attributes & LATT_UNMARKED)
02277 ast_debug(5, "unmarked\n");
02278 }
02279
02280
02281 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02282 {
02283 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02284 if (status->flags & SA_MESSAGES)
02285 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02286 if (status->flags & SA_RECENT)
02287 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02288 if (status->flags & SA_UNSEEN)
02289 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02290 if (status->flags & SA_UIDVALIDITY)
02291 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02292 if (status->flags & SA_UIDNEXT)
02293 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02294 ast_log(AST_LOG_NOTICE, "\n");
02295 }
02296
02297
02298 void mm_log(char *string, long errflg)
02299 {
02300 switch ((short) errflg) {
02301 case NIL:
02302 ast_debug(1,"IMAP Info: %s\n", string);
02303 break;
02304 case PARSE:
02305 case WARN:
02306 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02307 break;
02308 case ERROR:
02309 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02310 break;
02311 }
02312 }
02313
02314
02315 void mm_dlog(char *string)
02316 {
02317 ast_log(AST_LOG_NOTICE, "%s\n", string);
02318 }
02319
02320
02321 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02322 {
02323 struct ast_vm_user *vmu;
02324
02325 ast_debug(4, "Entering callback mm_login\n");
02326
02327 ast_copy_string(user, mb->user, MAILTMPLEN);
02328
02329
02330 if (!ast_strlen_zero(authpassword)) {
02331 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02332 } else {
02333 AST_LIST_TRAVERSE(&users, vmu, list) {
02334 if (!strcasecmp(mb->user, vmu->imapuser)) {
02335 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02336 break;
02337 }
02338 }
02339 if (!vmu) {
02340 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02341 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02342 free_user(vmu);
02343 }
02344 }
02345 }
02346 }
02347
02348
02349 void mm_critical(MAILSTREAM * stream)
02350 {
02351 }
02352
02353
02354 void mm_nocritical(MAILSTREAM * stream)
02355 {
02356 }
02357
02358
02359 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02360 {
02361 kill (getpid (), SIGSTOP);
02362 return NIL;
02363 }
02364
02365
02366 void mm_fatal(char *string)
02367 {
02368 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02369 }
02370
02371
02372 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02373 {
02374 struct vm_state *vms;
02375 char *mailbox = stream->mailbox, *user;
02376 char buf[1024] = "";
02377 unsigned long usage = 0, limit = 0;
02378
02379 while (pquota) {
02380 usage = pquota->usage;
02381 limit = pquota->limit;
02382 pquota = pquota->next;
02383 }
02384
02385 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
02386 ast_log(AST_LOG_ERROR, "No state found.\n");
02387 return;
02388 }
02389
02390 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02391
02392 vms->quota_usage = usage;
02393 vms->quota_limit = limit;
02394 }
02395
02396 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02397 {
02398 char *start, *eol_pnt;
02399 int taglen;
02400
02401 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02402 return NULL;
02403
02404 taglen = strlen(tag) + 1;
02405 if (taglen < 1)
02406 return NULL;
02407
02408 if (!(start = strstr(header, tag)))
02409 return NULL;
02410
02411
02412 memset(buf, 0, len);
02413
02414 ast_copy_string(buf, start+taglen, len);
02415 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02416 *eol_pnt = '\0';
02417 return buf;
02418 }
02419
02420 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02421 {
02422 char *start, *quote, *eol_pnt;
02423
02424 if (ast_strlen_zero(mailbox))
02425 return NULL;
02426
02427 if (!(start = strstr(mailbox, "/user=")))
02428 return NULL;
02429
02430 ast_copy_string(buf, start+6, len);
02431
02432 if (!(quote = strchr(buf, '\"'))) {
02433 if (!(eol_pnt = strchr(buf, '/')))
02434 eol_pnt = strchr(buf,'}');
02435 *eol_pnt = '\0';
02436 return buf;
02437 } else {
02438 eol_pnt = strchr(buf+1,'\"');
02439 *eol_pnt = '\0';
02440 return buf+1;
02441 }
02442 }
02443
02444 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02445 {
02446 struct vm_state *vms_p;
02447
02448 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02449 return vms_p;
02450 }
02451 if (option_debug > 4)
02452 ast_log(AST_LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02453 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02454 return NULL;
02455 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02456 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02457 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02458 vms_p->mailstream = NIL;
02459 if (option_debug > 4)
02460 ast_log(AST_LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02461 vms_p->updated = 1;
02462
02463 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02464 init_vm_state(vms_p);
02465 vmstate_insert(vms_p);
02466 return vms_p;
02467 }
02468
02469 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02470 {
02471 struct vmstate *vlist = NULL;
02472
02473 if (interactive) {
02474 struct vm_state *vms;
02475 vms = pthread_getspecific(ts_vmstate.key);
02476 return vms;
02477 }
02478
02479 AST_LIST_LOCK(&vmstates);
02480 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02481 if (!vlist->vms) {
02482 ast_debug(3, "error: vms is NULL for %s\n", user);
02483 continue;
02484 }
02485 if (!vlist->vms->imapuser) {
02486 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02487 continue;
02488 }
02489
02490 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02491 AST_LIST_UNLOCK(&vmstates);
02492 return vlist->vms;
02493 }
02494 }
02495 AST_LIST_UNLOCK(&vmstates);
02496
02497 ast_debug(3, "%s not found in vmstates\n", user);
02498
02499 return NULL;
02500 }
02501
02502 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02503 {
02504
02505 struct vmstate *vlist = NULL;
02506 const char *local_context = S_OR(context, "default");
02507
02508 if (interactive) {
02509 struct vm_state *vms;
02510 vms = pthread_getspecific(ts_vmstate.key);
02511 return vms;
02512 }
02513
02514 AST_LIST_LOCK(&vmstates);
02515 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02516 if (!vlist->vms) {
02517 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02518 continue;
02519 }
02520 if (!vlist->vms->username || !vlist->vms->context) {
02521 ast_debug(3, "error: username is NULL for %s\n", mailbox);
02522 continue;
02523 }
02524
02525 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
02526
02527 if (!strcmp(vlist->vms->username,mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
02528 ast_debug(3, "Found it!\n");
02529 AST_LIST_UNLOCK(&vmstates);
02530 return vlist->vms;
02531 }
02532 }
02533 AST_LIST_UNLOCK(&vmstates);
02534
02535 ast_debug(3, "%s not found in vmstates\n", mailbox);
02536
02537 return NULL;
02538 }
02539
02540 static void vmstate_insert(struct vm_state *vms)
02541 {
02542 struct vmstate *v;
02543 struct vm_state *altvms;
02544
02545
02546
02547
02548 if (vms->interactive == 1) {
02549 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
02550 if (altvms) {
02551 ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username);
02552 vms->newmessages = altvms->newmessages;
02553 vms->oldmessages = altvms->oldmessages;
02554 vms->vmArrayIndex = altvms->vmArrayIndex;
02555 vms->lastmsg = altvms->lastmsg;
02556 vms->curmsg = altvms->curmsg;
02557
02558 vms->persist_vms = altvms;
02559
02560 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02561 vms->mailstream = altvms->mailstream;
02562 #else
02563 vms->mailstream = NIL;
02564 #endif
02565 }
02566 return;
02567 }
02568
02569 if (!(v = ast_calloc(1, sizeof(*v))))
02570 return;
02571
02572 v->vms = vms;
02573
02574 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02575
02576 AST_LIST_LOCK(&vmstates);
02577 AST_LIST_INSERT_TAIL(&vmstates, v, list);
02578 AST_LIST_UNLOCK(&vmstates);
02579 }
02580
02581 static void vmstate_delete(struct vm_state *vms)
02582 {
02583 struct vmstate *vc = NULL;
02584 struct vm_state *altvms = NULL;
02585
02586
02587
02588 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
02589 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
02590 altvms->newmessages = vms->newmessages;
02591 altvms->oldmessages = vms->oldmessages;
02592 altvms->updated = 1;
02593 vms->mailstream = mail_close(vms->mailstream);
02594
02595
02596 return;
02597 }
02598
02599 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02600
02601 AST_LIST_LOCK(&vmstates);
02602 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
02603 if (vc->vms == vms) {
02604 AST_LIST_REMOVE_CURRENT(list);
02605 break;
02606 }
02607 }
02608 AST_LIST_TRAVERSE_SAFE_END
02609 AST_LIST_UNLOCK(&vmstates);
02610
02611 if (vc) {
02612 ast_mutex_destroy(&vc->vms->lock);
02613 ast_free(vc);
02614 }
02615 else
02616 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02617 }
02618
02619 static void set_update(MAILSTREAM * stream)
02620 {
02621 struct vm_state *vms;
02622 char *mailbox = stream->mailbox, *user;
02623 char buf[1024] = "";
02624
02625 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
02626 if (user && option_debug > 2)
02627 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
02628 return;
02629 }
02630
02631 ast_debug(3, "User %s mailbox set for update.\n", user);
02632
02633 vms->updated = 1;
02634 }
02635
02636 static void init_vm_state(struct vm_state *vms)
02637 {
02638 int x;
02639 vms->vmArrayIndex = 0;
02640 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
02641 vms->msgArray[x] = 0;
02642 }
02643 ast_mutex_init(&vms->lock);
02644 }
02645
02646 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
02647 {
02648 char *body_content;
02649 char *body_decoded;
02650 char *fn = is_intro ? vms->introfn : vms->fn;
02651 unsigned long len;
02652 unsigned long newlen;
02653 char filename[256];
02654
02655 if (!body || body == NIL)
02656 return -1;
02657
02658 ast_mutex_lock(&vms->lock);
02659 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02660 ast_mutex_unlock(&vms->lock);
02661 if (body_content != NIL) {
02662 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
02663
02664 body_decoded = rfc822_base64((unsigned char *)body_content, len, &newlen);
02665
02666 if (!newlen) {
02667 return -1;
02668 }
02669 write_file(filename, (char *) body_decoded, newlen);
02670 } else {
02671 ast_debug(5, "Body of message is NULL.\n");
02672 return -1;
02673 }
02674 return 0;
02675 }
02676
02677
02678
02679
02680
02681
02682
02683
02684 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02685 char tmp[50];
02686 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02687 mail_list(stream, tmp, "*");
02688 }
02689
02690
02691
02692
02693
02694
02695
02696
02697 static void check_quota(struct vm_state *vms, char *mailbox) {
02698 ast_mutex_lock(&vms->lock);
02699 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02700 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02701 if (vms && vms->mailstream != NULL) {
02702 imap_getquotaroot(vms->mailstream, mailbox);
02703 } else {
02704 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
02705 }
02706 ast_mutex_unlock(&vms->lock);
02707 }
02708
02709 #endif
02710
02711
02712
02713
02714
02715 static int vm_lock_path(const char *path)
02716 {
02717 switch (ast_lock_path(path)) {
02718 case AST_LOCK_TIMEOUT:
02719 return -1;
02720 default:
02721 return 0;
02722 }
02723 }
02724
02725
02726 #ifdef ODBC_STORAGE
02727 struct generic_prepare_struct {
02728 char *sql;
02729 int argc;
02730 char **argv;
02731 };
02732
02733 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02734 {
02735 struct generic_prepare_struct *gps = data;
02736 int res, i;
02737 SQLHSTMT stmt;
02738
02739 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02740 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02741 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
02742 return NULL;
02743 }
02744 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02745 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02746 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02747 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02748 return NULL;
02749 }
02750 for (i = 0; i < gps->argc; i++)
02751 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02752
02753 return stmt;
02754 }
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770 static int retrieve_file(char *dir, int msgnum)
02771 {
02772 int x = 0;
02773 int res;
02774 int fd=-1;
02775 size_t fdlen = 0;
02776 void *fdm = MAP_FAILED;
02777 SQLSMALLINT colcount=0;
02778 SQLHSTMT stmt;
02779 char sql[PATH_MAX];
02780 char fmt[80]="";
02781 char *c;
02782 char coltitle[256];
02783 SQLSMALLINT collen;
02784 SQLSMALLINT datatype;
02785 SQLSMALLINT decimaldigits;
02786 SQLSMALLINT nullable;
02787 SQLULEN colsize;
02788 SQLLEN colsize2;
02789 FILE *f=NULL;
02790 char rowdata[80];
02791 char fn[PATH_MAX];
02792 char full_fn[PATH_MAX];
02793 char msgnums[80];
02794 char *argv[] = { dir, msgnums };
02795 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02796
02797 struct odbc_obj *obj;
02798 obj = ast_odbc_request_obj(odbc_database, 0);
02799 if (obj) {
02800 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02801 c = strchr(fmt, '|');
02802 if (c)
02803 *c = '\0';
02804 if (!strcasecmp(fmt, "wav49"))
02805 strcpy(fmt, "WAV");
02806 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02807 if (msgnum > -1)
02808 make_file(fn, sizeof(fn), dir, msgnum);
02809 else
02810 ast_copy_string(fn, dir, sizeof(fn));
02811
02812
02813 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02814
02815 if (!(f = fopen(full_fn, "w+"))) {
02816 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02817 goto yuck;
02818 }
02819
02820 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02821 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02822 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02823 if (!stmt) {
02824 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02825 ast_odbc_release_obj(obj);
02826 goto yuck;
02827 }
02828 res = SQLFetch(stmt);
02829 if (res == SQL_NO_DATA) {
02830 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02831 ast_odbc_release_obj(obj);
02832 goto yuck;
02833 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02834 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02835 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02836 ast_odbc_release_obj(obj);
02837 goto yuck;
02838 }
02839 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
02840 if (fd < 0) {
02841 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02842 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02843 ast_odbc_release_obj(obj);
02844 goto yuck;
02845 }
02846 res = SQLNumResultCols(stmt, &colcount);
02847 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02848 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02849 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02850 ast_odbc_release_obj(obj);
02851 goto yuck;
02852 }
02853 if (f)
02854 fprintf(f, "[message]\n");
02855 for (x=0;x<colcount;x++) {
02856 rowdata[0] = '\0';
02857 collen = sizeof(coltitle);
02858 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02859 &datatype, &colsize, &decimaldigits, &nullable);
02860 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02861 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02862 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02863 ast_odbc_release_obj(obj);
02864 goto yuck;
02865 }
02866 if (!strcasecmp(coltitle, "recording")) {
02867 off_t offset;
02868 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02869 fdlen = colsize2;
02870 if (fd > -1) {
02871 char tmp[1]="";
02872 lseek(fd, fdlen - 1, SEEK_SET);
02873 if (write(fd, tmp, 1) != 1) {
02874 close(fd);
02875 fd = -1;
02876 continue;
02877 }
02878
02879 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02880 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02881 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02882 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02883 ast_odbc_release_obj(obj);
02884 goto yuck;
02885 } else {
02886 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02887 munmap(fdm, CHUNKSIZE);
02888 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02889 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02890 unlink(full_fn);
02891 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02892 ast_odbc_release_obj(obj);
02893 goto yuck;
02894 }
02895 }
02896 }
02897 if (truncate(full_fn, fdlen) < 0) {
02898 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
02899 }
02900 }
02901 } else {
02902 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02903 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02904 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
02905 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02906 ast_odbc_release_obj(obj);
02907 goto yuck;
02908 }
02909 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02910 fprintf(f, "%s=%s\n", coltitle, rowdata);
02911 }
02912 }
02913 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02914 ast_odbc_release_obj(obj);
02915 } else
02916 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02917 yuck:
02918 if (f)
02919 fclose(f);
02920 if (fd > -1)
02921 close(fd);
02922 return x - 1;
02923 }
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933
02934
02935 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02936 {
02937 int x = 0;
02938 int res;
02939 SQLHSTMT stmt;
02940 char sql[PATH_MAX];
02941 char rowdata[20];
02942 char *argv[] = { dir };
02943 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02944
02945 struct odbc_obj *obj;
02946 obj = ast_odbc_request_obj(odbc_database, 0);
02947 if (obj) {
02948 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
02949 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02950 if (!stmt) {
02951 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02952 ast_odbc_release_obj(obj);
02953 goto yuck;
02954 }
02955 res = SQLFetch(stmt);
02956 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02957 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02958 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02959 ast_odbc_release_obj(obj);
02960 goto yuck;
02961 }
02962 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02963 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02964 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02965 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02966 ast_odbc_release_obj(obj);
02967 goto yuck;
02968 }
02969 if (sscanf(rowdata, "%d", &x) != 1)
02970 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
02971 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02972 ast_odbc_release_obj(obj);
02973 } else
02974 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02975 yuck:
02976 return x - 1;
02977 }
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988 static int message_exists(char *dir, int msgnum)
02989 {
02990 int x = 0;
02991 int res;
02992 SQLHSTMT stmt;
02993 char sql[PATH_MAX];
02994 char rowdata[20];
02995 char msgnums[20];
02996 char *argv[] = { dir, msgnums };
02997 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02998
02999 struct odbc_obj *obj;
03000 obj = ast_odbc_request_obj(odbc_database, 0);
03001 if (obj) {
03002 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03003 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03004 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03005 if (!stmt) {
03006 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03007 ast_odbc_release_obj(obj);
03008 goto yuck;
03009 }
03010 res = SQLFetch(stmt);
03011 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03012 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03013 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03014 ast_odbc_release_obj(obj);
03015 goto yuck;
03016 }
03017 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03018 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03019 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03020 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03021 ast_odbc_release_obj(obj);
03022 goto yuck;
03023 }
03024 if (sscanf(rowdata, "%d", &x) != 1)
03025 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03026 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03027 ast_odbc_release_obj(obj);
03028 } else
03029 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03030 yuck:
03031 return x;
03032 }
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046 static int count_messages(struct ast_vm_user *vmu, char *dir)
03047 {
03048 return last_message_index(vmu, dir) + 1;
03049 }
03050
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061 static void delete_file(char *sdir, int smsg)
03062 {
03063 SQLHSTMT stmt;
03064 char sql[PATH_MAX];
03065 char msgnums[20];
03066 char *argv[] = { sdir, msgnums };
03067 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03068
03069 struct odbc_obj *obj;
03070 obj = ast_odbc_request_obj(odbc_database, 0);
03071 if (obj) {
03072 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03073 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03074 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03075 if (!stmt)
03076 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03077 else
03078 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03079 ast_odbc_release_obj(obj);
03080 } else
03081 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03082 return;
03083 }
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03097 {
03098 SQLHSTMT stmt;
03099 char sql[512];
03100 char msgnums[20];
03101 char msgnumd[20];
03102 struct odbc_obj *obj;
03103 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03104 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03105
03106 delete_file(ddir, dmsg);
03107 obj = ast_odbc_request_obj(odbc_database, 0);
03108 if (obj) {
03109 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03110 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03111 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext, flag) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
03112 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03113 if (!stmt)
03114 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03115 else
03116 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03117 ast_odbc_release_obj(obj);
03118 } else
03119 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03120 return;
03121 }
03122
03123 struct insert_data {
03124 char *sql;
03125 char *dir;
03126 char *msgnums;
03127 void *data;
03128 SQLLEN datalen;
03129 SQLLEN indlen;
03130 const char *context;
03131 const char *macrocontext;
03132 const char *callerid;
03133 const char *origtime;
03134 const char *duration;
03135 char *mailboxuser;
03136 char *mailboxcontext;
03137 const char *category;
03138 const char *flag;
03139 };
03140
03141 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03142 {
03143 struct insert_data *data = vdata;
03144 int res;
03145 SQLHSTMT stmt;
03146
03147 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03148 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03149 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03150 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03151 return NULL;
03152 }
03153
03154 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *)data->dir, 0, NULL);
03155 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *)data->msgnums, 0, NULL);
03156 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *)data->data, data->datalen, &data->indlen);
03157 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *)data->context, 0, NULL);
03158 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *)data->macrocontext, 0, NULL);
03159 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *)data->callerid, 0, NULL);
03160 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *)data->origtime, 0, NULL);
03161 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *)data->duration, 0, NULL);
03162 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *)data->mailboxuser, 0, NULL);
03163 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *)data->mailboxcontext, 0, NULL);
03164 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *)data->flag, 0, NULL);
03165 if (!ast_strlen_zero(data->category)) {
03166 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *)data->category, 0, NULL);
03167 }
03168 res = SQLExecDirect(stmt, (unsigned char *)data->sql, SQL_NTS);
03169 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03170 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03171 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03172 return NULL;
03173 }
03174
03175 return stmt;
03176 }
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
03192 {
03193 int res = 0;
03194 int fd = -1;
03195 void *fdm = MAP_FAILED;
03196 size_t fdlen = -1;
03197 SQLHSTMT stmt;
03198 char sql[PATH_MAX];
03199 char msgnums[20];
03200 char fn[PATH_MAX];
03201 char full_fn[PATH_MAX];
03202 char fmt[80]="";
03203 char *c;
03204 struct ast_config *cfg=NULL;
03205 struct odbc_obj *obj;
03206 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext };
03207 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03208
03209 delete_file(dir, msgnum);
03210 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03211 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03212 return -1;
03213 }
03214
03215 do {
03216 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03217 c = strchr(fmt, '|');
03218 if (c)
03219 *c = '\0';
03220 if (!strcasecmp(fmt, "wav49"))
03221 strcpy(fmt, "WAV");
03222 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
03223 if (msgnum > -1)
03224 make_file(fn, sizeof(fn), dir, msgnum);
03225 else
03226 ast_copy_string(fn, dir, sizeof(fn));
03227 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03228 cfg = ast_config_load(full_fn, config_flags);
03229 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03230 fd = open(full_fn, O_RDWR);
03231 if (fd < 0) {
03232 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03233 res = -1;
03234 break;
03235 }
03236 if (cfg) {
03237 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03238 idata.context = "";
03239 }
03240 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03241 idata.macrocontext = "";
03242 }
03243 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03244 idata.callerid = "";
03245 }
03246 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03247 idata.origtime = "";
03248 }
03249 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03250 idata.duration = "";
03251 }
03252 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03253 idata.category = "";
03254 }
03255 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03256 idata.flag = "";
03257 }
03258 }
03259 fdlen = lseek(fd, 0, SEEK_END);
03260 lseek(fd, 0, SEEK_SET);
03261 printf("Length is %zd\n", fdlen);
03262 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
03263 if (fdm == MAP_FAILED) {
03264 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03265 res = -1;
03266 break;
03267 }
03268 idata.data = fdm;
03269 idata.datalen = idata.indlen = fdlen;
03270
03271 if (!ast_strlen_zero(idata.category))
03272 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03273 else
03274 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03275
03276 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03277 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03278 } else {
03279 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03280 res = -1;
03281 }
03282 } while (0);
03283 if (obj) {
03284 ast_odbc_release_obj(obj);
03285 }
03286 if (cfg)
03287 ast_config_destroy(cfg);
03288 if (fdm != MAP_FAILED)
03289 munmap(fdm, fdlen);
03290 if (fd > -1)
03291 close(fd);
03292 return res;
03293 }
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03309 {
03310 SQLHSTMT stmt;
03311 char sql[PATH_MAX];
03312 char msgnums[20];
03313 char msgnumd[20];
03314 struct odbc_obj *obj;
03315 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03316 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03317
03318 delete_file(ddir, dmsg);
03319 obj = ast_odbc_request_obj(odbc_database, 0);
03320 if (obj) {
03321 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03322 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03323 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
03324 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03325 if (!stmt)
03326 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03327 else
03328 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03329 ast_odbc_release_obj(obj);
03330 } else
03331 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03332 return;
03333 }
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346 static int remove_file(char *dir, int msgnum)
03347 {
03348 char fn[PATH_MAX];
03349 char full_fn[PATH_MAX];
03350 char msgnums[80];
03351
03352 if (msgnum > -1) {
03353 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03354 make_file(fn, sizeof(fn), dir, msgnum);
03355 } else
03356 ast_copy_string(fn, dir, sizeof(fn));
03357 ast_filedelete(fn, NULL);
03358 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03359 unlink(full_fn);
03360 return 0;
03361 }
03362 #else
03363 #ifndef IMAP_STORAGE
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373 static int count_messages(struct ast_vm_user *vmu, char *dir)
03374 {
03375
03376 int vmcount = 0;
03377 DIR *vmdir = NULL;
03378 struct dirent *vment = NULL;
03379
03380 if (vm_lock_path(dir))
03381 return ERROR_LOCK_PATH;
03382
03383 if ((vmdir = opendir(dir))) {
03384 while ((vment = readdir(vmdir))) {
03385 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03386 vmcount++;
03387 }
03388 }
03389 closedir(vmdir);
03390 }
03391 ast_unlock_path(dir);
03392
03393 return vmcount;
03394 }
03395
03396
03397
03398
03399
03400
03401
03402
03403 static void rename_file(char *sfn, char *dfn)
03404 {
03405 char stxt[PATH_MAX];
03406 char dtxt[PATH_MAX];
03407 ast_filerename(sfn,dfn,NULL);
03408 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03409 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03410 if (ast_check_realtime("voicemail_data")) {
03411 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03412 }
03413 rename(stxt, dtxt);
03414 }
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426
03427 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03428 {
03429 int x;
03430 unsigned char map[MAXMSGLIMIT] = "";
03431 DIR *msgdir;
03432 struct dirent *msgdirent;
03433 int msgdirint;
03434
03435
03436
03437
03438
03439 msgdir = opendir(dir);
03440 while ((msgdirent = readdir(msgdir))) {
03441 if (sscanf(msgdirent->d_name, "msg%d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03442 map[msgdirint] = 1;
03443 }
03444 closedir(msgdir);
03445
03446 for (x = 0; x < vmu->maxmsg; x++) {
03447 if (map[x] == 0)
03448 break;
03449 }
03450
03451 return x - 1;
03452 }
03453
03454 #endif
03455 #endif
03456 #ifndef IMAP_STORAGE
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467 static int copy(char *infile, char *outfile)
03468 {
03469 int ifd;
03470 int ofd;
03471 int res;
03472 int len;
03473 char buf[4096];
03474
03475 #ifdef HARDLINK_WHEN_POSSIBLE
03476
03477 if (link(infile, outfile)) {
03478 #endif
03479 if ((ifd = open(infile, O_RDONLY)) < 0) {
03480 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03481 return -1;
03482 }
03483 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03484 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03485 close(ifd);
03486 return -1;
03487 }
03488 do {
03489 len = read(ifd, buf, sizeof(buf));
03490 if (len < 0) {
03491 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03492 close(ifd);
03493 close(ofd);
03494 unlink(outfile);
03495 }
03496 if (len) {
03497 res = write(ofd, buf, len);
03498 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03499 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03500 close(ifd);
03501 close(ofd);
03502 unlink(outfile);
03503 }
03504 }
03505 } while (len);
03506 close(ifd);
03507 close(ofd);
03508 return 0;
03509 #ifdef HARDLINK_WHEN_POSSIBLE
03510 } else {
03511
03512 return 0;
03513 }
03514 #endif
03515 }
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526 static void copy_plain_file(char *frompath, char *topath)
03527 {
03528 char frompath2[PATH_MAX], topath2[PATH_MAX];
03529 struct ast_variable *tmp,*var = NULL;
03530 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
03531 ast_filecopy(frompath, topath, NULL);
03532 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03533 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03534 if (ast_check_realtime("voicemail_data")) {
03535 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
03536
03537 for (tmp = var; tmp; tmp = tmp->next) {
03538 if (!strcasecmp(tmp->name, "origmailbox")) {
03539 origmailbox = tmp->value;
03540 } else if (!strcasecmp(tmp->name, "context")) {
03541 context = tmp->value;
03542 } else if (!strcasecmp(tmp->name, "macrocontext")) {
03543 macrocontext = tmp->value;
03544 } else if (!strcasecmp(tmp->name, "exten")) {
03545 exten = tmp->value;
03546 } else if (!strcasecmp(tmp->name, "priority")) {
03547 priority = tmp->value;
03548 } else if (!strcasecmp(tmp->name, "callerchan")) {
03549 callerchan = tmp->value;
03550 } else if (!strcasecmp(tmp->name, "callerid")) {
03551 callerid = tmp->value;
03552 } else if (!strcasecmp(tmp->name, "origdate")) {
03553 origdate = tmp->value;
03554 } else if (!strcasecmp(tmp->name, "origtime")) {
03555 origtime = tmp->value;
03556 } else if (!strcasecmp(tmp->name, "category")) {
03557 category = tmp->value;
03558 } else if (!strcasecmp(tmp->name, "duration")) {
03559 duration = tmp->value;
03560 }
03561 }
03562 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
03563 }
03564 copy(frompath2, topath2);
03565 ast_variables_destroy(var);
03566 }
03567 #endif
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577 static int vm_delete(char *file)
03578 {
03579 char *txt;
03580 int txtsize = 0;
03581
03582 txtsize = (strlen(file) + 5)*sizeof(char);
03583 txt = alloca(txtsize);
03584
03585
03586
03587 if (ast_check_realtime("voicemail_data")) {
03588 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
03589 }
03590 snprintf(txt, txtsize, "%s.txt", file);
03591 unlink(txt);
03592 return ast_filedelete(file, NULL);
03593 }
03594
03595
03596
03597
03598 static int inbuf(struct baseio *bio, FILE *fi)
03599 {
03600 int l;
03601
03602 if (bio->ateof)
03603 return 0;
03604
03605 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
03606 if (ferror(fi))
03607 return -1;
03608
03609 bio->ateof = 1;
03610 return 0;
03611 }
03612
03613 bio->iolen= l;
03614 bio->iocp= 0;
03615
03616 return 1;
03617 }
03618
03619
03620
03621
03622 static int inchar(struct baseio *bio, FILE *fi)
03623 {
03624 if (bio->iocp>=bio->iolen) {
03625 if (!inbuf(bio, fi))
03626 return EOF;
03627 }
03628
03629 return bio->iobuf[bio->iocp++];
03630 }
03631
03632
03633
03634
03635 static int ochar(struct baseio *bio, int c, FILE *so)
03636 {
03637 if (bio->linelength >= BASELINELEN) {
03638 if (fputs(eol,so) == EOF)
03639 return -1;
03640
03641 bio->linelength= 0;
03642 }
03643
03644 if (putc(((unsigned char)c),so) == EOF)
03645 return -1;
03646
03647 bio->linelength++;
03648
03649 return 1;
03650 }
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661 static int base_encode(char *filename, FILE *so)
03662 {
03663 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
03664 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
03665 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
03666 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
03667 int i,hiteof= 0;
03668 FILE *fi;
03669 struct baseio bio;
03670
03671 memset(&bio, 0, sizeof(bio));
03672 bio.iocp = BASEMAXINLINE;
03673
03674 if (!(fi = fopen(filename, "rb"))) {
03675 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03676 return -1;
03677 }
03678
03679 while (!hiteof){
03680 unsigned char igroup[3], ogroup[4];
03681 int c,n;
03682
03683 igroup[0]= igroup[1]= igroup[2]= 0;
03684
03685 for (n= 0;n<3;n++) {
03686 if ((c = inchar(&bio, fi)) == EOF) {
03687 hiteof= 1;
03688 break;
03689 }
03690
03691 igroup[n]= (unsigned char)c;
03692 }
03693
03694 if (n> 0) {
03695 ogroup[0]= dtable[igroup[0]>>2];
03696 ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
03697 ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
03698 ogroup[3]= dtable[igroup[2]&0x3F];
03699
03700 if (n<3) {
03701 ogroup[3]= '=';
03702
03703 if (n<2)
03704 ogroup[2]= '=';
03705 }
03706
03707 for (i= 0;i<4;i++)
03708 ochar(&bio, ogroup[i], so);
03709 }
03710 }
03711
03712 fclose(fi);
03713
03714 if (fputs(eol,so)==EOF)
03715 return 0;
03716
03717 return 1;
03718 }
03719
03720 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
03721 {
03722 char callerid[256];
03723 char fromdir[256], fromfile[256];
03724 struct ast_config *msg_cfg;
03725 const char *origcallerid, *origtime;
03726 char origcidname[80], origcidnum[80], origdate[80];
03727 int inttime;
03728 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03729
03730
03731 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03732 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03733 snprintf(passdata, passdatasize, "%d", msgnum);
03734 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03735 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03736 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03737 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03738 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03739 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03740 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03741 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03742 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03743 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
03744
03745
03746 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03747 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03748 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03749 strcat(fromfile, ".txt");
03750 }
03751 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
03752 if (option_debug > 0) {
03753 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03754 }
03755 return;
03756 }
03757
03758 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03759 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03760 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03761 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03762 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03763 }
03764
03765 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%d", &inttime) == 1) {
03766 struct timeval tv = { inttime, };
03767 struct ast_tm tm;
03768 ast_localtime(&tv, &tm, NULL);
03769 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03770 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03771 }
03772 ast_config_destroy(msg_cfg);
03773 }
03774
03775
03776
03777
03778
03779
03780
03781
03782 static char *quote(const char *from, char *to, size_t len)
03783 {
03784 char *ptr = to;
03785 *ptr++ = '"';
03786 for (; ptr < to + len - 1; from++) {
03787 if (*from == '"')
03788 *ptr++ = '\\';
03789 else if (*from == '\0')
03790 break;
03791 *ptr++ = *from;
03792 }
03793 if (ptr < to + len - 1)
03794 *ptr++ = '"';
03795 *ptr = '\0';
03796 return to;
03797 }
03798
03799
03800
03801
03802
03803 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
03804 {
03805 const struct vm_zone *z = NULL;
03806 struct timeval t = ast_tvnow();
03807
03808
03809 if (!ast_strlen_zero(vmu->zonetag)) {
03810
03811 AST_LIST_LOCK(&zones);
03812 AST_LIST_TRAVERSE(&zones, z, list) {
03813 if (!strcmp(z->name, vmu->zonetag))
03814 break;
03815 }
03816 AST_LIST_UNLOCK(&zones);
03817 }
03818 ast_localtime(&t, tm, z ? z->timezone : NULL);
03819 return tm;
03820 }
03821
03822
03823
03824
03825
03826 static int check_mime(const char *str)
03827 {
03828 for (; *str; str++) {
03829 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03830 return 1;
03831 }
03832 }
03833 return 0;
03834 }
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03853 {
03854 char tmp[80];
03855 int first_section = 1;
03856 size_t endlen = 0, tmplen = 0;
03857 *end = '\0';
03858
03859 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03860 for (; *start; start++) {
03861 int need_encoding = 0;
03862 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03863 need_encoding = 1;
03864 }
03865 if ((first_section && need_encoding && preamble + tmplen > 70) ||
03866 (first_section && !need_encoding && preamble + tmplen > 72) ||
03867 (!first_section && need_encoding && tmplen > 70) ||
03868 (!first_section && !need_encoding && tmplen > 72)) {
03869
03870 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
03871 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03872 first_section = 0;
03873 }
03874 if (need_encoding && *start == ' ') {
03875 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
03876 } else if (need_encoding) {
03877 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
03878 } else {
03879 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
03880 }
03881 }
03882 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
03883 return end;
03884 }
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905
03906 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
03907 {
03908 char date[256];
03909 char host[MAXHOSTNAMELEN] = "";
03910 char who[256];
03911 char bound[256];
03912 char dur[256];
03913 struct ast_tm tm;
03914 char enc_cidnum[256] = "", enc_cidname[256] = "";
03915 char *passdata = NULL, *passdata2;
03916 size_t len_passdata = 0, len_passdata2, tmplen;
03917 char *greeting_attachment;
03918 char filename[256];
03919
03920 #ifdef IMAP_STORAGE
03921 #define ENDL "\r\n"
03922 #else
03923 #define ENDL "\n"
03924 #endif
03925
03926
03927 len_passdata2 = strlen(vmu->fullname);
03928 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
03929 len_passdata2 = tmplen;
03930 }
03931 if ((tmplen = strlen(fromstring)) > len_passdata2) {
03932 len_passdata2 = tmplen;
03933 }
03934 len_passdata2 = len_passdata2 * 3 + 200;
03935 passdata2 = alloca(len_passdata2);
03936
03937 if (cidnum) {
03938 strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
03939 }
03940 if (cidname) {
03941 strip_control(cidname, enc_cidname, sizeof(enc_cidname));
03942 }
03943 gethostname(host, sizeof(host) - 1);
03944
03945 if (strchr(srcemail, '@'))
03946 ast_copy_string(who, srcemail, sizeof(who));
03947 else
03948 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03949
03950 greeting_attachment = strrchr(ast_strdupa(attach), '/');
03951 if (greeting_attachment)
03952 *greeting_attachment++ = '\0';
03953
03954 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03955 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03956 fprintf(p, "Date: %s" ENDL, date);
03957
03958
03959 ast_strftime(date, sizeof(date), emaildateformat, &tm);
03960
03961 if (!ast_strlen_zero(fromstring)) {
03962 struct ast_channel *ast;
03963 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03964 char *ptr;
03965 memset(passdata2, 0, len_passdata2);
03966 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
03967 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
03968 len_passdata = strlen(passdata2) * 3 + 300;
03969 passdata = alloca(len_passdata);
03970 if (check_mime(passdata2)) {
03971 int first_line = 1;
03972 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
03973 while ((ptr = strchr(passdata, ' '))) {
03974 *ptr = '\0';
03975 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
03976 first_line = 0;
03977 passdata = ptr + 1;
03978 }
03979 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
03980 } else {
03981 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
03982 }
03983 ast_channel_free(ast);
03984 } else {
03985 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03986 }
03987 } else {
03988 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03989 }
03990
03991 if (check_mime(vmu->fullname)) {
03992 int first_line = 1;
03993 char *ptr;
03994 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
03995 while ((ptr = strchr(passdata2, ' '))) {
03996 *ptr = '\0';
03997 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
03998 first_line = 0;
03999 passdata2 = ptr + 1;
04000 }
04001 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
04002 } else {
04003 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
04004 }
04005 if (!ast_strlen_zero(emailsubject)) {
04006 struct ast_channel *ast;
04007 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04008 int vmlen = strlen(emailsubject) * 3 + 200;
04009
04010 if (vmlen > len_passdata) {
04011 passdata = alloca(vmlen);
04012 len_passdata = vmlen;
04013 }
04014
04015 memset(passdata, 0, len_passdata);
04016 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category, flag);
04017 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
04018 if (check_mime(passdata)) {
04019 int first_line = 1;
04020 char *ptr;
04021 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
04022 while ((ptr = strchr(passdata2, ' '))) {
04023 *ptr = '\0';
04024 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04025 first_line = 0;
04026 passdata2 = ptr + 1;
04027 }
04028 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04029 } else {
04030 fprintf(p, "Subject: %s" ENDL, passdata);
04031 }
04032 ast_channel_free(ast);
04033 } else {
04034 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04035 }
04036 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04037 if (ast_strlen_zero(flag)) {
04038 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04039 } else {
04040 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04041 }
04042 } else {
04043 if (ast_strlen_zero(flag)) {
04044 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04045 } else {
04046 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04047 }
04048 }
04049
04050 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
04051 if (imap) {
04052
04053 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04054
04055 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04056 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04057 #ifdef IMAP_STORAGE
04058 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04059 #else
04060 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04061 #endif
04062
04063 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04064 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04065 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04066 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04067 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04068 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04069 if (!ast_strlen_zero(category)) {
04070 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04071 } else {
04072 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04073 }
04074 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04075 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04076 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
04077 }
04078 if (!ast_strlen_zero(cidnum)) {
04079 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04080 }
04081 if (!ast_strlen_zero(cidname)) {
04082 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04083 }
04084 fprintf(p, "MIME-Version: 1.0" ENDL);
04085 if (attach_user_voicemail) {
04086
04087 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
04088
04089 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04090 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04091 fprintf(p, "--%s" ENDL, bound);
04092 }
04093 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04094 if (emailbody) {
04095 struct ast_channel *ast;
04096 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04097 char *passdata;
04098 int vmlen = strlen(emailbody)*3 + 200;
04099 passdata = alloca(vmlen);
04100 memset(passdata, 0, vmlen);
04101 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04102 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
04103 fprintf(p, "%s" ENDL, passdata);
04104 ast_channel_free(ast);
04105 } else
04106 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04107 } else if (msgnum > -1) {
04108 if (strcmp(vmu->mailbox, mailbox)) {
04109
04110 struct ast_config *msg_cfg;
04111 const char *v;
04112 int inttime;
04113 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04114 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04115
04116 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04117 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04118 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04119 strcat(fromfile, ".txt");
04120 }
04121 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04122 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04123 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04124 }
04125
04126
04127
04128 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%d", &inttime) == 1) {
04129 struct timeval tv = { inttime, };
04130 struct ast_tm tm;
04131 ast_localtime(&tv, &tm, NULL);
04132 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
04133 }
04134 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04135 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04136 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04137 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04138 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04139 date, origcallerid, origdate);
04140 ast_config_destroy(msg_cfg);
04141 } else {
04142 goto plain_message;
04143 }
04144 } else {
04145 plain_message:
04146 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04147 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04148 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04149 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04150 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04151 }
04152 } else {
04153 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04154 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04155 }
04156
04157 if (imap || attach_user_voicemail) {
04158 if (!ast_strlen_zero(attach2)) {
04159 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04160 ast_debug(5, "creating second attachment filename %s\n", filename);
04161 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04162 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04163 ast_debug(5, "creating attachment filename %s\n", filename);
04164 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04165 } else {
04166 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04167 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04168 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04169 }
04170 }
04171 }
04172
04173 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
04174 {
04175 char tmpdir[256], newtmp[256];
04176 char fname[256];
04177 char tmpcmd[256];
04178 int tmpfd = -1;
04179
04180
04181 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04182
04183 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04184 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04185 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04186 tmpfd = mkstemp(newtmp);
04187 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04188 ast_debug(3, "newtmp: %s\n", newtmp);
04189 if (tmpfd > -1) {
04190 int soxstatus;
04191 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04192 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04193 attach = newtmp;
04194 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04195 } else {
04196 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04197 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04198 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04199 }
04200 }
04201 }
04202 fprintf(p, "--%s" ENDL, bound);
04203 if (msgnum > -1)
04204 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04205 else
04206 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, attach, format);
04207 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04208 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04209 if (msgnum > -1)
04210 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04211 else
04212 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, attach, format);
04213 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04214 base_encode(fname, p);
04215 if (last)
04216 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04217 if (tmpfd > -1) {
04218 unlink(fname);
04219 close(tmpfd);
04220 unlink(newtmp);
04221 }
04222 return 0;
04223 }
04224 #undef ENDL
04225
04226 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04227 {
04228 FILE *p=NULL;
04229 char tmp[80] = "/tmp/astmail-XXXXXX";
04230 char tmp2[256];
04231
04232 if (vmu && ast_strlen_zero(vmu->email)) {
04233 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04234 return(0);
04235 }
04236 if (!strcmp(format, "wav49"))
04237 format = "WAV";
04238 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04239
04240
04241 if ((p = vm_mkftemp(tmp)) == NULL) {
04242 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04243 return -1;
04244 } else {
04245 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04246 fclose(p);
04247 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04248 ast_safe_system(tmp2);
04249 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04250 }
04251 return 0;
04252 }
04253
04254 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
04255 {
04256 char date[256];
04257 char host[MAXHOSTNAMELEN] = "";
04258 char who[256];
04259 char dur[PATH_MAX];
04260 char tmp[80] = "/tmp/astmail-XXXXXX";
04261 char tmp2[PATH_MAX];
04262 struct ast_tm tm;
04263 FILE *p;
04264
04265 if ((p = vm_mkftemp(tmp)) == NULL) {
04266 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04267 return -1;
04268 }
04269 gethostname(host, sizeof(host)-1);
04270 if (strchr(srcemail, '@'))
04271 ast_copy_string(who, srcemail, sizeof(who));
04272 else
04273 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04274 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04275 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04276 fprintf(p, "Date: %s\n", date);
04277
04278 if (*pagerfromstring) {
04279 struct ast_channel *ast;
04280 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04281 char *passdata;
04282 int vmlen = strlen(fromstring)*3 + 200;
04283 passdata = alloca(vmlen);
04284 memset(passdata, 0, vmlen);
04285 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04286 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
04287 fprintf(p, "From: %s <%s>\n", passdata, who);
04288 ast_channel_free(ast);
04289 } else
04290 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04291 } else
04292 fprintf(p, "From: Asterisk PBX <%s>\n", who);
04293 fprintf(p, "To: %s\n", pager);
04294 if (pagersubject) {
04295 struct ast_channel *ast;
04296 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04297 char *passdata;
04298 int vmlen = strlen(pagersubject) * 3 + 200;
04299 passdata = alloca(vmlen);
04300 memset(passdata, 0, vmlen);
04301 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04302 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
04303 fprintf(p, "Subject: %s\n\n", passdata);
04304 ast_channel_free(ast);
04305 } else
04306 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04307 } else {
04308 if (ast_strlen_zero(flag)) {
04309 fprintf(p, "Subject: New VM\n\n");
04310 } else {
04311 fprintf(p, "Subject: New %s VM\n\n", flag);
04312 }
04313 }
04314
04315 ast_strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
04316 if (pagerbody) {
04317 struct ast_channel *ast;
04318 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04319 char *passdata;
04320 int vmlen = strlen(pagerbody) * 3 + 200;
04321 passdata = alloca(vmlen);
04322 memset(passdata, 0, vmlen);
04323 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04324 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
04325 fprintf(p, "%s\n", passdata);
04326 ast_channel_free(ast);
04327 } else
04328 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04329 } else {
04330 fprintf(p, "New %s long %s msg in box %s\n"
04331 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04332 }
04333 fclose(p);
04334 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04335 ast_safe_system(tmp2);
04336 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04337 return 0;
04338 }
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349 static int get_date(char *s, int len)
04350 {
04351 struct ast_tm tm;
04352 struct timeval t = ast_tvnow();
04353
04354 ast_localtime(&t, &tm, "UTC");
04355
04356 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04357 }
04358
04359 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04360 {
04361 int res;
04362 char fn[PATH_MAX];
04363 char dest[PATH_MAX];
04364
04365 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04366
04367 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04368 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04369 return -1;
04370 }
04371
04372 RETRIEVE(fn, -1, ext, context);
04373 if (ast_fileexists(fn, NULL, NULL) > 0) {
04374 res = ast_stream_and_wait(chan, fn, ecodes);
04375 if (res) {
04376 DISPOSE(fn, -1);
04377 return res;
04378 }
04379 } else {
04380
04381 DISPOSE(fn, -1);
04382 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04383 if (res)
04384 return res;
04385 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04386 if (res)
04387 return res;
04388 }
04389 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04390 return res;
04391 }
04392
04393 static void free_zone(struct vm_zone *z)
04394 {
04395 ast_free(z);
04396 }
04397
04398 #ifdef ODBC_STORAGE
04399
04400 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04401 {
04402 int x = -1;
04403 int res;
04404 SQLHSTMT stmt;
04405 char sql[PATH_MAX];
04406 char rowdata[20];
04407 char tmp[PATH_MAX] = "";
04408 struct odbc_obj *obj;
04409 char *context;
04410 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04411
04412 if (newmsgs)
04413 *newmsgs = 0;
04414 if (oldmsgs)
04415 *oldmsgs = 0;
04416 if (urgentmsgs)
04417 *urgentmsgs = 0;
04418
04419
04420 if (ast_strlen_zero(mailbox))
04421 return 0;
04422
04423 ast_copy_string(tmp, mailbox, sizeof(tmp));
04424
04425 context = strchr(tmp, '@');
04426 if (context) {
04427 *context = '\0';
04428 context++;
04429 } else
04430 context = "default";
04431
04432 obj = ast_odbc_request_obj(odbc_database, 0);
04433 if (obj) {
04434 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
04435 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04436 if (!stmt) {
04437 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04438 ast_odbc_release_obj(obj);
04439 goto yuck;
04440 }
04441 res = SQLFetch(stmt);
04442 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04443 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04444 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04445 ast_odbc_release_obj(obj);
04446 goto yuck;
04447 }
04448 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04449 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04450 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04451 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04452 ast_odbc_release_obj(obj);
04453 goto yuck;
04454 }
04455 *newmsgs = atoi(rowdata);
04456 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04457
04458 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
04459 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04460 if (!stmt) {
04461 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04462 ast_odbc_release_obj(obj);
04463 goto yuck;
04464 }
04465 res = SQLFetch(stmt);
04466 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04467 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04468 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04469 ast_odbc_release_obj(obj);
04470 goto yuck;
04471 }
04472 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04473 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04474 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04475 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04476 ast_odbc_release_obj(obj);
04477 goto yuck;
04478 }
04479 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04480 *oldmsgs = atoi(rowdata);
04481
04482 if (!urgentmsgs) {
04483 x = 0;
04484 ast_odbc_release_obj(obj);
04485 goto yuck;
04486 }
04487
04488 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
04489 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04490 if (!stmt) {
04491 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04492 ast_odbc_release_obj(obj);
04493 goto yuck;
04494 }
04495 res = SQLFetch(stmt);
04496 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04497 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04498 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04499 ast_odbc_release_obj(obj);
04500 goto yuck;
04501 }
04502 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04503 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04504 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04505 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04506 ast_odbc_release_obj(obj);
04507 goto yuck;
04508 }
04509 *urgentmsgs = atoi(rowdata);
04510 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04511 ast_odbc_release_obj(obj);
04512 x = 0;
04513 } else
04514 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04515
04516 yuck:
04517 return x;
04518 }
04519
04520 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04521 {
04522 return inboxcount2(mailbox, NULL, newmsgs, oldmsgs);
04523 }
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534 static int messagecount(const char *context, const char *mailbox, const char *folder)
04535 {
04536 struct odbc_obj *obj = NULL;
04537 int nummsgs = 0;
04538 int res;
04539 SQLHSTMT stmt = NULL;
04540 char sql[PATH_MAX];
04541 char rowdata[20];
04542 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04543 if (!folder)
04544 folder = "INBOX";
04545
04546 if (ast_strlen_zero(mailbox))
04547 return 0;
04548
04549 obj = ast_odbc_request_obj(odbc_database, 0);
04550 if (obj) {
04551 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04552 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04553 if (!stmt) {
04554 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04555 goto yuck;
04556 }
04557 res = SQLFetch(stmt);
04558 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04559 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04560 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04561 goto yuck;
04562 }
04563 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04564 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04565 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04566 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04567 goto yuck;
04568 }
04569 nummsgs = atoi(rowdata);
04570 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04571 } else
04572 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04573
04574 yuck:
04575 if (obj)
04576 ast_odbc_release_obj(obj);
04577 return nummsgs;
04578 }
04579
04580
04581
04582
04583
04584
04585
04586
04587
04588 static int has_voicemail(const char *mailbox, const char *folder)
04589 {
04590 char tmp[256], *tmp2 = tmp, *box, *context;
04591 ast_copy_string(tmp, mailbox, sizeof(tmp));
04592 while ((context = box = strsep(&tmp2, ","))) {
04593 strsep(&context, "@");
04594 if (ast_strlen_zero(context))
04595 context = "default";
04596 if (messagecount(context, box, folder))
04597 return 1;
04598 }
04599 return 0;
04600 }
04601 #endif
04602 #ifndef IMAP_STORAGE
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616
04617
04618 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, const char *flag)
04619 {
04620 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04621 const char *frombox = mbox(imbox);
04622 int recipmsgnum;
04623
04624 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04625
04626 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
04627 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
04628 } else {
04629 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04630 }
04631
04632 if (!dir)
04633 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04634 else
04635 ast_copy_string(fromdir, dir, sizeof(fromdir));
04636
04637 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04638 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04639
04640 if (vm_lock_path(todir))
04641 return ERROR_LOCK_PATH;
04642
04643 recipmsgnum = last_message_index(recip, todir) + 1;
04644 if (recipmsgnum < recip->maxmsg) {
04645 make_file(topath, sizeof(topath), todir, recipmsgnum);
04646 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04647 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04648 } else {
04649
04650
04651
04652
04653
04654 copy_plain_file(frompath, topath);
04655 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
04656 vm_delete(topath);
04657 }
04658 } else {
04659 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04660 }
04661 ast_unlock_path(todir);
04662 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
04663
04664 return 0;
04665 }
04666 #endif
04667 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04668
04669 static int messagecount(const char *context, const char *mailbox, const char *folder)
04670 {
04671 return __has_voicemail(context, mailbox, folder, 0);
04672 }
04673
04674 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04675 {
04676 DIR *dir;
04677 struct dirent *de;
04678 char fn[256];
04679 int ret = 0;
04680
04681
04682 if (ast_strlen_zero(mailbox))
04683 return 0;
04684
04685 if (ast_strlen_zero(folder))
04686 folder = "INBOX";
04687 if (ast_strlen_zero(context))
04688 context = "default";
04689
04690 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04691
04692 if (!(dir = opendir(fn)))
04693 return 0;
04694
04695 while ((de = readdir(dir))) {
04696 if (!strncasecmp(de->d_name, "msg", 3)) {
04697 if (shortcircuit) {
04698 ret = 1;
04699 break;
04700 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
04701 if (shortcircuit) return 1;
04702 ret++;
04703 }
04704 }
04705 }
04706
04707 closedir(dir);
04708
04709
04710 if (strcmp(folder, "INBOX") == 0) {
04711 return (ret + __has_voicemail(context, mailbox, "Urgent", shortcircuit));
04712 } else {
04713 return ret;
04714 }
04715 }
04716
04717
04718
04719
04720
04721
04722
04723
04724
04725
04726 static int has_voicemail(const char *mailbox, const char *folder)
04727 {
04728 char tmp[256], *tmp2 = tmp, *box, *context;
04729 ast_copy_string(tmp, mailbox, sizeof(tmp));
04730 while ((box = strsep(&tmp2, ","))) {
04731 if ((context = strchr(box, '@')))
04732 *context++ = '\0';
04733 else
04734 context = "default";
04735 if (__has_voicemail(context, box, folder, 1))
04736 return 1;
04737 }
04738 return 0;
04739 }
04740
04741
04742 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04743 {
04744 char tmp[256];
04745 char *context;
04746
04747
04748 if (ast_strlen_zero(mailbox))
04749 return 0;
04750
04751 if (newmsgs)
04752 *newmsgs = 0;
04753 if (oldmsgs)
04754 *oldmsgs = 0;
04755 if (urgentmsgs)
04756 *urgentmsgs = 0;
04757
04758 if (strchr(mailbox, ',')) {
04759 int tmpnew, tmpold, tmpurgent;
04760 char *mb, *cur;
04761
04762 ast_copy_string(tmp, mailbox, sizeof(tmp));
04763 mb = tmp;
04764 while ((cur = strsep(&mb, ", "))) {
04765 if (!ast_strlen_zero(cur)) {
04766 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04767 return -1;
04768 else {
04769 if (newmsgs)
04770 *newmsgs += tmpnew;
04771 if (oldmsgs)
04772 *oldmsgs += tmpold;
04773 if (urgentmsgs)
04774 *urgentmsgs += tmpurgent;
04775 }
04776 }
04777 }
04778 return 0;
04779 }
04780
04781 ast_copy_string(tmp, mailbox, sizeof(tmp));
04782
04783 if ((context = strchr(tmp, '@')))
04784 *context++ = '\0';
04785 else
04786 context = "default";
04787
04788 if (newmsgs)
04789 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04790 if (oldmsgs)
04791 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04792 if (urgentmsgs)
04793 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
04794
04795 return 0;
04796 }
04797
04798 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04799 {
04800 return inboxcount2(mailbox, NULL, newmsgs, oldmsgs);
04801 }
04802
04803 #endif
04804
04805 static void run_externnotify(char *context, char *extension, const char *flag)
04806 {
04807 char arguments[255];
04808 char ext_context[256] = "";
04809 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
04810 struct ast_smdi_mwi_message *mwi_msg;
04811
04812 if (!ast_strlen_zero(context))
04813 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04814 else
04815 ast_copy_string(ext_context, extension, sizeof(ext_context));
04816
04817 if (smdi_iface) {
04818 if (ast_app_has_voicemail(ext_context, NULL))
04819 ast_smdi_mwi_set(smdi_iface, extension);
04820 else
04821 ast_smdi_mwi_unset(smdi_iface, extension);
04822
04823 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04824 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04825 if (!strncmp(mwi_msg->cause, "INV", 3))
04826 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04827 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04828 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04829 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04830 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04831 } else {
04832 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
04833 }
04834 }
04835
04836 if (!ast_strlen_zero(externnotify)) {
04837 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
04838 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04839 } else {
04840 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
04841 ast_debug(1, "Executing %s\n", arguments);
04842 ast_safe_system(arguments);
04843 }
04844 }
04845 }
04846
04847
04848
04849
04850
04851
04852 struct leave_vm_options {
04853 unsigned int flags;
04854 signed char record_gain;
04855 char *exitcontext;
04856 };
04857
04858
04859
04860
04861
04862
04863
04864
04865
04866
04867
04868 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
04869 {
04870 #ifdef IMAP_STORAGE
04871 int newmsgs, oldmsgs;
04872 #else
04873 char urgdir[PATH_MAX];
04874 #endif
04875 char txtfile[PATH_MAX];
04876 char tmptxtfile[PATH_MAX];
04877 struct vm_state *vms = NULL;
04878 char callerid[256];
04879 FILE *txt;
04880 char date[256];
04881 int txtdes;
04882 int res = 0;
04883 int msgnum;
04884 int duration = 0;
04885 int ausemacro = 0;
04886 int ousemacro = 0;
04887 int ouseexten = 0;
04888 int rtmsgid = 0;
04889 char tmpid[16];
04890 char tmpdur[16];
04891 char priority[16];
04892 char origtime[16];
04893 char dir[PATH_MAX];
04894 char tmpdir[PATH_MAX];
04895 char fn[PATH_MAX];
04896 char prefile[PATH_MAX] = "";
04897 char tempfile[PATH_MAX] = "";
04898 char ext_context[256] = "";
04899 char fmt[80];
04900 char *context;
04901 char ecodes[17] = "#";
04902 char tmp[1024] = "";
04903 char *tmpptr;
04904 struct ast_vm_user *vmu;
04905 struct ast_vm_user svm;
04906 const char *category = NULL;
04907 const char *code;
04908 const char *alldtmf = "0123456789ABCD*#";
04909 char flag[80];
04910
04911 ast_copy_string(tmp, ext, sizeof(tmp));
04912 ext = tmp;
04913 if ((context = strchr(tmp, '@'))) {
04914 *context++ = '\0';
04915 tmpptr = strchr(context, '&');
04916 } else {
04917 tmpptr = strchr(ext, '&');
04918 }
04919
04920 if (tmpptr)
04921 *tmpptr++ = '\0';
04922
04923 ast_channel_lock(chan);
04924 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
04925 category = ast_strdupa(category);
04926 }
04927 ast_channel_unlock(chan);
04928
04929 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
04930 ast_copy_string(flag, "Urgent", sizeof(flag));
04931 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
04932 ast_copy_string(flag, "PRIORITY", sizeof(flag));
04933 } else {
04934 flag[0] = '\0';
04935 }
04936
04937 ast_debug(3, "Before find_user\n");
04938 if (!(vmu = find_user(&svm, context, ext))) {
04939 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
04940 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04941 return res;
04942 }
04943
04944 if (strcmp(vmu->context, "default"))
04945 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
04946 else
04947 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
04948
04949
04950
04951
04952
04953
04954 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
04955 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
04956 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
04957 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
04958 }
04959
04960
04961
04962
04963 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
04964 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
04965 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
04966 return -1;
04967 }
04968 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
04969 if (ast_fileexists(tempfile, NULL, NULL) > 0)
04970 ast_copy_string(prefile, tempfile, sizeof(prefile));
04971
04972 DISPOSE(tempfile, -1);
04973
04974 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
04975
04976
04977 if (ast_test_flag(vmu, VM_OPERATOR)) {
04978 if (!ast_strlen_zero(vmu->exit)) {
04979 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
04980 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04981 ouseexten = 1;
04982 }
04983 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
04984 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04985 ouseexten = 1;
04986 } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
04987 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04988 ousemacro = 1;
04989 }
04990 }
04991
04992 if (!ast_strlen_zero(vmu->exit)) {
04993 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
04994 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04995 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
04996 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04997 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
04998 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04999 ausemacro = 1;
05000 }
05001
05002 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05003 for (code = alldtmf; *code; code++) {
05004 char e[2] = "";
05005 e[0] = *code;
05006 if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num))
05007 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05008 }
05009 }
05010
05011
05012 if (!ast_strlen_zero(prefile)) {
05013 #ifdef ODBC_STORAGE
05014 int success =
05015 #endif
05016 RETRIEVE(prefile, -1, ext, context);
05017 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05018 if (ast_streamfile(chan, prefile, chan->language) > -1)
05019 res = ast_waitstream(chan, ecodes);
05020 #ifdef ODBC_STORAGE
05021 if (success == -1) {
05022
05023 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05024 store_file(prefile, vmu->mailbox, vmu->context, -1);
05025 }
05026 #endif
05027 } else {
05028 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05029 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05030 }
05031 DISPOSE(prefile, -1);
05032 if (res < 0) {
05033 ast_debug(1, "Hang up during prefile playback\n");
05034 free_user(vmu);
05035 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05036 return -1;
05037 }
05038 }
05039 if (res == '#') {
05040
05041 ast_set_flag(options, OPT_SILENT);
05042 res = 0;
05043 }
05044 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05045 res = ast_stream_and_wait(chan, INTRO, ecodes);
05046 if (res == '#') {
05047 ast_set_flag(options, OPT_SILENT);
05048 res = 0;
05049 }
05050 }
05051 if (res > 0)
05052 ast_stopstream(chan);
05053
05054
05055 if (res == '*') {
05056 chan->exten[0] = 'a';
05057 chan->exten[1] = '\0';
05058 if (!ast_strlen_zero(vmu->exit)) {
05059 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05060 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05061 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05062 }
05063 chan->priority = 0;
05064 free_user(vmu);
05065 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05066 return 0;
05067 }
05068
05069
05070 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05071 transfer:
05072 if (ouseexten || ousemacro) {
05073 chan->exten[0] = 'o';
05074 chan->exten[1] = '\0';
05075 if (!ast_strlen_zero(vmu->exit)) {
05076 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05077 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05078 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05079 }
05080 ast_play_and_wait(chan, "transfer");
05081 chan->priority = 0;
05082 free_user(vmu);
05083 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05084 }
05085 return 0;
05086 }
05087
05088
05089 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05090 if (!ast_strlen_zero(options->exitcontext))
05091 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05092 free_user(vmu);
05093 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05094 return res;
05095 }
05096
05097 if (res < 0) {
05098 free_user(vmu);
05099 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05100 return -1;
05101 }
05102
05103 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05104 if (!ast_strlen_zero(fmt)) {
05105 msgnum = 0;
05106
05107 #ifdef IMAP_STORAGE
05108
05109
05110 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05111 if (res < 0) {
05112 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05113 return -1;
05114 }
05115 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05116
05117
05118
05119
05120 if (!(vms = create_vm_state_from_user(vmu))) {
05121 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05122 return -1;
05123 }
05124 }
05125 vms->newmessages++;
05126
05127
05128 msgnum = newmsgs + oldmsgs;
05129 ast_debug(3, "Messagecount set to %d\n",msgnum);
05130 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05131
05132 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05133
05134
05135 check_quota(vms, imapfolder);
05136 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
05137 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
05138 ast_play_and_wait(chan, "vm-mailboxfull");
05139 return -1;
05140 }
05141
05142
05143 if (msgnum >= vmu->maxmsg) {
05144 ast_log(AST_LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
05145 ast_play_and_wait(chan, "vm-mailboxfull");
05146 return -1;
05147 }
05148 #else
05149 if (count_messages(vmu, dir) >= vmu->maxmsg) {
05150 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05151 if (!res)
05152 res = ast_waitstream(chan, "");
05153 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05154 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05155 goto leave_vm_out;
05156 }
05157
05158 #endif
05159 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05160 txtdes = mkstemp(tmptxtfile);
05161 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05162 if (txtdes < 0) {
05163 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05164 if (!res)
05165 res = ast_waitstream(chan, "");
05166 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05167 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05168 goto leave_vm_out;
05169 }
05170
05171
05172 if (res >= 0) {
05173
05174 res = ast_stream_and_wait(chan, "beep", "");
05175 }
05176
05177
05178 if (ast_check_realtime("voicemail_data")) {
05179 snprintf(priority, sizeof(priority), "%d", chan->priority);
05180 snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL));
05181 get_date(date, sizeof(date));
05182 rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category,""), SENTINEL);
05183 }
05184
05185
05186 txt = fdopen(txtdes, "w+");
05187 if (txt) {
05188 get_date(date, sizeof(date));
05189 fprintf(txt,
05190 ";\n"
05191 "; Message Information file\n"
05192 ";\n"
05193 "[message]\n"
05194 "origmailbox=%s\n"
05195 "context=%s\n"
05196 "macrocontext=%s\n"
05197 "exten=%s\n"
05198 "priority=%d\n"
05199 "callerchan=%s\n"
05200 "callerid=%s\n"
05201 "origdate=%s\n"
05202 "origtime=%ld\n"
05203 "category=%s\n",
05204 ext,
05205 chan->context,
05206 chan->macrocontext,
05207 chan->exten,
05208 chan->priority,
05209 chan->name,
05210 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
05211 date, (long)time(NULL),
05212 category ? category : "");
05213 } else
05214 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05215 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05216
05217 if (txt) {
05218 fprintf(txt, "flag=%s\n", flag);
05219 if (duration < vmminsecs) {
05220 fclose(txt);
05221 if (option_verbose > 2)
05222 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
05223 ast_filedelete(tmptxtfile, NULL);
05224 unlink(tmptxtfile);
05225 if (ast_check_realtime("voicemail_data")) {
05226 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05227 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05228 }
05229 } else {
05230 fprintf(txt, "duration=%d\n", duration);
05231 fclose(txt);
05232 if (vm_lock_path(dir)) {
05233 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05234
05235 ast_filedelete(tmptxtfile, NULL);
05236 unlink(tmptxtfile);
05237 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05238 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05239 unlink(tmptxtfile);
05240 ast_unlock_path(dir);
05241 if (ast_check_realtime("voicemail_data")) {
05242 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05243 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05244 }
05245 } else {
05246 #ifndef IMAP_STORAGE
05247 msgnum = last_message_index(vmu, dir) + 1;
05248 #endif
05249 make_file(fn, sizeof(fn), dir, msgnum);
05250
05251
05252 #ifndef IMAP_STORAGE
05253 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05254 #else
05255 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05256 #endif
05257
05258 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05259 ast_filerename(tmptxtfile, fn, NULL);
05260 rename(tmptxtfile, txtfile);
05261
05262
05263
05264 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05265 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05266
05267 ast_unlock_path(dir);
05268 if (ast_check_realtime("voicemail_data")) {
05269 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05270 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05271 ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, SENTINEL);
05272 }
05273
05274
05275
05276 if (ast_fileexists(fn, NULL, NULL) > 0) {
05277 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05278 }
05279
05280
05281 while (tmpptr) {
05282 struct ast_vm_user recipu, *recip;
05283 char *exten, *cntx;
05284
05285 exten = strsep(&tmpptr, "&");
05286 cntx = strchr(exten, '@');
05287 if (cntx) {
05288 *cntx = '\0';
05289 cntx++;
05290 }
05291 if ((recip = find_user(&recipu, cntx, exten))) {
05292 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05293 free_user(recip);
05294 }
05295 }
05296 #ifndef IMAP_STORAGE
05297 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05298
05299 char sfn[PATH_MAX];
05300 char dfn[PATH_MAX];
05301 int x;
05302
05303 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05304 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n",sfn,dfn);
05305 x = last_message_index(vmu, urgdir) + 1;
05306 make_file(sfn, sizeof(sfn), dir, msgnum);
05307 make_file(dfn, sizeof(dfn), urgdir, x);
05308 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05309 }
05310 #endif
05311
05312 if (ast_fileexists(fn, NULL, NULL)) {
05313 #ifdef IMAP_STORAGE
05314 notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05315 #else
05316 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05317 #endif
05318 }
05319
05320
05321 if (ast_fileexists(fn, NULL, NULL)) {
05322 DISPOSE(dir, msgnum);
05323 }
05324 }
05325 }
05326 }
05327 if (res == '0') {
05328 goto transfer;
05329 } else if (res > 0)
05330 res = 0;
05331
05332 if (duration < vmminsecs)
05333
05334 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05335 else
05336 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05337 } else
05338 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05339 leave_vm_out:
05340 free_user(vmu);
05341
05342 #ifdef IMAP_STORAGE
05343
05344 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n",expungeonhangup);
05345 if (expungeonhangup == 1) {
05346 ast_mutex_lock(&vms->lock);
05347 #ifdef HAVE_IMAP_TK2006
05348 if (LEVELUIDPLUS (vms->mailstream)) {
05349 mail_expunge_full(vms->mailstream,NIL,EX_UID);
05350 } else
05351 #endif
05352 mail_expunge(vms->mailstream);
05353 ast_mutex_unlock(&vms->lock);
05354 }
05355 #endif
05356
05357 return res;
05358 }
05359
05360 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
05361 {
05362 int d;
05363 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
05364 return d;
05365 }
05366
05367 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
05368 {
05369 #ifdef IMAP_STORAGE
05370
05371
05372 char sequence[10];
05373 char mailbox[256];
05374 int res;
05375
05376
05377 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
05378
05379 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box));
05380 ast_mutex_lock(&vms->lock);
05381
05382 if (box == OLD_FOLDER) {
05383 mail_setflag(vms->mailstream, sequence, "\\Seen");
05384 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
05385 } else if (box == NEW_FOLDER) {
05386 mail_setflag(vms->mailstream, sequence, "\\Unseen");
05387 mail_clearflag(vms->mailstream, sequence, "\\Seen");
05388 }
05389 if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
05390 ast_mutex_unlock(&vms->lock);
05391 return 0;
05392 }
05393
05394 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
05395 ast_debug(5, "Checking if folder exists: %s\n",mailbox);
05396 if (mail_create(vms->mailstream, mailbox) == NIL)
05397 ast_debug(5, "Folder exists.\n");
05398 else
05399 ast_log(AST_LOG_NOTICE, "Folder %s created!\n",mbox(box));
05400 res = !mail_copy(vms->mailstream, sequence, (char *)mbox(box));
05401 ast_mutex_unlock(&vms->lock);
05402 return res;
05403 #else
05404 char *dir = vms->curdir;
05405 char *username = vms->username;
05406 char *context = vmu->context;
05407 char sfn[PATH_MAX];
05408 char dfn[PATH_MAX];
05409 char ddir[PATH_MAX];
05410 const char *dbox = mbox(box);
05411 int x, i;
05412 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
05413
05414 if (vm_lock_path(ddir))
05415 return ERROR_LOCK_PATH;
05416
05417 x = last_message_index(vmu, ddir) + 1;
05418
05419 if (box == 10 && x >= vmu->maxdeletedmsg) {
05420 x--;
05421 for (i = 1; i <= x; i++) {
05422
05423 make_file(sfn, sizeof(sfn), ddir, i);
05424 make_file(dfn, sizeof(dfn), ddir, i - 1);
05425 if (EXISTS(ddir, i, sfn, NULL)) {
05426 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
05427 } else
05428 break;
05429 }
05430 } else {
05431 if (x >= vmu->maxmsg) {
05432 ast_unlock_path(ddir);
05433 return -1;
05434 }
05435 }
05436 make_file(sfn, sizeof(sfn), dir, msg);
05437 make_file(dfn, sizeof(dfn), ddir, x);
05438 if (strcmp(sfn, dfn)) {
05439 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
05440 }
05441 ast_unlock_path(ddir);
05442 #endif
05443 return 0;
05444 }
05445
05446 static int adsi_logo(unsigned char *buf)
05447 {
05448 int bytes = 0;
05449 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
05450 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
05451 return bytes;
05452 }
05453
05454 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
05455 {
05456 unsigned char buf[256];
05457 int bytes=0;
05458 int x;
05459 char num[5];
05460
05461 *useadsi = 0;
05462 bytes += ast_adsi_data_mode(buf + bytes);
05463 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05464
05465 bytes = 0;
05466 bytes += adsi_logo(buf);
05467 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05468 #ifdef DISPLAY
05469 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
05470 #endif
05471 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05472 bytes += ast_adsi_data_mode(buf + bytes);
05473 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05474
05475 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
05476 bytes = 0;
05477 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
05478 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05479 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05480 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05481 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05482 return 0;
05483 }
05484
05485 #ifdef DISPLAY
05486
05487 bytes = 0;
05488 bytes += ast_adsi_logo(buf);
05489 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05490 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
05491 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05492 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05493 #endif
05494 bytes = 0;
05495 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
05496 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
05497 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
05498 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
05499 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
05500 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
05501 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05502
05503 #ifdef DISPLAY
05504
05505 bytes = 0;
05506 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
05507 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05508
05509 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05510 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05511 #endif
05512
05513 bytes = 0;
05514
05515 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
05516 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
05517 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
05518 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
05519 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
05520 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
05521 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05522
05523 #ifdef DISPLAY
05524
05525 bytes = 0;
05526 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
05527 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05528 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05529 #endif
05530
05531 bytes = 0;
05532 for (x=0;x<5;x++) {
05533 snprintf(num, sizeof(num), "%d", x);
05534 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
05535 }
05536 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
05537 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05538
05539 #ifdef DISPLAY
05540
05541 bytes = 0;
05542 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
05543 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05544 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05545 #endif
05546
05547 if (ast_adsi_end_download(chan)) {
05548 bytes = 0;
05549 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
05550 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05551 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05552 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05553 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05554 return 0;
05555 }
05556 bytes = 0;
05557 bytes += ast_adsi_download_disconnect(buf + bytes);
05558 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05559 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05560
05561 ast_debug(1, "Done downloading scripts...\n");
05562
05563 #ifdef DISPLAY
05564
05565 bytes = 0;
05566 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
05567 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05568 #endif
05569 ast_debug(1, "Restarting session...\n");
05570
05571 bytes = 0;
05572
05573 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
05574 *useadsi = 1;
05575 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
05576 } else
05577 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
05578
05579 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05580 return 0;
05581 }
05582
05583 static void adsi_begin(struct ast_channel *chan, int *useadsi)
05584 {
05585 int x;
05586 if (!ast_adsi_available(chan))
05587 return;
05588 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
05589 if (x < 0)
05590 return;
05591 if (!x) {
05592 if (adsi_load_vmail(chan, useadsi)) {
05593 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
05594 return;
05595 }
05596 } else
05597 *useadsi = 1;
05598 }
05599
05600 static void adsi_login(struct ast_channel *chan)
05601 {
05602 unsigned char buf[256];
05603 int bytes=0;
05604 unsigned char keys[8];
05605 int x;
05606 if (!ast_adsi_available(chan))
05607 return;
05608
05609 for (x=0;x<8;x++)
05610 keys[x] = 0;
05611
05612 keys[3] = ADSI_KEY_APPS + 3;
05613
05614 bytes += adsi_logo(buf + bytes);
05615 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
05616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
05617 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05618 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
05619 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
05620 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
05621 bytes += ast_adsi_set_keys(buf + bytes, keys);
05622 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05623 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05624 }
05625
05626 static void adsi_password(struct ast_channel *chan)
05627 {
05628 unsigned char buf[256];
05629 int bytes=0;
05630 unsigned char keys[8];
05631 int x;
05632 if (!ast_adsi_available(chan))
05633 return;
05634
05635 for (x=0;x<8;x++)
05636 keys[x] = 0;
05637
05638 keys[3] = ADSI_KEY_APPS + 3;
05639
05640 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05641 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
05642 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
05643 bytes += ast_adsi_set_keys(buf + bytes, keys);
05644 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05645 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05646 }
05647
05648 static void adsi_folders(struct ast_channel *chan, int start, char *label)
05649 {
05650 unsigned char buf[256];
05651 int bytes=0;
05652 unsigned char keys[8];
05653 int x,y;
05654
05655 if (!ast_adsi_available(chan))
05656 return;
05657
05658 for (x=0;x<5;x++) {
05659 y = ADSI_KEY_APPS + 12 + start + x;
05660 if (y > ADSI_KEY_APPS + 12 + 4)
05661 y = 0;
05662 keys[x] = ADSI_KEY_SKT | y;
05663 }
05664 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
05665 keys[6] = 0;
05666 keys[7] = 0;
05667
05668 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
05669 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
05670 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05671 bytes += ast_adsi_set_keys(buf + bytes, keys);
05672 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05673
05674 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05675 }
05676
05677 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
05678 {
05679 int bytes=0;
05680 unsigned char buf[256];
05681 char buf1[256], buf2[256];
05682 char fn2[PATH_MAX];
05683
05684 char cid[256]="";
05685 char *val;
05686 char *name, *num;
05687 char datetime[21]="";
05688 FILE *f;
05689
05690 unsigned char keys[8];
05691
05692 int x;
05693
05694 if (!ast_adsi_available(chan))
05695 return;
05696
05697
05698 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
05699 f = fopen(fn2, "r");
05700 if (f) {
05701 while (!feof(f)) {
05702 if (!fgets((char *)buf, sizeof(buf), f)) {
05703 continue;
05704 }
05705 if (!feof(f)) {
05706 char *stringp=NULL;
05707 stringp = (char *)buf;
05708 strsep(&stringp, "=");
05709 val = strsep(&stringp, "=");
05710 if (!ast_strlen_zero(val)) {
05711 if (!strcmp((char *)buf, "callerid"))
05712 ast_copy_string(cid, val, sizeof(cid));
05713 if (!strcmp((char *)buf, "origdate"))
05714 ast_copy_string(datetime, val, sizeof(datetime));
05715 }
05716 }
05717 }
05718 fclose(f);
05719 }
05720
05721 for (x=0;x<5;x++)
05722 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05723 keys[6] = 0x0;
05724 keys[7] = 0x0;
05725
05726 if (!vms->curmsg) {
05727
05728 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05729 }
05730 if (vms->curmsg >= vms->lastmsg) {
05731
05732 if (vms->curmsg) {
05733
05734 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05735 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05736
05737 } else {
05738
05739 keys[3] = 1;
05740 }
05741 }
05742
05743 if (!ast_strlen_zero(cid)) {
05744 ast_callerid_parse(cid, &name, &num);
05745 if (!name)
05746 name = num;
05747 } else
05748 name = "Unknown Caller";
05749
05750
05751
05752 if (vms->deleted[vms->curmsg])
05753 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05754
05755
05756 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05757 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05758 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05759 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05760
05761 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05762 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05763 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05764 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05765 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05766 bytes += ast_adsi_set_keys(buf + bytes, keys);
05767 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05768
05769 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05770 }
05771
05772 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05773 {
05774 int bytes=0;
05775 unsigned char buf[256];
05776 unsigned char keys[8];
05777
05778 int x;
05779
05780 if (!ast_adsi_available(chan))
05781 return;
05782
05783
05784 for (x=0;x<5;x++)
05785 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05786
05787 keys[6] = 0x0;
05788 keys[7] = 0x0;
05789
05790 if (!vms->curmsg) {
05791
05792 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05793 }
05794 if (vms->curmsg >= vms->lastmsg) {
05795
05796 if (vms->curmsg) {
05797
05798 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05799 } else {
05800
05801 keys[3] = 1;
05802 }
05803 }
05804
05805
05806 if (vms->deleted[vms->curmsg])
05807 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05808
05809
05810 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05811 bytes += ast_adsi_set_keys(buf + bytes, keys);
05812 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05813
05814 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05815 }
05816
05817 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05818 {
05819 unsigned char buf[256] = "";
05820 char buf1[256] = "", buf2[256] = "";
05821 int bytes=0;
05822 unsigned char keys[8];
05823 int x;
05824
05825 char *newm = (vms->newmessages == 1) ? "message" : "messages";
05826 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
05827 if (!ast_adsi_available(chan))
05828 return;
05829 if (vms->newmessages) {
05830 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
05831 if (vms->oldmessages) {
05832 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
05833 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
05834 } else {
05835 snprintf(buf2, sizeof(buf2), "%s.", newm);
05836 }
05837 } else if (vms->oldmessages) {
05838 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
05839 snprintf(buf2, sizeof(buf2), "%s.", oldm);
05840 } else {
05841 strcpy(buf1, "You have no messages.");
05842 buf2[0] = ' ';
05843 buf2[1] = '\0';
05844 }
05845 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05846 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05847 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05848
05849 for (x=0;x<6;x++)
05850 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05851 keys[6] = 0;
05852 keys[7] = 0;
05853
05854
05855 if (vms->lastmsg < 0)
05856 keys[0] = 1;
05857 bytes += ast_adsi_set_keys(buf + bytes, keys);
05858
05859 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05860
05861 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05862 }
05863
05864 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
05865 {
05866 unsigned char buf[256] = "";
05867 char buf1[256] = "", buf2[256] = "";
05868 int bytes=0;
05869 unsigned char keys[8];
05870 int x;
05871
05872 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
05873
05874 if (!ast_adsi_available(chan))
05875 return;
05876
05877
05878 for (x=0;x<6;x++)
05879 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05880
05881 keys[6] = 0;
05882 keys[7] = 0;
05883
05884 if ((vms->lastmsg + 1) < 1)
05885 keys[0] = 0;
05886
05887 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
05888 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
05889
05890 if (vms->lastmsg + 1)
05891 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
05892 else
05893 strcpy(buf2, "no messages.");
05894 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05895 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05896 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
05897 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05898 bytes += ast_adsi_set_keys(buf + bytes, keys);
05899
05900 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05901
05902 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05903
05904 }
05905
05906
05907
05908
05909
05910
05911
05912
05913
05914
05915
05916
05917
05918
05919
05920 static void adsi_goodbye(struct ast_channel *chan)
05921 {
05922 unsigned char buf[256];
05923 int bytes=0;
05924
05925 if (!ast_adsi_available(chan))
05926 return;
05927 bytes += adsi_logo(buf + bytes);
05928 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
05929 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
05930 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05931 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05932
05933 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05934 }
05935
05936
05937
05938
05939
05940 static int get_folder(struct ast_channel *chan, int start)
05941 {
05942 int x;
05943 int d;
05944 char fn[PATH_MAX];
05945 d = ast_play_and_wait(chan, "vm-press");
05946 if (d)
05947 return d;
05948 for (x = start; x< 5; x++) {
05949 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
05950 return d;
05951 d = ast_play_and_wait(chan, "vm-for");
05952 if (d)
05953 return d;
05954 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
05955 d = vm_play_folder_name(chan, fn);
05956 if (d)
05957 return d;
05958 d = ast_waitfordigit(chan, 500);
05959 if (d)
05960 return d;
05961 }
05962 d = ast_play_and_wait(chan, "vm-tocancel");
05963 if (d)
05964 return d;
05965 d = ast_waitfordigit(chan, 4000);
05966 return d;
05967 }
05968
05969
05970
05971
05972
05973
05974
05975
05976
05977
05978
05979
05980
05981 static int get_folder2(struct ast_channel *chan, char *fn, int start)
05982 {
05983 int res = 0;
05984 res = ast_play_and_wait(chan, fn);
05985 while (((res < '0') || (res > '9')) &&
05986 (res != '#') && (res >= 0)) {
05987 res = get_folder(chan, 0);
05988 }
05989 return res;
05990 }
05991
05992
05993
05994
05995
05996
05997
05998
05999
06000
06001
06002
06003
06004
06005
06006
06007
06008
06009 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06010 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06011 {
06012 #ifdef IMAP_STORAGE
06013 int res;
06014 #endif
06015 int cmd = 0;
06016 int retries = 0, prepend_duration = 0, already_recorded = 0;
06017 char msgfile[PATH_MAX], backup[PATH_MAX];
06018 char textfile[PATH_MAX];
06019 struct ast_config *msg_cfg;
06020 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06021 #ifndef IMAP_STORAGE
06022 signed char zero_gain = 0;
06023 #endif
06024 const char *duration_str;
06025
06026
06027 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06028 strcpy(textfile, msgfile);
06029 strcpy(backup, msgfile);
06030 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06031 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06032
06033 if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06034 *duration = atoi(duration_str);
06035 } else {
06036 *duration = 0;
06037 }
06038
06039 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06040 if (cmd)
06041 retries = 0;
06042 switch (cmd) {
06043 case '1':
06044
06045 #ifdef IMAP_STORAGE
06046
06047 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06048 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06049 res = ast_play_and_wait(chan, INTRO);
06050 res = ast_play_and_wait(chan, "beep");
06051 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *)duration, NULL, record_gain, vms, flag);
06052 cmd = 't';
06053 #else
06054
06055
06056
06057 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06058 strcpy(textfile, msgfile);
06059 strncat(textfile, ".txt", sizeof(textfile) - 1);
06060 *duration = 0;
06061
06062
06063 if (!msg_cfg) {
06064 cmd = 0;
06065 break;
06066 }
06067
06068
06069 if (already_recorded)
06070 ast_filecopy(backup, msgfile, NULL);
06071 else
06072 ast_filecopy(msgfile, backup, NULL);
06073 already_recorded = 1;
06074
06075 if (record_gain)
06076 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06077
06078 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06079 if (record_gain)
06080 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06081
06082
06083 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06084 *duration = atoi(duration_str);
06085
06086 if (prepend_duration) {
06087 struct ast_category *msg_cat;
06088
06089 char duration_buf[12];
06090
06091 *duration += prepend_duration;
06092 msg_cat = ast_category_get(msg_cfg, "message");
06093 snprintf(duration_buf, 11, "%ld", *duration);
06094 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06095 config_text_file_save(textfile, msg_cfg, "app_voicemail");
06096 }
06097 }
06098
06099 #endif
06100 break;
06101 case '2':
06102
06103 #ifdef IMAP_STORAGE
06104 *vms->introfn = '\0';
06105 #endif
06106 cmd = 't';
06107 break;
06108 case '*':
06109 cmd = '*';
06110 break;
06111 default:
06112 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
06113
06114 if (!cmd)
06115 cmd = ast_play_and_wait(chan,"vm-starmain");
06116
06117 if (!cmd)
06118 cmd = ast_waitfordigit(chan,6000);
06119 if (!cmd)
06120 retries++;
06121 if (retries > 3)
06122 cmd = 't';
06123 }
06124 }
06125
06126 if (msg_cfg)
06127 ast_config_destroy(msg_cfg);
06128 if (already_recorded)
06129 ast_filedelete(backup, NULL);
06130 if (prepend_duration)
06131 *duration = prepend_duration;
06132
06133 if (cmd == 't' || cmd == 'S')
06134 cmd = 0;
06135 return cmd;
06136 }
06137
06138 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06139 {
06140 struct ast_event *event;
06141 char *mailbox, *context;
06142
06143
06144 context = mailbox = ast_strdupa(box);
06145 strsep(&context, "@");
06146 if (ast_strlen_zero(context))
06147 context = "default";
06148
06149 if (!(event = ast_event_new(AST_EVENT_MWI,
06150 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06151 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06152 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06153 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06154 AST_EVENT_IE_END))) {
06155 return;
06156 }
06157
06158 ast_event_queue_and_cache(event);
06159 }
06160
06161
06162
06163
06164
06165
06166
06167
06168
06169
06170
06171
06172
06173
06174 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
06175 {
06176 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06177 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06178 const char *category;
06179 char *myserveremail = serveremail;
06180
06181 ast_channel_lock(chan);
06182 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06183 category = ast_strdupa(category);
06184 }
06185 ast_channel_unlock(chan);
06186
06187 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
06188 make_file(fn, sizeof(fn), todir, msgnum);
06189 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06190
06191 if (!ast_strlen_zero(vmu->attachfmt)) {
06192 if (strstr(fmt, vmu->attachfmt))
06193 fmt = vmu->attachfmt;
06194 else
06195 ast_log(AST_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);
06196 }
06197
06198
06199 fmt = ast_strdupa(fmt);
06200 stringp = fmt;
06201 strsep(&stringp, "|");
06202
06203 if (!ast_strlen_zero(vmu->serveremail))
06204 myserveremail = vmu->serveremail;
06205
06206 if (!ast_strlen_zero(vmu->email)) {
06207 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06208 if (!attach_user_voicemail)
06209 attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
06210
06211 if (attach_user_voicemail)
06212 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06213
06214
06215 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06216
06217 if (attach_user_voicemail)
06218 DISPOSE(todir, msgnum);
06219 }
06220
06221 if (!ast_strlen_zero(vmu->pager)) {
06222 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category, flag);
06223 }
06224
06225 if (ast_test_flag(vmu, VM_DELETE))
06226 DELETE(todir, msgnum, fn, vmu);
06227
06228
06229 if (ast_app_has_voicemail(ext_context, NULL))
06230 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06231
06232 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06233
06234 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);
06235 run_externnotify(vmu->context, vmu->mailbox, flag);
06236
06237 #ifdef IMAP_STORAGE
06238 vm_delete(fn);
06239 if (ast_test_flag(vmu, VM_DELETE)) {
06240 vm_imap_delete(vms->curmsg, vmu);
06241 vms->newmessages--;
06242 }
06243 #endif
06244
06245 return 0;
06246 }
06247
06248
06249
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262
06263
06264
06265
06266
06267
06268
06269
06270
06271
06272
06273
06274 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
06275 {
06276 #ifdef IMAP_STORAGE
06277 int todircount=0;
06278 struct vm_state *dstvms;
06279 #endif
06280 char username[70]="";
06281 char fn[PATH_MAX];
06282 char ecodes[16] = "#";
06283 int res = 0, cmd = 0;
06284 struct ast_vm_user *receiver = NULL, *vmtmp;
06285 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06286 char *stringp;
06287 const char *s;
06288 int saved_messages = 0, found = 0;
06289 int valid_extensions = 0;
06290 char *dir;
06291 int curmsg;
06292 char urgent_str[7] = "";
06293 char tmptxtfile[PATH_MAX];
06294
06295 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06296 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06297 }
06298
06299 if (vms == NULL) return -1;
06300 dir = vms->curdir;
06301 curmsg = vms->curmsg;
06302
06303 tmptxtfile[0] = '\0';
06304 while (!res && !valid_extensions) {
06305 int use_directory = 0;
06306 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06307 int done = 0;
06308 int retries = 0;
06309 cmd=0;
06310 while ((cmd >= 0) && !done ){
06311 if (cmd)
06312 retries = 0;
06313 switch (cmd) {
06314 case '1':
06315 use_directory = 0;
06316 done = 1;
06317 break;
06318 case '2':
06319 use_directory = 1;
06320 done=1;
06321 break;
06322 case '*':
06323 cmd = 't';
06324 done = 1;
06325 break;
06326 default:
06327
06328 cmd = ast_play_and_wait(chan,"vm-forward");
06329 if (!cmd)
06330 cmd = ast_waitfordigit(chan,3000);
06331 if (!cmd)
06332 retries++;
06333 if (retries > 3) {
06334 cmd = 't';
06335 done = 1;
06336 }
06337
06338 }
06339 }
06340 if (cmd < 0 || cmd == 't')
06341 break;
06342 }
06343
06344 if (use_directory) {
06345
06346
06347 char old_context[sizeof(chan->context)];
06348 char old_exten[sizeof(chan->exten)];
06349 int old_priority;
06350 struct ast_app* directory_app;
06351
06352 directory_app = pbx_findapp("Directory");
06353 if (directory_app) {
06354 char vmcontext[256];
06355
06356 memcpy(old_context, chan->context, sizeof(chan->context));
06357 memcpy(old_exten, chan->exten, sizeof(chan->exten));
06358 old_priority = chan->priority;
06359
06360
06361 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
06362 res = pbx_exec(chan, directory_app, vmcontext);
06363
06364 ast_copy_string(username, chan->exten, sizeof(username));
06365
06366
06367 memcpy(chan->context, old_context, sizeof(chan->context));
06368 memcpy(chan->exten, old_exten, sizeof(chan->exten));
06369 chan->priority = old_priority;
06370 } else {
06371 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
06372 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
06373 }
06374 } else {
06375
06376 res = ast_streamfile(chan, "vm-extension", chan->language);
06377 if (res)
06378 break;
06379 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
06380 break;
06381 }
06382
06383
06384 if (ast_strlen_zero(username))
06385 continue;
06386 stringp = username;
06387 s = strsep(&stringp, "*");
06388
06389 valid_extensions = 1;
06390 while (s) {
06391 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
06392 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
06393 found++;
06394 } else {
06395
06396
06397
06398
06399
06400 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
06401 free_user(receiver);
06402 }
06403 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
06404 valid_extensions = 0;
06405 break;
06406 }
06407
06408
06409 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
06410 RETRIEVE(fn, -1, s, receiver->context);
06411 if (ast_fileexists(fn, NULL, NULL) > 0) {
06412 res = ast_stream_and_wait(chan, fn, ecodes);
06413 if (res) {
06414 DISPOSE(fn, -1);
06415 return res;
06416 }
06417 } else {
06418 res = ast_say_digit_str(chan, s, ecodes, chan->language);
06419 }
06420 DISPOSE(fn, -1);
06421
06422 s = strsep(&stringp, "*");
06423 }
06424
06425 if (valid_extensions)
06426 break;
06427
06428 res = ast_play_and_wait(chan, "pbx-invalid");
06429 }
06430
06431 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
06432 return res;
06433 if (is_new_message == 1) {
06434 struct leave_vm_options leave_options;
06435 char mailbox[AST_MAX_EXTENSION * 2 + 2];
06436 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
06437
06438
06439 memset(&leave_options, 0, sizeof(leave_options));
06440 leave_options.record_gain = record_gain;
06441 cmd = leave_voicemail(chan, mailbox, &leave_options);
06442 } else {
06443
06444 long duration = 0;
06445 struct vm_state vmstmp;
06446 memcpy(&vmstmp, vms, sizeof(vmstmp));
06447
06448 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
06449
06450 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
06451 if (!cmd) {
06452 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
06453 #ifdef IMAP_STORAGE
06454 int attach_user_voicemail;
06455 char *myserveremail = serveremail;
06456
06457
06458 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
06459 if (!dstvms) {
06460 dstvms = create_vm_state_from_user(vmtmp);
06461 }
06462 if (dstvms) {
06463 init_mailstream(dstvms, 0);
06464 if (!dstvms->mailstream) {
06465 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
06466 } else {
06467 STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
06468 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
06469 }
06470 } else {
06471 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
06472 }
06473 if (!ast_strlen_zero(vmtmp->serveremail))
06474 myserveremail = vmtmp->serveremail;
06475 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
06476
06477 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
06478 #else
06479 copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
06480 #endif
06481 saved_messages++;
06482 AST_LIST_REMOVE_CURRENT(list);
06483 free_user(vmtmp);
06484 if (res)
06485 break;
06486 }
06487 AST_LIST_TRAVERSE_SAFE_END;
06488 if (saved_messages > 0) {
06489
06490
06491
06492
06493
06494
06495
06496
06497 #ifdef IMAP_STORAGE
06498
06499 if (ast_strlen_zero(vmstmp.introfn))
06500 #endif
06501 res = ast_play_and_wait(chan, "vm-msgsaved");
06502 }
06503 }
06504 DISPOSE(dir, curmsg);
06505 }
06506
06507
06508 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
06509 free_user(vmtmp);
06510 return res ? res : cmd;
06511 }
06512
06513 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
06514 {
06515 int res;
06516 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
06517 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
06518 return res;
06519 }
06520
06521 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
06522 {
06523 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
06524 }
06525
06526 static int play_message_category(struct ast_channel *chan, const char *category)
06527 {
06528 int res = 0;
06529
06530 if (!ast_strlen_zero(category))
06531 res = ast_play_and_wait(chan, category);
06532
06533 if (res) {
06534 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
06535 res = 0;
06536 }
06537
06538 return res;
06539 }
06540
06541 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
06542 {
06543 int res = 0;
06544 struct vm_zone *the_zone = NULL;
06545 time_t t;
06546
06547 if (ast_get_time_t(origtime, &t, 0, NULL)) {
06548 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
06549 return 0;
06550 }
06551
06552
06553 if (!ast_strlen_zero(vmu->zonetag)) {
06554
06555 struct vm_zone *z;
06556 AST_LIST_LOCK(&zones);
06557 AST_LIST_TRAVERSE(&zones, z, list) {
06558 if (!strcmp(z->name, vmu->zonetag)) {
06559 the_zone = z;
06560 break;
06561 }
06562 }
06563 AST_LIST_UNLOCK(&zones);
06564 }
06565
06566
06567 #if 0
06568
06569 ast_localtime(&t, &time_now, NULL);
06570 tv_now = ast_tvnow();
06571 ast_localtime(&tv_now, &time_then, NULL);
06572
06573
06574 if (time_now.tm_year == time_then.tm_year)
06575 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
06576 else
06577 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
06578 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
06579
06580
06581 #endif
06582 if (the_zone) {
06583 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
06584 }
06585 else if (!strcasecmp(chan->language,"pl"))
06586 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
06587 else if (!strcasecmp(chan->language,"se"))
06588 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
06589 else if (!strcasecmp(chan->language,"no"))
06590 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06591 else if (!strcasecmp(chan->language,"de"))
06592 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06593 else if (!strcasecmp(chan->language,"nl"))
06594 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
06595 else if (!strcasecmp(chan->language,"it"))
06596 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);
06597 else if (!strcasecmp(chan->language,"gr"))
06598 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
06599 else if (!strcasecmp(chan->language,"pt_BR"))
06600 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);
06601 else if (!strcasecmp(chan->language,"tw"))
06602 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
06603 else {
06604 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
06605 }
06606 #if 0
06607 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
06608 #endif
06609 return res;
06610 }
06611
06612
06613
06614 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
06615 {
06616 int res = 0;
06617 int i;
06618 char *callerid, *name;
06619 char prefile[PATH_MAX] = "";
06620
06621
06622
06623
06624
06625
06626
06627
06628
06629 if ((cid == NULL)||(context == NULL))
06630 return res;
06631
06632
06633 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
06634 ast_callerid_parse(cid, &name, &callerid);
06635 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
06636
06637
06638 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
06639 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
06640 if ((strcmp(cidinternalcontexts[i], context) == 0))
06641 break;
06642 }
06643 if (i != MAX_NUM_CID_CONTEXTS){
06644 if (!res) {
06645 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
06646 if (!ast_strlen_zero(prefile)) {
06647
06648 if (ast_fileexists(prefile, NULL, NULL) > 0) {
06649 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
06650 if (!callback)
06651 res = wait_file2(chan, vms, "vm-from");
06652 res = ast_stream_and_wait(chan, prefile, "");
06653 } else {
06654 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
06655
06656 if (!callback)
06657 res = wait_file2(chan, vms, "vm-from-extension");
06658 res = ast_say_digit_str(chan, callerid, "", chan->language);
06659 }
06660 }
06661 }
06662 } else if (!res) {
06663 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
06664
06665 if (!callback)
06666 res = wait_file2(chan, vms, "vm-from-phonenumber");
06667 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
06668 }
06669 } else {
06670
06671 ast_debug(1, "VM-CID: From an unknown number\n");
06672
06673 res = wait_file2(chan, vms, "vm-unknown-caller");
06674 }
06675 return res;
06676 }
06677
06678 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
06679 {
06680 int res = 0;
06681 int durationm;
06682 int durations;
06683
06684 if (duration == NULL)
06685 return res;
06686
06687
06688 durations=atoi(duration);
06689 durationm=(durations / 60);
06690
06691 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
06692
06693 if ((!res) && (durationm >= minduration)) {
06694 res = wait_file2(chan, vms, "vm-duration");
06695
06696
06697 if (!strcasecmp(chan->language, "pl")) {
06698 div_t num = div(durationm, 10);
06699
06700 if (durationm == 1) {
06701 res = ast_play_and_wait(chan, "digits/1z");
06702 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
06703 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06704 if (num.rem == 2) {
06705 if (!num.quot) {
06706 res = ast_play_and_wait(chan, "digits/2-ie");
06707 } else {
06708 res = say_and_wait(chan, durationm - 2 , chan->language);
06709 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06710 }
06711 } else {
06712 res = say_and_wait(chan, durationm, chan->language);
06713 }
06714 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
06715 } else {
06716 res = say_and_wait(chan, durationm, chan->language);
06717 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
06718 }
06719
06720 } else {
06721 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
06722 res = wait_file2(chan, vms, "vm-minutes");
06723 }
06724 }
06725 return res;
06726 }
06727
06728 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06729 {
06730 int res = 0;
06731 char filename[256], *cid;
06732 const char *origtime, *context, *category, *duration, *flag;
06733 struct ast_config *msg_cfg;
06734 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06735
06736 vms->starting = 0;
06737 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06738 adsi_message(chan, vms);
06739 if (!vms->curmsg)
06740 res = wait_file2(chan, vms, "vm-first");
06741 else if (vms->curmsg == vms->lastmsg)
06742 res = wait_file2(chan, vms, "vm-last");
06743
06744 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
06745 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
06746 msg_cfg = ast_config_load(filename, config_flags);
06747 if (!msg_cfg) {
06748 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06749 return 0;
06750 }
06751 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
06752
06753
06754 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06755 res = wait_file2(chan, vms, "vm-Urgent");
06756 }
06757
06758 if (!res) {
06759
06760 if (!strcasecmp(chan->language, "pl")) {
06761 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06762 int ten, one;
06763 char nextmsg[256];
06764 ten = (vms->curmsg + 1) / 10;
06765 one = (vms->curmsg + 1) % 10;
06766
06767 if (vms->curmsg < 20) {
06768 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
06769 res = wait_file2(chan, vms, nextmsg);
06770 } else {
06771 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
06772 res = wait_file2(chan, vms, nextmsg);
06773 if (one > 0) {
06774 if (!res) {
06775 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
06776 res = wait_file2(chan, vms, nextmsg);
06777 }
06778 }
06779 }
06780 }
06781 if (!res)
06782 res = wait_file2(chan, vms, "vm-message");
06783
06784 } else if (!strcasecmp(chan->language, "he")) {
06785 if (!vms->curmsg) {
06786 res = wait_file2(chan, vms, "vm-message");
06787 res = wait_file2(chan, vms, "vm-first");
06788 } else if (vms->curmsg == vms->lastmsg) {
06789 res = wait_file2(chan, vms, "vm-message");
06790 res = wait_file2(chan, vms, "vm-last");
06791 } else {
06792 res = wait_file2(chan, vms, "vm-message");
06793 res = wait_file2(chan, vms, "vm-number");
06794 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
06795 }
06796 } else {
06797 if (!strcasecmp(chan->language, "se"))
06798 res = wait_file2(chan, vms, "vm-meddelandet");
06799 else {
06800 res = wait_file2(chan, vms, "vm-message");
06801 }
06802 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06803 if (!res) {
06804 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06805 }
06806 }
06807 }
06808 }
06809
06810 if (!msg_cfg) {
06811 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06812 return 0;
06813 }
06814
06815 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
06816 ast_log(AST_LOG_WARNING, "No origtime?!\n");
06817 DISPOSE(vms->curdir, vms->curmsg);
06818 ast_config_destroy(msg_cfg);
06819 return 0;
06820 }
06821
06822 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
06823 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
06824 category = ast_variable_retrieve(msg_cfg, "message", "category");
06825
06826 context = ast_variable_retrieve(msg_cfg, "message", "context");
06827 if (!strncasecmp("macro",context,5))
06828 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
06829 if (!res) {
06830 res = play_message_category(chan, category);
06831 }
06832 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
06833 res = play_message_datetime(chan, vmu, origtime, filename);
06834 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
06835 res = play_message_callerid(chan, vms, cid, context, 0);
06836 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
06837 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
06838
06839 if (res == '1')
06840 res = 0;
06841 ast_config_destroy(msg_cfg);
06842
06843 if (!res) {
06844 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06845 vms->heard[vms->curmsg] = 1;
06846 #ifdef IMAP_STORAGE
06847
06848
06849
06850 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
06851 wait_file(chan, vms, vms->introfn);
06852 }
06853 #endif
06854 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
06855 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
06856 res = 0;
06857 }
06858 }
06859 DISPOSE(vms->curdir, vms->curmsg);
06860 return res;
06861 }
06862
06863 #ifdef IMAP_STORAGE
06864 static int imap_remove_file(char *dir, int msgnum)
06865 {
06866 char fn[PATH_MAX];
06867 char full_fn[PATH_MAX];
06868 char intro[PATH_MAX] = {0,};
06869
06870 if (msgnum > -1) {
06871 make_file(fn, sizeof(fn), dir, msgnum);
06872 snprintf(intro, sizeof(intro), "%sintro", fn);
06873 } else
06874 ast_copy_string(fn, dir, sizeof(fn));
06875
06876 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
06877 ast_filedelete(fn, NULL);
06878 if (!ast_strlen_zero(intro)) {
06879 ast_filedelete(intro, NULL);
06880 }
06881 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
06882 unlink(full_fn);
06883 }
06884 return 0;
06885 }
06886
06887
06888
06889 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
06890 {
06891 char *file, *filename;
06892 char *attachment;
06893 char arg[10];
06894 int i;
06895 BODY* body;
06896
06897
06898 file = strrchr(ast_strdupa(dir), '/');
06899 if (file)
06900 *file++ = '\0';
06901 else {
06902 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
06903 return -1;
06904 }
06905
06906 ast_mutex_lock(&vms->lock);
06907 for (i = 0; i < vms->mailstream->nmsgs; i++) {
06908 mail_fetchstructure(vms->mailstream, i + 1, &body);
06909
06910 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
06911 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
06912 } else {
06913 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
06914 ast_mutex_unlock(&vms->lock);
06915 return -1;
06916 }
06917 filename = strsep(&attachment, ".");
06918 if (!strcmp(filename, file)) {
06919 sprintf (arg,"%d", i+1);
06920 mail_setflag (vms->mailstream,arg,"\\DELETED");
06921 }
06922 }
06923 mail_expunge(vms->mailstream);
06924 ast_mutex_unlock(&vms->lock);
06925 return 0;
06926 }
06927
06928 #else
06929 #ifndef IMAP_STORAGE
06930 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
06931 {
06932 int count_msg, last_msg;
06933
06934 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
06935
06936
06937
06938
06939 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
06940
06941
06942 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
06943
06944 count_msg = count_messages(vmu, vms->curdir);
06945 if (count_msg < 0)
06946 return count_msg;
06947 else
06948 vms->lastmsg = count_msg - 1;
06949
06950
06951
06952
06953
06954
06955
06956
06957 if (vm_lock_path(vms->curdir)) {
06958 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
06959 return -1;
06960 }
06961
06962 last_msg = last_message_index(vmu, vms->curdir);
06963 ast_unlock_path(vms->curdir);
06964
06965 if (last_msg < 0)
06966 return last_msg;
06967
06968 return 0;
06969 }
06970 #endif
06971 #endif
06972
06973 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
06974 {
06975 int x = 0;
06976 #ifndef IMAP_STORAGE
06977 int res = 0, nummsg;
06978 char fn2[PATH_MAX];
06979 #endif
06980
06981 if (vms->lastmsg <= -1)
06982 goto done;
06983
06984 vms->curmsg = -1;
06985 #ifndef IMAP_STORAGE
06986
06987 if (vm_lock_path(vms->curdir))
06988 return ERROR_LOCK_PATH;
06989
06990 for (x = 0; x < vmu->maxmsg; x++) {
06991 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
06992
06993 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06994 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
06995 break;
06996 vms->curmsg++;
06997 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
06998 if (strcmp(vms->fn, fn2)) {
06999 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07000 }
07001 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07002
07003 res = save_to_folder(vmu, vms, x, 1);
07004 if (res == ERROR_LOCK_PATH) {
07005
07006 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07007 vms->deleted[x] = 0;
07008 vms->heard[x] = 0;
07009 --x;
07010 }
07011 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07012
07013 res = save_to_folder(vmu, vms, x, 10);
07014 if (res == ERROR_LOCK_PATH) {
07015
07016 vms->deleted[x] = 0;
07017 vms->heard[x] = 0;
07018 --x;
07019 }
07020 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07021
07022
07023 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07024 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07025 DELETE(vms->curdir, x, vms->fn, vmu);
07026 }
07027 }
07028
07029
07030 nummsg = x - 1;
07031 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07032 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07033 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07034 DELETE(vms->curdir, x, vms->fn, vmu);
07035 }
07036 ast_unlock_path(vms->curdir);
07037 #else
07038 if (vms->deleted) {
07039 for (x=0;x < vmu->maxmsg;x++) {
07040 if (vms->deleted[x]) {
07041 ast_debug(3,"IMAP delete of %d\n",x);
07042 DELETE(vms->curdir, x, vms->fn, vmu);
07043 }
07044 }
07045 }
07046 #endif
07047
07048 done:
07049 if (vms->deleted)
07050 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
07051 if (vms->heard)
07052 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
07053
07054 return 0;
07055 }
07056
07057
07058
07059
07060
07061
07062
07063 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07064 {
07065 int cmd;
07066 char *buf;
07067
07068 buf = alloca(strlen(box)+2);
07069 strcpy(buf, box);
07070 strcat(buf,"s");
07071
07072 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07073 cmd = ast_play_and_wait(chan, buf);
07074 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07075 } else {
07076 cmd = ast_play_and_wait(chan, "vm-messages");
07077 return cmd ? cmd : ast_play_and_wait(chan, box);
07078 }
07079 }
07080
07081 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07082 {
07083 int cmd;
07084
07085 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07086 if (!strcasecmp(box, "vm-INBOX"))
07087 cmd = ast_play_and_wait(chan, "vm-new-e");
07088 else
07089 cmd = ast_play_and_wait(chan, "vm-old-e");
07090 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07091 } else {
07092 cmd = ast_play_and_wait(chan, "vm-messages");
07093 return cmd ? cmd : ast_play_and_wait(chan, box);
07094 }
07095 }
07096
07097 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07098 {
07099 int cmd;
07100
07101 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07102 cmd = ast_play_and_wait(chan, "vm-messages");
07103 return cmd ? cmd : ast_play_and_wait(chan, box);
07104 } else {
07105 cmd = ast_play_and_wait(chan, box);
07106 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07107 }
07108 }
07109
07110 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07111 {
07112 int cmd;
07113
07114 if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) {
07115 cmd = ast_play_and_wait(chan, "vm-messages");
07116 return cmd ? cmd : ast_play_and_wait(chan, box);
07117 } else if (!strcasecmp(chan->language, "gr")){
07118 return vm_play_folder_name_gr(chan, box);
07119 } else if (!strcasecmp(chan->language, "pl")){
07120 return vm_play_folder_name_pl(chan, box);
07121 } else if (!strcasecmp(chan->language, "ua")){
07122 return vm_play_folder_name_ua(chan, box);
07123 } else {
07124 cmd = ast_play_and_wait(chan, box);
07125 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07126 }
07127 }
07128
07129
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139
07140
07141 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07142 {
07143 int res = 0;
07144
07145 if (vms->newmessages) {
07146 res = ast_play_and_wait(chan, "vm-youhave");
07147 if (!res)
07148 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07149 if (!res) {
07150 if ((vms->newmessages == 1)) {
07151 res = ast_play_and_wait(chan, "vm-INBOX");
07152 if (!res)
07153 res = ast_play_and_wait(chan, "vm-message");
07154 } else {
07155 res = ast_play_and_wait(chan, "vm-INBOXs");
07156 if (!res)
07157 res = ast_play_and_wait(chan, "vm-messages");
07158 }
07159 }
07160 } else if (vms->oldmessages){
07161 res = ast_play_and_wait(chan, "vm-youhave");
07162 if (!res)
07163 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07164 if ((vms->oldmessages == 1)){
07165 res = ast_play_and_wait(chan, "vm-Old");
07166 if (!res)
07167 res = ast_play_and_wait(chan, "vm-message");
07168 } else {
07169 res = ast_play_and_wait(chan, "vm-Olds");
07170 if (!res)
07171 res = ast_play_and_wait(chan, "vm-messages");
07172 }
07173 } else if (!vms->oldmessages && !vms->newmessages)
07174 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07175 return res;
07176 }
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206
07207
07208
07209
07210
07211
07212
07213
07214
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227
07228
07229
07230
07231
07232
07233
07234
07235 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
07236 {
07237 int res;
07238 int lastnum = 0;
07239
07240 res = ast_play_and_wait(chan, "vm-youhave");
07241
07242 if (!res && vms->newmessages) {
07243 lastnum = vms->newmessages;
07244
07245 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07246 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
07247 }
07248
07249 if (!res && vms->oldmessages) {
07250 res = ast_play_and_wait(chan, "vm-and");
07251 }
07252 }
07253
07254 if (!res && vms->oldmessages) {
07255 lastnum = vms->oldmessages;
07256
07257 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07258 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
07259 }
07260 }
07261
07262 if (!res) {
07263 if (lastnum == 0) {
07264 res = ast_play_and_wait(chan, "vm-no");
07265 }
07266 if (!res) {
07267 res = ast_say_counted_noun(chan, lastnum, "vm-message");
07268 }
07269 }
07270
07271 return res;
07272 }
07273
07274
07275 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
07276 {
07277 int res = 0;
07278
07279
07280 if (!res) {
07281 if ((vms->newmessages) || (vms->oldmessages)) {
07282 res = ast_play_and_wait(chan, "vm-youhave");
07283 }
07284
07285
07286
07287
07288
07289 if (vms->newmessages) {
07290 if (!res) {
07291 if (vms->newmessages == 1) {
07292 res = ast_play_and_wait(chan, "vm-INBOX1");
07293 } else {
07294 if (vms->newmessages == 2) {
07295 res = ast_play_and_wait(chan, "vm-shtei");
07296 } else {
07297 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07298 }
07299 res = ast_play_and_wait(chan, "vm-INBOX");
07300 }
07301 }
07302 if (vms->oldmessages && !res) {
07303 res = ast_play_and_wait(chan, "vm-and");
07304 if (vms->oldmessages == 1) {
07305 res = ast_play_and_wait(chan, "vm-Old1");
07306 } else {
07307 if (vms->oldmessages == 2) {
07308 res = ast_play_and_wait(chan, "vm-shtei");
07309 } else {
07310 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07311 }
07312 res = ast_play_and_wait(chan, "vm-Old");
07313 }
07314 }
07315 }
07316 if (!res && vms->oldmessages && !vms->newmessages) {
07317 if (!res) {
07318 if (vms->oldmessages == 1) {
07319 res = ast_play_and_wait(chan, "vm-Old1");
07320 } else {
07321 if (vms->oldmessages == 2) {
07322 res = ast_play_and_wait(chan, "vm-shtei");
07323 } else {
07324 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07325 }
07326 res = ast_play_and_wait(chan, "vm-Old");
07327 }
07328 }
07329 }
07330 if (!res) {
07331 if (!vms->oldmessages && !vms->newmessages) {
07332 if (!res) {
07333 res = ast_play_and_wait(chan, "vm-nomessages");
07334 }
07335 }
07336 }
07337 }
07338 return res;
07339 }
07340
07341
07342 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
07343 {
07344 int res;
07345
07346
07347 res = ast_play_and_wait(chan, "vm-youhave");
07348 if (!res) {
07349 if (vms->urgentmessages) {
07350 res = say_and_wait(chan, vms->urgentmessages, chan->language);
07351 if (!res)
07352 res = ast_play_and_wait(chan, "vm-Urgent");
07353 if ((vms->oldmessages || vms->newmessages) && !res) {
07354 res = ast_play_and_wait(chan, "vm-and");
07355 } else if (!res) {
07356 if ((vms->urgentmessages == 1))
07357 res = ast_play_and_wait(chan, "vm-message");
07358 else
07359 res = ast_play_and_wait(chan, "vm-messages");
07360 }
07361 }
07362 if (vms->newmessages) {
07363 res = say_and_wait(chan, vms->newmessages, chan->language);
07364 if (!res)
07365 res = ast_play_and_wait(chan, "vm-INBOX");
07366 if (vms->oldmessages && !res)
07367 res = ast_play_and_wait(chan, "vm-and");
07368 else if (!res) {
07369 if ((vms->newmessages == 1))
07370 res = ast_play_and_wait(chan, "vm-message");
07371 else
07372 res = ast_play_and_wait(chan, "vm-messages");
07373 }
07374
07375 }
07376 if (!res && vms->oldmessages) {
07377 res = say_and_wait(chan, vms->oldmessages, chan->language);
07378 if (!res)
07379 res = ast_play_and_wait(chan, "vm-Old");
07380 if (!res) {
07381 if (vms->oldmessages == 1)
07382 res = ast_play_and_wait(chan, "vm-message");
07383 else
07384 res = ast_play_and_wait(chan, "vm-messages");
07385 }
07386 }
07387 if (!res) {
07388 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
07389 res = ast_play_and_wait(chan, "vm-no");
07390 if (!res)
07391 res = ast_play_and_wait(chan, "vm-messages");
07392 }
07393 }
07394 }
07395 return res;
07396 }
07397
07398
07399 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
07400 {
07401
07402 int res;
07403 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
07404 res = ast_play_and_wait(chan, "vm-no") ||
07405 ast_play_and_wait(chan, "vm-message");
07406 else
07407 res = ast_play_and_wait(chan, "vm-youhave");
07408 if (!res && vms->newmessages) {
07409 res = (vms->newmessages == 1) ?
07410 ast_play_and_wait(chan, "digits/un") ||
07411 ast_play_and_wait(chan, "vm-nuovo") ||
07412 ast_play_and_wait(chan, "vm-message") :
07413
07414 say_and_wait(chan, vms->newmessages, chan->language) ||
07415 ast_play_and_wait(chan, "vm-nuovi") ||
07416 ast_play_and_wait(chan, "vm-messages");
07417 if (!res && vms->oldmessages)
07418 res = ast_play_and_wait(chan, "vm-and");
07419 }
07420 if (!res && vms->oldmessages) {
07421 res = (vms->oldmessages == 1) ?
07422 ast_play_and_wait(chan, "digits/un") ||
07423 ast_play_and_wait(chan, "vm-vecchio") ||
07424 ast_play_and_wait(chan, "vm-message") :
07425
07426 say_and_wait(chan, vms->oldmessages, chan->language) ||
07427 ast_play_and_wait(chan, "vm-vecchi") ||
07428 ast_play_and_wait(chan, "vm-messages");
07429 }
07430 return res;
07431 }
07432
07433
07434 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
07435 {
07436
07437 int res;
07438 div_t num;
07439
07440 if (!vms->oldmessages && !vms->newmessages) {
07441 res = ast_play_and_wait(chan, "vm-no");
07442 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07443 return res;
07444 } else {
07445 res = ast_play_and_wait(chan, "vm-youhave");
07446 }
07447
07448 if (vms->newmessages) {
07449 num = div(vms->newmessages, 10);
07450 if (vms->newmessages == 1) {
07451 res = ast_play_and_wait(chan, "digits/1-a");
07452 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
07453 res = res ? res : ast_play_and_wait(chan, "vm-message");
07454 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07455 if (num.rem == 2) {
07456 if (!num.quot) {
07457 res = ast_play_and_wait(chan, "digits/2-ie");
07458 } else {
07459 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
07460 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07461 }
07462 } else {
07463 res = say_and_wait(chan, vms->newmessages, chan->language);
07464 }
07465 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
07466 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07467 } else {
07468 res = say_and_wait(chan, vms->newmessages, chan->language);
07469 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
07470 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07471 }
07472 if (!res && vms->oldmessages)
07473 res = ast_play_and_wait(chan, "vm-and");
07474 }
07475 if (!res && vms->oldmessages) {
07476 num = div(vms->oldmessages, 10);
07477 if (vms->oldmessages == 1) {
07478 res = ast_play_and_wait(chan, "digits/1-a");
07479 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
07480 res = res ? res : ast_play_and_wait(chan, "vm-message");
07481 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07482 if (num.rem == 2) {
07483 if (!num.quot) {
07484 res = ast_play_and_wait(chan, "digits/2-ie");
07485 } else {
07486 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
07487 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07488 }
07489 } else {
07490 res = say_and_wait(chan, vms->oldmessages, chan->language);
07491 }
07492 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
07493 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07494 } else {
07495 res = say_and_wait(chan, vms->oldmessages, chan->language);
07496 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
07497 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07498 }
07499 }
07500
07501 return res;
07502 }
07503
07504
07505 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
07506 {
07507
07508 int res;
07509
07510 res = ast_play_and_wait(chan, "vm-youhave");
07511 if (res)
07512 return res;
07513
07514 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07515 res = ast_play_and_wait(chan, "vm-no");
07516 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07517 return res;
07518 }
07519
07520 if (vms->newmessages) {
07521 if ((vms->newmessages == 1)) {
07522 res = ast_play_and_wait(chan, "digits/ett");
07523 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
07524 res = res ? res : ast_play_and_wait(chan, "vm-message");
07525 } else {
07526 res = say_and_wait(chan, vms->newmessages, chan->language);
07527 res = res ? res : ast_play_and_wait(chan, "vm-nya");
07528 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07529 }
07530 if (!res && vms->oldmessages)
07531 res = ast_play_and_wait(chan, "vm-and");
07532 }
07533 if (!res && vms->oldmessages) {
07534 if (vms->oldmessages == 1) {
07535 res = ast_play_and_wait(chan, "digits/ett");
07536 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
07537 res = res ? res : ast_play_and_wait(chan, "vm-message");
07538 } else {
07539 res = say_and_wait(chan, vms->oldmessages, chan->language);
07540 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
07541 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07542 }
07543 }
07544
07545 return res;
07546 }
07547
07548
07549 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
07550 {
07551
07552 int res;
07553
07554 res = ast_play_and_wait(chan, "vm-youhave");
07555 if (res)
07556 return res;
07557
07558 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07559 res = ast_play_and_wait(chan, "vm-no");
07560 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07561 return res;
07562 }
07563
07564 if (vms->newmessages) {
07565 if ((vms->newmessages == 1)) {
07566 res = ast_play_and_wait(chan, "digits/1");
07567 res = res ? res : ast_play_and_wait(chan, "vm-ny");
07568 res = res ? res : ast_play_and_wait(chan, "vm-message");
07569 } else {
07570 res = say_and_wait(chan, vms->newmessages, chan->language);
07571 res = res ? res : ast_play_and_wait(chan, "vm-nye");
07572 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07573 }
07574 if (!res && vms->oldmessages)
07575 res = ast_play_and_wait(chan, "vm-and");
07576 }
07577 if (!res && vms->oldmessages) {
07578 if (vms->oldmessages == 1) {
07579 res = ast_play_and_wait(chan, "digits/1");
07580 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
07581 res = res ? res : ast_play_and_wait(chan, "vm-message");
07582 } else {
07583 res = say_and_wait(chan, vms->oldmessages, chan->language);
07584 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
07585 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07586 }
07587 }
07588
07589 return res;
07590 }
07591
07592
07593 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
07594 {
07595
07596 int res;
07597 res = ast_play_and_wait(chan, "vm-youhave");
07598 if (!res) {
07599 if (vms->newmessages) {
07600 if ((vms->newmessages == 1))
07601 res = ast_play_and_wait(chan, "digits/1F");
07602 else
07603 res = say_and_wait(chan, vms->newmessages, chan->language);
07604 if (!res)
07605 res = ast_play_and_wait(chan, "vm-INBOX");
07606 if (vms->oldmessages && !res)
07607 res = ast_play_and_wait(chan, "vm-and");
07608 else if (!res) {
07609 if ((vms->newmessages == 1))
07610 res = ast_play_and_wait(chan, "vm-message");
07611 else
07612 res = ast_play_and_wait(chan, "vm-messages");
07613 }
07614
07615 }
07616 if (!res && vms->oldmessages) {
07617 if (vms->oldmessages == 1)
07618 res = ast_play_and_wait(chan, "digits/1F");
07619 else
07620 res = say_and_wait(chan, vms->oldmessages, chan->language);
07621 if (!res)
07622 res = ast_play_and_wait(chan, "vm-Old");
07623 if (!res) {
07624 if (vms->oldmessages == 1)
07625 res = ast_play_and_wait(chan, "vm-message");
07626 else
07627 res = ast_play_and_wait(chan, "vm-messages");
07628 }
07629 }
07630 if (!res) {
07631 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07632 res = ast_play_and_wait(chan, "vm-no");
07633 if (!res)
07634 res = ast_play_and_wait(chan, "vm-messages");
07635 }
07636 }
07637 }
07638 return res;
07639 }
07640
07641
07642 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
07643 {
07644
07645 int res;
07646 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07647 res = ast_play_and_wait(chan, "vm-youhaveno");
07648 if (!res)
07649 res = ast_play_and_wait(chan, "vm-messages");
07650 } else {
07651 res = ast_play_and_wait(chan, "vm-youhave");
07652 }
07653 if (!res) {
07654 if (vms->newmessages) {
07655 if (!res) {
07656 if ((vms->newmessages == 1)) {
07657 res = ast_play_and_wait(chan, "digits/1M");
07658 if (!res)
07659 res = ast_play_and_wait(chan, "vm-message");
07660 if (!res)
07661 res = ast_play_and_wait(chan, "vm-INBOXs");
07662 } else {
07663 res = say_and_wait(chan, vms->newmessages, chan->language);
07664 if (!res)
07665 res = ast_play_and_wait(chan, "vm-messages");
07666 if (!res)
07667 res = ast_play_and_wait(chan, "vm-INBOX");
07668 }
07669 }
07670 if (vms->oldmessages && !res)
07671 res = ast_play_and_wait(chan, "vm-and");
07672 }
07673 if (vms->oldmessages) {
07674 if (!res) {
07675 if (vms->oldmessages == 1) {
07676 res = ast_play_and_wait(chan, "digits/1M");
07677 if (!res)
07678 res = ast_play_and_wait(chan, "vm-message");
07679 if (!res)
07680 res = ast_play_and_wait(chan, "vm-Olds");
07681 } else {
07682 res = say_and_wait(chan, vms->oldmessages, chan->language);
07683 if (!res)
07684 res = ast_play_and_wait(chan, "vm-messages");
07685 if (!res)
07686 res = ast_play_and_wait(chan, "vm-Old");
07687 }
07688 }
07689 }
07690 }
07691 return res;
07692 }
07693
07694
07695 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
07696
07697 int res;
07698 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07699 res = ast_play_and_wait(chan, "vm-nomessages");
07700 return res;
07701 } else {
07702 res = ast_play_and_wait(chan, "vm-youhave");
07703 }
07704 if (vms->newmessages) {
07705 if (!res)
07706 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07707 if ((vms->newmessages == 1)) {
07708 if (!res)
07709 res = ast_play_and_wait(chan, "vm-message");
07710 if (!res)
07711 res = ast_play_and_wait(chan, "vm-INBOXs");
07712 } else {
07713 if (!res)
07714 res = ast_play_and_wait(chan, "vm-messages");
07715 if (!res)
07716 res = ast_play_and_wait(chan, "vm-INBOX");
07717 }
07718 if (vms->oldmessages && !res)
07719 res = ast_play_and_wait(chan, "vm-and");
07720 }
07721 if (vms->oldmessages) {
07722 if (!res)
07723 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07724 if (vms->oldmessages == 1) {
07725 if (!res)
07726 res = ast_play_and_wait(chan, "vm-message");
07727 if (!res)
07728 res = ast_play_and_wait(chan, "vm-Olds");
07729 } else {
07730 if (!res)
07731 res = ast_play_and_wait(chan, "vm-messages");
07732 if (!res)
07733 res = ast_play_and_wait(chan, "vm-Old");
07734 }
07735 }
07736 return res;
07737 }
07738
07739
07740 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
07741 {
07742
07743 int res;
07744 res = ast_play_and_wait(chan, "vm-youhave");
07745 if (!res) {
07746 if (vms->newmessages) {
07747 res = say_and_wait(chan, vms->newmessages, chan->language);
07748 if (!res)
07749 res = ast_play_and_wait(chan, "vm-INBOX");
07750 if (vms->oldmessages && !res)
07751 res = ast_play_and_wait(chan, "vm-and");
07752 else if (!res) {
07753 if ((vms->newmessages == 1))
07754 res = ast_play_and_wait(chan, "vm-message");
07755 else
07756 res = ast_play_and_wait(chan, "vm-messages");
07757 }
07758
07759 }
07760 if (!res && vms->oldmessages) {
07761 res = say_and_wait(chan, vms->oldmessages, chan->language);
07762 if (!res)
07763 res = ast_play_and_wait(chan, "vm-Old");
07764 if (!res) {
07765 if (vms->oldmessages == 1)
07766 res = ast_play_and_wait(chan, "vm-message");
07767 else
07768 res = ast_play_and_wait(chan, "vm-messages");
07769 }
07770 }
07771 if (!res) {
07772 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07773 res = ast_play_and_wait(chan, "vm-no");
07774 if (!res)
07775 res = ast_play_and_wait(chan, "vm-messages");
07776 }
07777 }
07778 }
07779 return res;
07780 }
07781
07782
07783 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
07784 {
07785
07786 int res;
07787 res = ast_play_and_wait(chan, "vm-youhave");
07788 if (!res) {
07789 if (vms->newmessages) {
07790 res = say_and_wait(chan, vms->newmessages, chan->language);
07791 if (!res) {
07792 if (vms->newmessages == 1)
07793 res = ast_play_and_wait(chan, "vm-INBOXs");
07794 else
07795 res = ast_play_and_wait(chan, "vm-INBOX");
07796 }
07797 if (vms->oldmessages && !res)
07798 res = ast_play_and_wait(chan, "vm-and");
07799 else if (!res) {
07800 if ((vms->newmessages == 1))
07801 res = ast_play_and_wait(chan, "vm-message");
07802 else
07803 res = ast_play_and_wait(chan, "vm-messages");
07804 }
07805
07806 }
07807 if (!res && vms->oldmessages) {
07808 res = say_and_wait(chan, vms->oldmessages, chan->language);
07809 if (!res) {
07810 if (vms->oldmessages == 1)
07811 res = ast_play_and_wait(chan, "vm-Olds");
07812 else
07813 res = ast_play_and_wait(chan, "vm-Old");
07814 }
07815 if (!res) {
07816 if (vms->oldmessages == 1)
07817 res = ast_play_and_wait(chan, "vm-message");
07818 else
07819 res = ast_play_and_wait(chan, "vm-messages");
07820 }
07821 }
07822 if (!res) {
07823 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07824 res = ast_play_and_wait(chan, "vm-no");
07825 if (!res)
07826 res = ast_play_and_wait(chan, "vm-messages");
07827 }
07828 }
07829 }
07830 return res;
07831 }
07832
07833
07834 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
07835 {
07836
07837 int res;
07838 res = ast_play_and_wait(chan, "vm-youhave");
07839 if (!res) {
07840 if (vms->newmessages) {
07841 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07842 if (!res) {
07843 if ((vms->newmessages == 1)) {
07844 res = ast_play_and_wait(chan, "vm-message");
07845 if (!res)
07846 res = ast_play_and_wait(chan, "vm-INBOXs");
07847 } else {
07848 res = ast_play_and_wait(chan, "vm-messages");
07849 if (!res)
07850 res = ast_play_and_wait(chan, "vm-INBOX");
07851 }
07852 }
07853 if (vms->oldmessages && !res)
07854 res = ast_play_and_wait(chan, "vm-and");
07855 }
07856 if (!res && vms->oldmessages) {
07857 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07858 if (!res) {
07859 if (vms->oldmessages == 1) {
07860 res = ast_play_and_wait(chan, "vm-message");
07861 if (!res)
07862 res = ast_play_and_wait(chan, "vm-Olds");
07863 } else {
07864 res = ast_play_and_wait(chan, "vm-messages");
07865 if (!res)
07866 res = ast_play_and_wait(chan, "vm-Old");
07867 }
07868 }
07869 }
07870 if (!res) {
07871 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07872 res = ast_play_and_wait(chan, "vm-no");
07873 if (!res)
07874 res = ast_play_and_wait(chan, "vm-messages");
07875 }
07876 }
07877 }
07878 return res;
07879 }
07880
07881
07882
07883
07884
07885
07886
07887
07888
07889
07890
07891
07892
07893
07894
07895
07896
07897 static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
07898 {
07899 int res;
07900 res = ast_play_and_wait(chan, "vm-youhave");
07901 if (!res) {
07902 if (vms->newmessages) {
07903 if (vms->newmessages == 1) {
07904 res = ast_play_and_wait(chan, "digits/jednu");
07905 } else {
07906 res = say_and_wait(chan, vms->newmessages, chan->language);
07907 }
07908 if (!res) {
07909 if ((vms->newmessages == 1))
07910 res = ast_play_and_wait(chan, "vm-novou");
07911 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07912 res = ast_play_and_wait(chan, "vm-nove");
07913 if (vms->newmessages > 4)
07914 res = ast_play_and_wait(chan, "vm-novych");
07915 }
07916 if (vms->oldmessages && !res)
07917 res = ast_play_and_wait(chan, "vm-and");
07918 else if (!res) {
07919 if ((vms->newmessages == 1))
07920 res = ast_play_and_wait(chan, "vm-zpravu");
07921 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07922 res = ast_play_and_wait(chan, "vm-zpravy");
07923 if (vms->newmessages > 4)
07924 res = ast_play_and_wait(chan, "vm-zprav");
07925 }
07926 }
07927 if (!res && vms->oldmessages) {
07928 res = say_and_wait(chan, vms->oldmessages, chan->language);
07929 if (!res) {
07930 if ((vms->oldmessages == 1))
07931 res = ast_play_and_wait(chan, "vm-starou");
07932 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07933 res = ast_play_and_wait(chan, "vm-stare");
07934 if (vms->oldmessages > 4)
07935 res = ast_play_and_wait(chan, "vm-starych");
07936 }
07937 if (!res) {
07938 if ((vms->oldmessages == 1))
07939 res = ast_play_and_wait(chan, "vm-zpravu");
07940 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07941 res = ast_play_and_wait(chan, "vm-zpravy");
07942 if (vms->oldmessages > 4)
07943 res = ast_play_and_wait(chan, "vm-zprav");
07944 }
07945 }
07946 if (!res) {
07947 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07948 res = ast_play_and_wait(chan, "vm-no");
07949 if (!res)
07950 res = ast_play_and_wait(chan, "vm-zpravy");
07951 }
07952 }
07953 }
07954 return res;
07955 }
07956
07957
07958 static int vm_intro_tw(struct ast_channel *chan, struct vm_state *vms)
07959 {
07960 int res;
07961
07962 res = ast_play_and_wait(chan, "vm-you");
07963
07964 if (!res && vms->newmessages) {
07965 res = ast_play_and_wait(chan, "vm-have");
07966 if (!res)
07967 res = say_and_wait(chan, vms->newmessages, chan->language);
07968 if (!res)
07969 res = ast_play_and_wait(chan, "vm-tong");
07970 if (!res)
07971 res = ast_play_and_wait(chan, "vm-INBOX");
07972 if (vms->oldmessages && !res)
07973 res = ast_play_and_wait(chan, "vm-and");
07974 else if (!res)
07975 res = ast_play_and_wait(chan, "vm-messages");
07976 }
07977 if (!res && vms->oldmessages) {
07978 res = ast_play_and_wait(chan, "vm-have");
07979 if (!res)
07980 res = say_and_wait(chan, vms->oldmessages, chan->language);
07981 if (!res)
07982 res = ast_play_and_wait(chan, "vm-tong");
07983 if (!res)
07984 res = ast_play_and_wait(chan, "vm-Old");
07985 if (!res)
07986 res = ast_play_and_wait(chan, "vm-messages");
07987 }
07988 if (!res && !vms->oldmessages && !vms->newmessages) {
07989 res = ast_play_and_wait(chan, "vm-haveno");
07990 if (!res)
07991 res = ast_play_and_wait(chan, "vm-messages");
07992 }
07993 return res;
07994 }
07995
07996 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07997 {
07998 char prefile[256];
07999
08000
08001 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08002 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08003 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08004 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08005 ast_play_and_wait(chan, "vm-tempgreetactive");
08006 }
08007 DISPOSE(prefile, -1);
08008 }
08009
08010
08011 if (!strcasecmp(chan->language, "de")) {
08012 return vm_intro_de(chan, vms);
08013 } else if (!strcasecmp(chan->language, "es")) {
08014 return vm_intro_es(chan, vms);
08015 } else if (!strcasecmp(chan->language, "it")) {
08016 return vm_intro_it(chan, vms);
08017 } else if (!strcasecmp(chan->language, "fr")) {
08018 return vm_intro_fr(chan, vms);
08019 } else if (!strcasecmp(chan->language, "nl")) {
08020 return vm_intro_nl(chan, vms);
08021 } else if (!strcasecmp(chan->language, "pt")) {
08022 return vm_intro_pt(chan, vms);
08023 } else if (!strcasecmp(chan->language, "pt_BR")) {
08024 return vm_intro_pt_BR(chan, vms);
08025 } else if (!strcasecmp(chan->language, "cz")) {
08026 return vm_intro_cz(chan, vms);
08027 } else if (!strcasecmp(chan->language, "gr")) {
08028 return vm_intro_gr(chan, vms);
08029 } else if (!strcasecmp(chan->language, "pl")) {
08030 return vm_intro_pl(chan, vms);
08031 } else if (!strcasecmp(chan->language, "se")) {
08032 return vm_intro_se(chan, vms);
08033 } else if (!strcasecmp(chan->language, "no")) {
08034 return vm_intro_no(chan, vms);
08035 } else if (!strcasecmp(chan->language, "ru")) {
08036 return vm_intro_multilang(chan, vms, "n");
08037 } else if (!strcasecmp(chan->language, "tw")) {
08038 return vm_intro_tw(chan, vms);
08039 } else if (!strcasecmp(chan->language, "ua")) {
08040 return vm_intro_multilang(chan, vms, "n");
08041 } else if (!strcasecmp(chan->language, "he")) {
08042 return vm_intro_he(chan, vms);
08043 } else {
08044 return vm_intro_en(chan, vms);
08045 }
08046 }
08047
08048 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08049 {
08050 int res = 0;
08051
08052 while (!res) {
08053 if (vms->starting) {
08054 if (vms->lastmsg > -1) {
08055 if (skipadvanced)
08056 res = ast_play_and_wait(chan, "vm-onefor-full");
08057 else
08058 res = ast_play_and_wait(chan, "vm-onefor");
08059 if (!res)
08060 res = vm_play_folder_name(chan, vms->vmbox);
08061 }
08062 if (!res) {
08063 if (skipadvanced)
08064 res = ast_play_and_wait(chan, "vm-opts-full");
08065 else
08066 res = ast_play_and_wait(chan, "vm-opts");
08067 }
08068 } else {
08069
08070 if (skipadvanced) {
08071 res = ast_play_and_wait(chan, "vm-onefor-full");
08072 if (!res)
08073 res = vm_play_folder_name(chan, vms->vmbox);
08074 res = ast_play_and_wait(chan, "vm-opts-full");
08075 }
08076
08077
08078
08079
08080
08081
08082 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08083 res = ast_play_and_wait(chan, "vm-prev");
08084 }
08085 if (!res && !skipadvanced)
08086 res = ast_play_and_wait(chan, "vm-advopts");
08087 if (!res)
08088 res = ast_play_and_wait(chan, "vm-repeat");
08089
08090
08091
08092
08093
08094
08095 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08096 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08097 res = ast_play_and_wait(chan, "vm-next");
08098 }
08099 if (!res) {
08100 if (!vms->deleted[vms->curmsg])
08101 res = ast_play_and_wait(chan, "vm-delete");
08102 else
08103 res = ast_play_and_wait(chan, "vm-undelete");
08104 if (!res)
08105 res = ast_play_and_wait(chan, "vm-toforward");
08106 if (!res)
08107 res = ast_play_and_wait(chan, "vm-savemessage");
08108 }
08109 }
08110 if (!res) {
08111 if (skipadvanced)
08112 res = ast_play_and_wait(chan, "vm-helpexit-full");
08113 else
08114 res = ast_play_and_wait(chan, "vm-helpexit");
08115 }
08116 if (!res)
08117 res = ast_waitfordigit(chan, 6000);
08118 if (!res) {
08119 vms->repeats++;
08120 if (vms->repeats > 2) {
08121 res = 't';
08122 }
08123 }
08124 }
08125 return res;
08126 }
08127
08128 static int vm_instructions_tw(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08129 {
08130 int res = 0;
08131
08132 while (!res) {
08133 if (vms->lastmsg > -1) {
08134 res = ast_play_and_wait(chan, "vm-listen");
08135 if (!res)
08136 res = vm_play_folder_name(chan, vms->vmbox);
08137 if (!res)
08138 res = ast_play_and_wait(chan, "press");
08139 if (!res)
08140 res = ast_play_and_wait(chan, "digits/1");
08141 }
08142 if (!res)
08143 res = ast_play_and_wait(chan, "vm-opts");
08144 if (!res) {
08145 vms->starting = 0;
08146 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08147 }
08148 }
08149 return res;
08150 }
08151
08152 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08153 {
08154 if (vms->starting && !strcasecmp(chan->language, "tw")) {
08155 return vm_instructions_tw(chan, vmu, vms, skipadvanced, in_urgent);
08156 } else {
08157 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08158 }
08159 }
08160
08161
08162 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08163 {
08164 int cmd = 0;
08165 int duration = 0;
08166 int tries = 0;
08167 char newpassword[80] = "";
08168 char newpassword2[80] = "";
08169 char prefile[PATH_MAX] = "";
08170 unsigned char buf[256];
08171 int bytes=0;
08172
08173 if (ast_adsi_available(chan)) {
08174 bytes += adsi_logo(buf + bytes);
08175 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
08176 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08177 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08178 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08179 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08180 }
08181
08182
08183
08184 for (;;) {
08185 newpassword[1] = '\0';
08186 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08187 if (cmd == '#')
08188 newpassword[0] = '\0';
08189 if (cmd < 0 || cmd == 't' || cmd == '#')
08190 return cmd;
08191 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
08192 if (cmd < 0 || cmd == 't' || cmd == '#')
08193 return cmd;
08194 cmd = check_password(vmu, newpassword);
08195 if (cmd != 0) {
08196 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08197 cmd = ast_play_and_wait(chan, vm_invalid_password);
08198 } else {
08199 newpassword2[1] = '\0';
08200 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08201 if (cmd == '#')
08202 newpassword2[0] = '\0';
08203 if (cmd < 0 || cmd == 't' || cmd == '#')
08204 return cmd;
08205 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
08206 if (cmd < 0 || cmd == 't' || cmd == '#')
08207 return cmd;
08208 if (!strcmp(newpassword, newpassword2))
08209 break;
08210 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08211 cmd = ast_play_and_wait(chan, vm_mismatch);
08212 }
08213 if (++tries == 3)
08214 return -1;
08215 }
08216 if (pwdchange & PWDCHANGE_INTERNAL)
08217 vm_change_password(vmu, newpassword);
08218 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08219 vm_change_password_shell(vmu, newpassword);
08220
08221 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08222 cmd = ast_play_and_wait(chan, vm_passchanged);
08223
08224
08225 if (ast_test_flag(vmu, VM_FORCENAME)) {
08226 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08227 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08228 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08229 if (cmd < 0 || cmd == 't' || cmd == '#')
08230 return cmd;
08231 }
08232 }
08233
08234
08235 if (ast_test_flag(vmu, VM_FORCEGREET)) {
08236 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08237 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08238 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08239 if (cmd < 0 || cmd == 't' || cmd == '#')
08240 return cmd;
08241 }
08242
08243 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08244 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08245 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08246 if (cmd < 0 || cmd == 't' || cmd == '#')
08247 return cmd;
08248 }
08249 }
08250
08251 return cmd;
08252 }
08253
08254 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08255 {
08256 int cmd = 0;
08257 int retries = 0;
08258 int duration = 0;
08259 char newpassword[80] = "";
08260 char newpassword2[80] = "";
08261 char prefile[PATH_MAX] = "";
08262 unsigned char buf[256];
08263 int bytes=0;
08264
08265 if (ast_adsi_available(chan)) {
08266 bytes += adsi_logo(buf + bytes);
08267 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
08268 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08269 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08270 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08271 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08272 }
08273 while ((cmd >= 0) && (cmd != 't')) {
08274 if (cmd)
08275 retries = 0;
08276 switch (cmd) {
08277 case '1':
08278 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08279 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08280 break;
08281 case '2':
08282 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08283 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08284 break;
08285 case '3':
08286 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08287 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08288 break;
08289 case '4':
08290 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
08291 break;
08292 case '5':
08293 if (vmu->password[0] == '-') {
08294 cmd = ast_play_and_wait(chan, "vm-no");
08295 break;
08296 }
08297 newpassword[1] = '\0';
08298 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08299 if (cmd == '#')
08300 newpassword[0] = '\0';
08301 else {
08302 if (cmd < 0)
08303 break;
08304 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
08305 break;
08306 }
08307 }
08308 cmd = check_password(vmu, newpassword);
08309 if (cmd != 0) {
08310 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08311 cmd = ast_play_and_wait(chan, vm_invalid_password);
08312 break;
08313 }
08314 newpassword2[1] = '\0';
08315 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08316 if (cmd == '#')
08317 newpassword2[0] = '\0';
08318 else {
08319 if (cmd < 0)
08320 break;
08321
08322 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
08323 break;
08324 }
08325 }
08326 if (strcmp(newpassword, newpassword2)) {
08327 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08328 cmd = ast_play_and_wait(chan, vm_mismatch);
08329 break;
08330 }
08331 if (pwdchange & PWDCHANGE_INTERNAL)
08332 vm_change_password(vmu, newpassword);
08333 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08334 vm_change_password_shell(vmu, newpassword);
08335
08336 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08337 cmd = ast_play_and_wait(chan, vm_passchanged);
08338 break;
08339 case '*':
08340 cmd = 't';
08341 break;
08342 default:
08343 cmd = 0;
08344 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08345 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08346 if (ast_fileexists(prefile, NULL, NULL)) {
08347 cmd = ast_play_and_wait(chan, "vm-tmpexists");
08348 }
08349 DISPOSE(prefile, -1);
08350 if (!cmd) {
08351 cmd = ast_play_and_wait(chan, "vm-options");
08352 }
08353 if (!cmd) {
08354 cmd = ast_waitfordigit(chan,6000);
08355 }
08356 if (!cmd) {
08357 retries++;
08358 }
08359 if (retries > 3) {
08360 cmd = 't';
08361 }
08362 }
08363 }
08364 if (cmd == 't')
08365 cmd = 0;
08366 return cmd;
08367 }
08368
08369
08370
08371
08372
08373
08374
08375
08376
08377
08378
08379
08380
08381
08382
08383
08384
08385 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08386 {
08387 int cmd = 0;
08388 int retries = 0;
08389 int duration = 0;
08390 char prefile[PATH_MAX] = "";
08391 unsigned char buf[256];
08392 int bytes = 0;
08393
08394 if (ast_adsi_available(chan)) {
08395 bytes += adsi_logo(buf + bytes);
08396 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
08397 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08398 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08399 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08400 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08401 }
08402
08403 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08404 while ((cmd >= 0) && (cmd != 't')) {
08405 if (cmd)
08406 retries = 0;
08407 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08408 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
08409 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08410 cmd = 't';
08411 } else {
08412 switch (cmd) {
08413 case '1':
08414 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08415 break;
08416 case '2':
08417 DELETE(prefile, -1, prefile, vmu);
08418 ast_play_and_wait(chan, "vm-tempremoved");
08419 cmd = 't';
08420 break;
08421 case '*':
08422 cmd = 't';
08423 break;
08424 default:
08425 cmd = ast_play_and_wait(chan,
08426 ast_fileexists(prefile, NULL, NULL) > 0 ?
08427 "vm-tempgreeting2" : "vm-tempgreeting");
08428 if (!cmd)
08429 cmd = ast_waitfordigit(chan,6000);
08430 if (!cmd)
08431 retries++;
08432 if (retries > 3)
08433 cmd = 't';
08434 }
08435 }
08436 DISPOSE(prefile, -1);
08437 }
08438 if (cmd == 't')
08439 cmd = 0;
08440 return cmd;
08441 }
08442
08443
08444
08445
08446
08447
08448
08449
08450
08451 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08452 {
08453 int cmd=0;
08454
08455 if (vms->lastmsg > -1) {
08456 cmd = play_message(chan, vmu, vms);
08457 } else {
08458 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08459 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
08460 if (!cmd) {
08461 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
08462 cmd = ast_play_and_wait(chan, vms->fn);
08463 }
08464 if (!cmd)
08465 cmd = ast_play_and_wait(chan, "vm-messages");
08466 } else {
08467 if (!cmd)
08468 cmd = ast_play_and_wait(chan, "vm-messages");
08469 if (!cmd) {
08470 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08471 cmd = ast_play_and_wait(chan, vms->fn);
08472 }
08473 }
08474 }
08475 return cmd;
08476 }
08477
08478
08479 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08480 {
08481 int cmd = 0;
08482
08483 if (vms->lastmsg > -1) {
08484 cmd = play_message(chan, vmu, vms);
08485 } else {
08486 if (!strcasecmp(vms->fn, "INBOX")) {
08487 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
08488 } else {
08489 cmd = ast_play_and_wait(chan, "vm-nomessages");
08490 }
08491 }
08492 return cmd;
08493 }
08494
08495
08496
08497
08498
08499
08500
08501
08502
08503 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08504 {
08505 int cmd=0;
08506
08507 if (vms->lastmsg > -1) {
08508 cmd = play_message(chan, vmu, vms);
08509 } else {
08510 cmd = ast_play_and_wait(chan, "vm-youhave");
08511 if (!cmd)
08512 cmd = ast_play_and_wait(chan, "vm-no");
08513 if (!cmd) {
08514 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08515 cmd = ast_play_and_wait(chan, vms->fn);
08516 }
08517 if (!cmd)
08518 cmd = ast_play_and_wait(chan, "vm-messages");
08519 }
08520 return cmd;
08521 }
08522
08523
08524
08525
08526
08527
08528
08529
08530
08531 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08532 {
08533 int cmd=0;
08534
08535 if (vms->lastmsg > -1) {
08536 cmd = play_message(chan, vmu, vms);
08537 } else {
08538 cmd = ast_play_and_wait(chan, "vm-no");
08539 if (!cmd)
08540 cmd = ast_play_and_wait(chan, "vm-message");
08541 if (!cmd) {
08542 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08543 cmd = ast_play_and_wait(chan, vms->fn);
08544 }
08545 }
08546 return cmd;
08547 }
08548
08549
08550
08551
08552
08553
08554
08555
08556
08557 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08558 {
08559 int cmd=0;
08560
08561 if (vms->lastmsg > -1) {
08562 cmd = play_message(chan, vmu, vms);
08563 } else {
08564 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08565 if (!cmd)
08566 cmd = ast_play_and_wait(chan, "vm-messages");
08567 if (!cmd) {
08568 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08569 cmd = ast_play_and_wait(chan, vms->fn);
08570 }
08571 }
08572 return cmd;
08573 }
08574
08575
08576
08577
08578
08579
08580
08581
08582
08583 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08584 {
08585 int cmd=0;
08586
08587 if (vms->lastmsg > -1) {
08588 cmd = play_message(chan, vmu, vms);
08589 } else {
08590 cmd = ast_play_and_wait(chan, "vm-no");
08591 if (!cmd) {
08592 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08593 cmd = ast_play_and_wait(chan, vms->fn);
08594 }
08595 if (!cmd)
08596 cmd = ast_play_and_wait(chan, "vm-messages");
08597 }
08598 return cmd;
08599 }
08600
08601
08602
08603
08604
08605
08606
08607
08608
08609 static int vm_browse_messages_tw(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08610 {
08611 int cmd=0;
08612
08613 if (vms->lastmsg > -1) {
08614 cmd = play_message(chan, vmu, vms);
08615 } else {
08616 cmd = ast_play_and_wait(chan, "vm-you");
08617 if (!cmd)
08618 cmd = ast_play_and_wait(chan, "vm-haveno");
08619 if (!cmd)
08620 cmd = ast_play_and_wait(chan, "vm-messages");
08621 if (!cmd) {
08622 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08623 cmd = ast_play_and_wait(chan, vms->fn);
08624 }
08625 }
08626 return cmd;
08627 }
08628
08629
08630
08631
08632
08633
08634
08635
08636
08637
08638
08639
08640 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08641 {
08642 if (!strcasecmp(chan->language, "es")) {
08643 return vm_browse_messages_es(chan, vms, vmu);
08644 } else if (!strcasecmp(chan->language, "it")) {
08645 return vm_browse_messages_it(chan, vms, vmu);
08646 } else if (!strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) {
08647 return vm_browse_messages_pt(chan, vms, vmu);
08648 } else if (!strcasecmp(chan->language, "gr")){
08649 return vm_browse_messages_gr(chan, vms, vmu);
08650 } else if (!strcasecmp(chan->language, "tw")){
08651 return vm_browse_messages_tw(chan, vms, vmu);
08652 } else if (!strcasecmp(chan->language, "he")) {
08653 return vm_browse_messages_he(chan, vms, vmu);
08654 } else {
08655 return vm_browse_messages_en(chan, vms, vmu);
08656 }
08657 }
08658
08659 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
08660 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
08661 int skipuser, int max_logins, int silent)
08662 {
08663 int useadsi=0, valid=0, logretries=0;
08664 char password[AST_MAX_EXTENSION]="", *passptr;
08665 struct ast_vm_user vmus, *vmu = NULL;
08666
08667
08668 adsi_begin(chan, &useadsi);
08669 if (!skipuser && useadsi)
08670 adsi_login(chan);
08671 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
08672 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
08673 return -1;
08674 }
08675
08676
08677
08678 while (!valid && (logretries < max_logins)) {
08679
08680 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
08681 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
08682 return -1;
08683 }
08684 if (ast_strlen_zero(mailbox)) {
08685 if (chan->cid.cid_num) {
08686 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
08687 } else {
08688 ast_verb(3,"Username not entered\n");
08689 return -1;
08690 }
08691 }
08692 if (useadsi)
08693 adsi_password(chan);
08694
08695 if (!ast_strlen_zero(prefix)) {
08696 char fullusername[80] = "";
08697 ast_copy_string(fullusername, prefix, sizeof(fullusername));
08698 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
08699 ast_copy_string(mailbox, fullusername, mailbox_size);
08700 }
08701
08702 ast_debug(1, "Before find user for mailbox %s\n",mailbox);
08703 vmu = find_user(&vmus, context, mailbox);
08704 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
08705
08706 password[0] = '\0';
08707 } else {
08708 if (ast_streamfile(chan, vm_password, chan->language)) {
08709 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
08710 return -1;
08711 }
08712 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
08713 ast_log(AST_LOG_WARNING, "Unable to read password\n");
08714 return -1;
08715 }
08716 }
08717
08718 if (vmu) {
08719 passptr = vmu->password;
08720 if (passptr[0] == '-') passptr++;
08721 }
08722 if (vmu && !strcmp(passptr, password))
08723 valid++;
08724 else {
08725 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
08726 if (!ast_strlen_zero(prefix))
08727 mailbox[0] = '\0';
08728 }
08729 logretries++;
08730 if (!valid) {
08731 if (skipuser || logretries >= max_logins) {
08732 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
08733 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
08734 return -1;
08735 }
08736 } else {
08737 if (useadsi)
08738 adsi_login(chan);
08739 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
08740 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
08741 return -1;
08742 }
08743 }
08744 if (ast_waitstream(chan, ""))
08745 return -1;
08746 }
08747 }
08748 if (!valid && (logretries >= max_logins)) {
08749 ast_stopstream(chan);
08750 ast_play_and_wait(chan, "vm-goodbye");
08751 return -1;
08752 }
08753 if (vmu && !skipuser) {
08754 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
08755 }
08756 return 0;
08757 }
08758
08759 static int vm_execmain(struct ast_channel *chan, void *data)
08760 {
08761
08762
08763
08764 int res=-1;
08765 int cmd=0;
08766 int valid = 0;
08767 char prefixstr[80] ="";
08768 char ext_context[256]="";
08769 int box;
08770 int useadsi = 0;
08771 int skipuser = 0;
08772 struct vm_state vms;
08773 struct ast_vm_user *vmu = NULL, vmus;
08774 char *context=NULL;
08775 int silentexit = 0;
08776 struct ast_flags flags = { 0 };
08777 signed char record_gain = 0;
08778 int play_auto = 0;
08779 int play_folder = 0;
08780 int in_urgent = 0;
08781 #ifdef IMAP_STORAGE
08782 int deleted = 0;
08783 #endif
08784
08785
08786 memset(&vms, 0, sizeof(vms));
08787
08788 vms.lastmsg = -1;
08789
08790 memset(&vmus, 0, sizeof(vmus));
08791
08792 if (chan->_state != AST_STATE_UP) {
08793 ast_debug(1, "Before ast_answer\n");
08794 ast_answer(chan);
08795 }
08796
08797 if (!ast_strlen_zero(data)) {
08798 char *opts[OPT_ARG_ARRAY_SIZE];
08799 char *parse;
08800 AST_DECLARE_APP_ARGS(args,
08801 AST_APP_ARG(argv0);
08802 AST_APP_ARG(argv1);
08803 );
08804
08805 parse = ast_strdupa(data);
08806
08807 AST_STANDARD_APP_ARGS(args, parse);
08808
08809 if (args.argc == 2) {
08810 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
08811 return -1;
08812 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
08813 int gain;
08814 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
08815 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
08816 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
08817 return -1;
08818 } else {
08819 record_gain = (signed char) gain;
08820 }
08821 } else {
08822 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
08823 }
08824 }
08825 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
08826 play_auto = 1;
08827 if (opts[OPT_ARG_PLAYFOLDER]) {
08828 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%d", &play_folder) != 1) {
08829 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
08830 }
08831 } else {
08832 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
08833 }
08834 if ( play_folder > 9 || play_folder < 0) {
08835 ast_log(AST_LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
08836 play_folder = 0;
08837 }
08838 }
08839 } else {
08840
08841 while (*(args.argv0)) {
08842 if (*(args.argv0) == 's')
08843 ast_set_flag(&flags, OPT_SILENT);
08844 else if (*(args.argv0) == 'p')
08845 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
08846 else
08847 break;
08848 (args.argv0)++;
08849 }
08850
08851 }
08852
08853 valid = ast_test_flag(&flags, OPT_SILENT);
08854
08855 if ((context = strchr(args.argv0, '@')))
08856 *context++ = '\0';
08857
08858 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
08859 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
08860 else
08861 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
08862
08863 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
08864 skipuser++;
08865 else
08866 valid = 0;
08867 }
08868
08869 if (!valid)
08870 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
08871
08872 ast_debug(1, "After vm_authenticate\n");
08873 if (!res) {
08874 valid = 1;
08875 if (!skipuser)
08876 vmu = &vmus;
08877 } else {
08878 res = 0;
08879 }
08880
08881
08882 adsi_begin(chan, &useadsi);
08883
08884 #ifdef IMAP_STORAGE
08885 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
08886 pthread_setspecific(ts_vmstate.key, &vms);
08887
08888 vms.interactive = 1;
08889 vms.updated = 1;
08890 if (vmu)
08891 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
08892 vmstate_insert(&vms);
08893 init_vm_state(&vms);
08894 #endif
08895 if (!valid)
08896 goto out;
08897
08898 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
08899 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
08900 cmd = ast_play_and_wait(chan, "an-error-has-occured");
08901 return -1;
08902 }
08903 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
08904 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
08905 cmd = ast_play_and_wait(chan, "an-error-has-occured");
08906 return -1;
08907 }
08908
08909
08910 if (!ast_strlen_zero(vmu->language))
08911 ast_string_field_set(chan, language, vmu->language);
08912
08913
08914 ast_debug(1, "Before open_mailbox\n");
08915 res = open_mailbox(&vms, vmu, OLD_FOLDER);
08916 if (res == ERROR_LOCK_PATH)
08917 goto out;
08918 vms.oldmessages = vms.lastmsg + 1;
08919 ast_debug(1, "Number of old messages: %d\n",vms.oldmessages);
08920
08921 res = open_mailbox(&vms, vmu, NEW_FOLDER);
08922 if (res == ERROR_LOCK_PATH)
08923 goto out;
08924 vms.newmessages = vms.lastmsg + 1;
08925 ast_debug(1, "Number of new messages: %d\n",vms.newmessages);
08926
08927 in_urgent = 1;
08928 res = open_mailbox(&vms, vmu, 11);
08929 if (res == ERROR_LOCK_PATH)
08930 goto out;
08931 vms.urgentmessages = vms.lastmsg + 1;
08932 ast_debug(1, "Number of urgent messages: %d\n",vms.urgentmessages);
08933
08934
08935 if (play_auto) {
08936 if (vms.urgentmessages) {
08937 in_urgent = 1;
08938 res = open_mailbox(&vms, vmu, 11);
08939 } else {
08940 in_urgent = 0;
08941 res = open_mailbox(&vms, vmu, play_folder);
08942 }
08943 if (res == ERROR_LOCK_PATH)
08944 goto out;
08945
08946
08947 if (vms.lastmsg == -1) {
08948 in_urgent = 0;
08949 cmd = vm_browse_messages(chan, &vms, vmu);
08950 res = 0;
08951 goto out;
08952 }
08953 } else {
08954 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
08955
08956 res = open_mailbox(&vms, vmu, OLD_FOLDER);
08957 in_urgent = 0;
08958 play_folder = 1;
08959 if (res == ERROR_LOCK_PATH)
08960 goto out;
08961 } else if (!vms.urgentmessages && vms.newmessages) {
08962
08963 in_urgent = 0;
08964 res = open_mailbox(&vms, vmu, NEW_FOLDER);
08965 if (res == ERROR_LOCK_PATH)
08966 goto out;
08967 }
08968 }
08969
08970 if (useadsi)
08971 adsi_status(chan, &vms);
08972 res = 0;
08973
08974
08975 if (!strcasecmp(vmu->mailbox, vmu->password) &&
08976 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
08977 if (ast_play_and_wait(chan, "vm-newuser") == -1)
08978 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
08979 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
08980 if ((cmd == 't') || (cmd == '#')) {
08981
08982 res = 0;
08983 goto out;
08984 } else if (cmd < 0) {
08985
08986 res = -1;
08987 goto out;
08988 }
08989 }
08990 #ifdef IMAP_STORAGE
08991 ast_debug(3, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
08992 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
08993 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
08994 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
08995 }
08996 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
08997 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
08998 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
08999 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09000 }
09001 #endif
09002 if (play_auto) {
09003 cmd = '1';
09004 } else {
09005 cmd = vm_intro(chan, vmu, &vms);
09006 }
09007
09008 vms.repeats = 0;
09009 vms.starting = 1;
09010 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09011
09012 switch (cmd) {
09013 case '1':
09014 vms.curmsg = 0;
09015
09016 case '5':
09017 cmd = vm_browse_messages(chan, &vms, vmu);
09018 break;
09019 case '2':
09020 if (useadsi)
09021 adsi_folders(chan, 0, "Change to folder...");
09022 cmd = get_folder2(chan, "vm-changeto", 0);
09023 if (cmd == '#') {
09024 cmd = 0;
09025 } else if (cmd > 0) {
09026 cmd = cmd - '0';
09027 res = close_mailbox(&vms, vmu);
09028 if (res == ERROR_LOCK_PATH)
09029 goto out;
09030
09031 if (cmd != 11) in_urgent = 0;
09032 res = open_mailbox(&vms, vmu, cmd);
09033 if (res == ERROR_LOCK_PATH)
09034 goto out;
09035 play_folder = cmd;
09036 cmd = 0;
09037 }
09038 if (useadsi)
09039 adsi_status2(chan, &vms);
09040
09041 if (!cmd)
09042 cmd = vm_play_folder_name(chan, vms.vmbox);
09043
09044 vms.starting = 1;
09045 break;
09046 case '3':
09047 cmd = 0;
09048 vms.repeats = 0;
09049 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09050 switch (cmd) {
09051 case '1':
09052 if (vms.lastmsg > -1 && !vms.starting) {
09053 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09054 if (cmd == ERROR_LOCK_PATH) {
09055 res = cmd;
09056 goto out;
09057 }
09058 } else
09059 cmd = ast_play_and_wait(chan, "vm-sorry");
09060 cmd = 't';
09061 break;
09062 case '2':
09063 if (!vms.starting)
09064 ast_verb(3, "Callback Requested\n");
09065 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09066 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09067 if (cmd == 9) {
09068 silentexit = 1;
09069 goto out;
09070 } else if (cmd == ERROR_LOCK_PATH) {
09071 res = cmd;
09072 goto out;
09073 }
09074 } else
09075 cmd = ast_play_and_wait(chan, "vm-sorry");
09076 cmd = 't';
09077 break;
09078 case '3':
09079 if (vms.lastmsg > -1 && !vms.starting) {
09080 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09081 if (cmd == ERROR_LOCK_PATH) {
09082 res = cmd;
09083 goto out;
09084 }
09085 } else
09086 cmd = ast_play_and_wait(chan, "vm-sorry");
09087 cmd = 't';
09088 break;
09089 case '4':
09090 if (!ast_strlen_zero(vmu->dialout)) {
09091 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09092 if (cmd == 9) {
09093 silentexit = 1;
09094 goto out;
09095 }
09096 } else
09097 cmd = ast_play_and_wait(chan, "vm-sorry");
09098 cmd = 't';
09099 break;
09100
09101 case '5':
09102 if (ast_test_flag(vmu, VM_SVMAIL)) {
09103 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
09104 if (cmd == ERROR_LOCK_PATH) {
09105 res = cmd;
09106 ast_log(AST_LOG_WARNING, "forward_message failed to lock path.\n");
09107 goto out;
09108 }
09109 } else
09110 cmd = ast_play_and_wait(chan,"vm-sorry");
09111 cmd='t';
09112 break;
09113
09114 case '*':
09115 cmd = 't';
09116 break;
09117
09118 default:
09119 cmd = 0;
09120 if (!vms.starting) {
09121 cmd = ast_play_and_wait(chan, "vm-toreply");
09122 }
09123 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
09124 cmd = ast_play_and_wait(chan, "vm-tocallback");
09125 }
09126 if (!cmd && !vms.starting) {
09127 cmd = ast_play_and_wait(chan, "vm-tohearenv");
09128 }
09129 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
09130 cmd = ast_play_and_wait(chan, "vm-tomakecall");
09131 }
09132 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
09133 cmd=ast_play_and_wait(chan, "vm-leavemsg");
09134 if (!cmd)
09135 cmd = ast_play_and_wait(chan, "vm-starmain");
09136 if (!cmd)
09137 cmd = ast_waitfordigit(chan,6000);
09138 if (!cmd)
09139 vms.repeats++;
09140 if (vms.repeats > 3)
09141 cmd = 't';
09142 }
09143 }
09144 if (cmd == 't') {
09145 cmd = 0;
09146 vms.repeats = 0;
09147 }
09148 break;
09149 case '4':
09150 if (vms.curmsg > 0) {
09151 vms.curmsg--;
09152 cmd = play_message(chan, vmu, &vms);
09153 } else {
09154
09155
09156
09157
09158 if (in_urgent == 0 && vms.urgentmessages > 0) {
09159
09160 in_urgent = 1;
09161 res = close_mailbox(&vms, vmu);
09162 if (res == ERROR_LOCK_PATH)
09163 goto out;
09164 res = open_mailbox(&vms, vmu, 11);
09165 if (res == ERROR_LOCK_PATH)
09166 goto out;
09167 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n",vms.lastmsg + 1);
09168 vms.curmsg = vms.lastmsg;
09169 if (vms.lastmsg < 0)
09170 cmd = ast_play_and_wait(chan, "vm-nomore");
09171 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09172 vms.curmsg = vms.lastmsg;
09173 cmd = play_message(chan, vmu, &vms);
09174 } else {
09175 cmd = ast_play_and_wait(chan, "vm-nomore");
09176 }
09177 }
09178 break;
09179 case '6':
09180 if (vms.curmsg < vms.lastmsg) {
09181 vms.curmsg++;
09182 cmd = play_message(chan, vmu, &vms);
09183 } else {
09184 if (in_urgent && vms.newmessages > 0) {
09185
09186
09187
09188
09189 in_urgent = 0;
09190 res = close_mailbox(&vms, vmu);
09191 if (res == ERROR_LOCK_PATH)
09192 goto out;
09193 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09194 if (res == ERROR_LOCK_PATH)
09195 goto out;
09196 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09197 vms.curmsg = -1;
09198 if (vms.lastmsg < 0) {
09199 cmd = ast_play_and_wait(chan, "vm-nomore");
09200 }
09201 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09202 vms.curmsg = 0;
09203 cmd = play_message(chan, vmu, &vms);
09204 } else {
09205 cmd = ast_play_and_wait(chan, "vm-nomore");
09206 }
09207 }
09208 break;
09209 case '7':
09210 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
09211 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
09212 if (useadsi)
09213 adsi_delete(chan, &vms);
09214 if (vms.deleted[vms.curmsg]) {
09215 if (play_folder == 0) {
09216 if (in_urgent) {
09217 vms.urgentmessages--;
09218 } else {
09219 vms.newmessages--;
09220 }
09221 }
09222 else if (play_folder == 1)
09223 vms.oldmessages--;
09224 cmd = ast_play_and_wait(chan, "vm-deleted");
09225 } else {
09226 if (play_folder == 0) {
09227 if (in_urgent) {
09228 vms.urgentmessages++;
09229 } else {
09230 vms.newmessages++;
09231 }
09232 }
09233 else if (play_folder == 1)
09234 vms.oldmessages++;
09235 cmd = ast_play_and_wait(chan, "vm-undeleted");
09236 }
09237 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09238 if (vms.curmsg < vms.lastmsg) {
09239 vms.curmsg++;
09240 cmd = play_message(chan, vmu, &vms);
09241 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09242 vms.curmsg = 0;
09243 cmd = play_message(chan, vmu, &vms);
09244 } else {
09245
09246
09247
09248
09249 if (in_urgent == 1) {
09250
09251 in_urgent = 0;
09252 res = close_mailbox(&vms, vmu);
09253 if (res == ERROR_LOCK_PATH)
09254 goto out;
09255 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09256 if (res == ERROR_LOCK_PATH)
09257 goto out;
09258 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09259 vms.curmsg = -1;
09260 if (vms.lastmsg < 0)
09261 cmd = ast_play_and_wait(chan, "vm-nomore");
09262 } else {
09263 cmd = ast_play_and_wait(chan, "vm-nomore");
09264 }
09265 }
09266 }
09267 } else
09268 cmd = 0;
09269 #ifdef IMAP_STORAGE
09270 deleted = 1;
09271 #endif
09272 break;
09273
09274 case '8':
09275 if (vms.lastmsg > -1) {
09276 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
09277 if (cmd == ERROR_LOCK_PATH) {
09278 res = cmd;
09279 goto out;
09280 }
09281 } else {
09282
09283
09284
09285
09286 if (in_urgent == 1 && vms.newmessages > 0) {
09287
09288 in_urgent = 0;
09289 res = close_mailbox(&vms, vmu);
09290 if (res == ERROR_LOCK_PATH)
09291 goto out;
09292 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09293 if (res == ERROR_LOCK_PATH)
09294 goto out;
09295 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09296 vms.curmsg = -1;
09297 if (vms.lastmsg < 0)
09298 cmd = ast_play_and_wait(chan, "vm-nomore");
09299 } else {
09300 cmd = ast_play_and_wait(chan, "vm-nomore");
09301 }
09302 }
09303 break;
09304 case '9':
09305 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
09306
09307 cmd = 0;
09308 break;
09309 }
09310 if (useadsi)
09311 adsi_folders(chan, 1, "Save to folder...");
09312 cmd = get_folder2(chan, "vm-savefolder", 1);
09313 box = 0;
09314 if (cmd == '#') {
09315 cmd = 0;
09316 break;
09317 } else if (cmd > 0) {
09318 box = cmd = cmd - '0';
09319 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
09320 if (cmd == ERROR_LOCK_PATH) {
09321 res = cmd;
09322 goto out;
09323 #ifndef IMAP_STORAGE
09324 } else if (!cmd) {
09325 vms.deleted[vms.curmsg] = 1;
09326 #endif
09327 } else {
09328 vms.deleted[vms.curmsg] = 0;
09329 vms.heard[vms.curmsg] = 0;
09330 }
09331 }
09332 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
09333 if (useadsi)
09334 adsi_message(chan, &vms);
09335 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
09336 if (!cmd) {
09337 cmd = ast_play_and_wait(chan, "vm-message");
09338 if (!cmd)
09339 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
09340 if (!cmd)
09341 cmd = ast_play_and_wait(chan, "vm-savedto");
09342 if (!cmd)
09343 cmd = vm_play_folder_name(chan, vms.fn);
09344 } else {
09345 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09346 }
09347 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09348 if (vms.curmsg < vms.lastmsg) {
09349 vms.curmsg++;
09350 cmd = play_message(chan, vmu, &vms);
09351 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09352 vms.curmsg = 0;
09353 cmd = play_message(chan, vmu, &vms);
09354 } else {
09355
09356
09357
09358
09359 if (in_urgent == 1 && vms.newmessages > 0) {
09360
09361 in_urgent = 0;
09362 res = close_mailbox(&vms, vmu);
09363 if (res == ERROR_LOCK_PATH)
09364 goto out;
09365 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09366 if (res == ERROR_LOCK_PATH)
09367 goto out;
09368 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09369 vms.curmsg = -1;
09370 if (vms.lastmsg < 0)
09371 cmd = ast_play_and_wait(chan, "vm-nomore");
09372 } else {
09373 cmd = ast_play_and_wait(chan, "vm-nomore");
09374 }
09375 }
09376 }
09377 break;
09378 case '*':
09379 if (!vms.starting) {
09380 cmd = ast_play_and_wait(chan, "vm-onefor");
09381 if (!cmd)
09382 cmd = vm_play_folder_name(chan, vms.vmbox);
09383 if (!cmd)
09384 cmd = ast_play_and_wait(chan, "vm-opts");
09385 if (!cmd)
09386 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
09387 } else
09388 cmd = 0;
09389 break;
09390 case '0':
09391 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
09392 if (useadsi)
09393 adsi_status(chan, &vms);
09394 break;
09395 default:
09396 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
09397 break;
09398 }
09399 }
09400 if ((cmd == 't') || (cmd == '#')) {
09401
09402 res = 0;
09403 } else {
09404
09405 res = -1;
09406 }
09407
09408 out:
09409 if (res > -1) {
09410 ast_stopstream(chan);
09411 adsi_goodbye(chan);
09412 if (valid) {
09413 if (silentexit)
09414 res = ast_play_and_wait(chan, "vm-dialout");
09415 else
09416 res = ast_play_and_wait(chan, "vm-goodbye");
09417 if (res > 0)
09418 res = 0;
09419 }
09420 if (useadsi)
09421 ast_adsi_unload_session(chan);
09422 }
09423 if (vmu)
09424 close_mailbox(&vms, vmu);
09425 if (valid) {
09426 int new = 0, old = 0, urgent = 0;
09427 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
09428 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
09429
09430 run_externnotify(vmu->context, vmu->mailbox, NULL);
09431 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
09432 queue_mwi_event(ext_context, urgent, new, old);
09433 }
09434 #ifdef IMAP_STORAGE
09435
09436 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
09437 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
09438 ast_mutex_lock(&vms.lock);
09439 #ifdef HAVE_IMAP_TK2006
09440 if (LEVELUIDPLUS (vms.mailstream)) {
09441 mail_expunge_full(vms.mailstream,NIL,EX_UID);
09442 } else
09443 #endif
09444 mail_expunge(vms.mailstream);
09445 ast_mutex_unlock(&vms.lock);
09446 }
09447
09448
09449 vmstate_delete(&vms);
09450 #endif
09451 if (vmu)
09452 free_user(vmu);
09453 if (vms.deleted)
09454 ast_free(vms.deleted);
09455 if (vms.heard)
09456 ast_free(vms.heard);
09457
09458 #ifdef IMAP_STORAGE
09459 pthread_setspecific(ts_vmstate.key, NULL);
09460 #endif
09461 return res;
09462 }
09463
09464 static int vm_exec(struct ast_channel *chan, void *data)
09465 {
09466 int res = 0;
09467 char *tmp;
09468 struct leave_vm_options leave_options;
09469 struct ast_flags flags = { 0 };
09470 char *opts[OPT_ARG_ARRAY_SIZE];
09471 AST_DECLARE_APP_ARGS(args,
09472 AST_APP_ARG(argv0);
09473 AST_APP_ARG(argv1);
09474 );
09475
09476 memset(&leave_options, 0, sizeof(leave_options));
09477
09478 if (chan->_state != AST_STATE_UP)
09479 ast_answer(chan);
09480
09481 if (!ast_strlen_zero(data)) {
09482 tmp = ast_strdupa(data);
09483 AST_STANDARD_APP_ARGS(args, tmp);
09484 if (args.argc == 2) {
09485 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09486 return -1;
09487 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
09488 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09489 int gain;
09490
09491 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
09492 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09493 return -1;
09494 } else {
09495 leave_options.record_gain = (signed char) gain;
09496 }
09497 }
09498 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
09499 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
09500 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
09501 }
09502 }
09503 } else {
09504 char temp[256];
09505 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
09506 if (res < 0)
09507 return res;
09508 if (ast_strlen_zero(temp))
09509 return 0;
09510 args.argv0 = ast_strdupa(temp);
09511 }
09512
09513 res = leave_voicemail(chan, args.argv0, &leave_options);
09514
09515 if (res == ERROR_LOCK_PATH) {
09516 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
09517 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
09518 res = 0;
09519 }
09520
09521 return res;
09522 }
09523
09524 static struct ast_vm_user *find_or_create(const char *context, const char *box)
09525 {
09526 struct ast_vm_user *vmu;
09527
09528 AST_LIST_TRAVERSE(&users, vmu, list) {
09529 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
09530 if (strcasecmp(vmu->context, context)) {
09531 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
09532 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
09533 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
09534 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
09535 }
09536 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
09537 return NULL;
09538 }
09539 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
09540 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
09541 return NULL;
09542 }
09543 }
09544
09545 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
09546 return NULL;
09547
09548 ast_copy_string(vmu->context, context, sizeof(vmu->context));
09549 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
09550
09551 AST_LIST_INSERT_TAIL(&users, vmu, list);
09552
09553 return vmu;
09554 }
09555
09556 static int append_mailbox(const char *context, const char *box, const char *data)
09557 {
09558
09559 char *tmp;
09560 char *stringp;
09561 char *s;
09562 struct ast_vm_user *vmu;
09563 char *mailbox_full;
09564 int new = 0, old = 0, urgent = 0;
09565
09566 tmp = ast_strdupa(data);
09567
09568 if (!(vmu = find_or_create(context, box)))
09569 return -1;
09570
09571 populate_defaults(vmu);
09572
09573 stringp = tmp;
09574 if ((s = strsep(&stringp, ",")))
09575 ast_copy_string(vmu->password, s, sizeof(vmu->password));
09576 if (stringp && (s = strsep(&stringp, ",")))
09577 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
09578 if (stringp && (s = strsep(&stringp, ",")))
09579 ast_copy_string(vmu->email, s, sizeof(vmu->email));
09580 if (stringp && (s = strsep(&stringp, ",")))
09581 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
09582 if (stringp && (s = strsep(&stringp, ",")))
09583 apply_options(vmu, s);
09584
09585 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
09586 strcpy(mailbox_full, box);
09587 strcat(mailbox_full, "@");
09588 strcat(mailbox_full, context);
09589
09590 inboxcount2(mailbox_full, &urgent, &new, &old);
09591 queue_mwi_event(mailbox_full, urgent, new, old);
09592
09593 return 0;
09594 }
09595
09596 static int vm_box_exists(struct ast_channel *chan, void *data)
09597 {
09598 struct ast_vm_user svm;
09599 char *context, *box;
09600 AST_DECLARE_APP_ARGS(args,
09601 AST_APP_ARG(mbox);
09602 AST_APP_ARG(options);
09603 );
09604 static int dep_warning = 0;
09605
09606 if (ast_strlen_zero(data)) {
09607 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
09608 return -1;
09609 }
09610
09611 if (!dep_warning) {
09612 dep_warning = 1;
09613 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *)data);
09614 }
09615
09616 box = ast_strdupa(data);
09617
09618 AST_STANDARD_APP_ARGS(args, box);
09619
09620 if (args.options) {
09621 }
09622
09623 if ((context = strchr(args.mbox, '@'))) {
09624 *context = '\0';
09625 context++;
09626 }
09627
09628 if (find_user(&svm, context, args.mbox)) {
09629 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
09630 } else
09631 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
09632
09633 return 0;
09634 }
09635
09636 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
09637 {
09638 struct ast_vm_user svm;
09639 AST_DECLARE_APP_ARGS(arg,
09640 AST_APP_ARG(mbox);
09641 AST_APP_ARG(context);
09642 );
09643
09644 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
09645
09646 if (ast_strlen_zero(arg.mbox)) {
09647 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
09648 return -1;
09649 }
09650
09651 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
09652 return 0;
09653 }
09654
09655 static struct ast_custom_function mailbox_exists_acf = {
09656 .name = "MAILBOX_EXISTS",
09657 .synopsis = "Tell if a mailbox is configured",
09658 .desc =
09659 "Returns a boolean of whether the corresponding mailbox exists. If context\n"
09660 "is not specified, defaults to the \"default\" context.\n",
09661 .syntax = "MAILBOX_EXISTS(<vmbox>[@<context>])",
09662 .read = acf_mailbox_exists,
09663 };
09664
09665 static int vmauthenticate(struct ast_channel *chan, void *data)
09666 {
09667 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
09668 struct ast_vm_user vmus;
09669 char *options = NULL;
09670 int silent = 0, skipuser = 0;
09671 int res = -1;
09672
09673 if (s) {
09674 s = ast_strdupa(s);
09675 user = strsep(&s, ",");
09676 options = strsep(&s, ",");
09677 if (user) {
09678 s = user;
09679 user = strsep(&s, "@");
09680 context = strsep(&s, "");
09681 if (!ast_strlen_zero(user))
09682 skipuser++;
09683 ast_copy_string(mailbox, user, sizeof(mailbox));
09684 }
09685 }
09686
09687 if (options) {
09688 silent = (strchr(options, 's')) != NULL;
09689 }
09690
09691 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
09692 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
09693 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
09694 ast_play_and_wait(chan, "auth-thankyou");
09695 res = 0;
09696 }
09697
09698 return res;
09699 }
09700
09701 static char *show_users_realtime(int fd, const char *context)
09702 {
09703 struct ast_config *cfg;
09704 const char *cat = NULL;
09705
09706 if (!(cfg = ast_load_realtime_multientry("voicemail",
09707 "context", context, SENTINEL))) {
09708 return CLI_FAILURE;
09709 }
09710
09711 ast_cli(fd,
09712 "\n"
09713 "=============================================================\n"
09714 "=== Configured Voicemail Users ==============================\n"
09715 "=============================================================\n"
09716 "===\n");
09717
09718 while ((cat = ast_category_browse(cfg, cat))) {
09719 struct ast_variable *var = NULL;
09720 ast_cli(fd,
09721 "=== Mailbox ...\n"
09722 "===\n");
09723 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
09724 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
09725 ast_cli(fd,
09726 "===\n"
09727 "=== ---------------------------------------------------------\n"
09728 "===\n");
09729 }
09730
09731 ast_cli(fd,
09732 "=============================================================\n"
09733 "\n");
09734
09735 ast_config_destroy(cfg);
09736
09737 return CLI_SUCCESS;
09738 }
09739
09740 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
09741 {
09742 int which = 0;
09743 int wordlen;
09744 struct ast_vm_user *vmu;
09745 const char *context = "";
09746
09747
09748 if (pos > 4)
09749 return NULL;
09750 if (pos == 3)
09751 return (state == 0) ? ast_strdup("for") : NULL;
09752 wordlen = strlen(word);
09753 AST_LIST_TRAVERSE(&users, vmu, list) {
09754 if (!strncasecmp(word, vmu->context, wordlen)) {
09755 if (context && strcmp(context, vmu->context) && ++which > state)
09756 return ast_strdup(vmu->context);
09757
09758 context = vmu->context;
09759 }
09760 }
09761 return NULL;
09762 }
09763
09764
09765 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09766 {
09767 struct ast_vm_user *vmu;
09768 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
09769 const char *context = NULL;
09770 int users_counter = 0;
09771
09772 switch (cmd) {
09773 case CLI_INIT:
09774 e->command = "voicemail show users";
09775 e->usage =
09776 "Usage: voicemail show users [for <context>]\n"
09777 " Lists all mailboxes currently set up\n";
09778 return NULL;
09779 case CLI_GENERATE:
09780 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
09781 }
09782
09783 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
09784 return CLI_SHOWUSAGE;
09785 if (a->argc == 5) {
09786 if (strcmp(a->argv[3],"for"))
09787 return CLI_SHOWUSAGE;
09788 context = a->argv[4];
09789 }
09790
09791 if (ast_check_realtime("voicemail")) {
09792 if (!context) {
09793 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
09794 return CLI_SHOWUSAGE;
09795 }
09796 return show_users_realtime(a->fd, context);
09797 }
09798
09799 AST_LIST_LOCK(&users);
09800 if (AST_LIST_EMPTY(&users)) {
09801 ast_cli(a->fd, "There are no voicemail users currently defined\n");
09802 AST_LIST_UNLOCK(&users);
09803 return CLI_FAILURE;
09804 }
09805 if (a->argc == 3)
09806 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
09807 else {
09808 int count = 0;
09809 AST_LIST_TRAVERSE(&users, vmu, list) {
09810 if (!strcmp(context, vmu->context))
09811 count++;
09812 }
09813 if (count) {
09814 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
09815 } else {
09816 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
09817 AST_LIST_UNLOCK(&users);
09818 return CLI_FAILURE;
09819 }
09820 }
09821 AST_LIST_TRAVERSE(&users, vmu, list) {
09822 int newmsgs = 0, oldmsgs = 0;
09823 char count[12], tmp[256] = "";
09824
09825 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
09826 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
09827 inboxcount(tmp, &newmsgs, &oldmsgs);
09828 snprintf(count, sizeof(count), "%d", newmsgs);
09829 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
09830 users_counter++;
09831 }
09832 }
09833 AST_LIST_UNLOCK(&users);
09834 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
09835 return CLI_SUCCESS;
09836 }
09837
09838
09839 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09840 {
09841 struct vm_zone *zone;
09842 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
09843 char *res = CLI_SUCCESS;
09844
09845 switch (cmd) {
09846 case CLI_INIT:
09847 e->command = "voicemail show zones";
09848 e->usage =
09849 "Usage: voicemail show zones\n"
09850 " Lists zone message formats\n";
09851 return NULL;
09852 case CLI_GENERATE:
09853 return NULL;
09854 }
09855
09856 if (a->argc != 3)
09857 return CLI_SHOWUSAGE;
09858
09859 AST_LIST_LOCK(&zones);
09860 if (!AST_LIST_EMPTY(&zones)) {
09861 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
09862 AST_LIST_TRAVERSE(&zones, zone, list) {
09863 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
09864 }
09865 } else {
09866 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
09867 res = CLI_FAILURE;
09868 }
09869 AST_LIST_UNLOCK(&zones);
09870
09871 return res;
09872 }
09873
09874
09875 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09876 {
09877 switch (cmd) {
09878 case CLI_INIT:
09879 e->command = "voicemail reload";
09880 e->usage =
09881 "Usage: voicemail reload\n"
09882 " Reload voicemail configuration\n";
09883 return NULL;
09884 case CLI_GENERATE:
09885 return NULL;
09886 }
09887
09888 if (a->argc != 2)
09889 return CLI_SHOWUSAGE;
09890
09891 ast_cli(a->fd, "Reloading voicemail configuration...\n");
09892 load_config(1);
09893
09894 return CLI_SUCCESS;
09895 }
09896
09897 static struct ast_cli_entry cli_voicemail[] = {
09898 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
09899 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
09900 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
09901 };
09902
09903 static void poll_subscribed_mailboxes(void)
09904 {
09905 struct mwi_sub *mwi_sub;
09906
09907 AST_RWLIST_RDLOCK(&mwi_subs);
09908 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
09909 int new = 0, old = 0, urgent = 0;
09910
09911 if (ast_strlen_zero(mwi_sub->mailbox))
09912 continue;
09913
09914 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
09915
09916 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
09917 mwi_sub->old_urgent = urgent;
09918 mwi_sub->old_new = new;
09919 mwi_sub->old_old = old;
09920 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
09921 }
09922 }
09923 AST_RWLIST_UNLOCK(&mwi_subs);
09924 }
09925
09926 static void *mb_poll_thread(void *data)
09927 {
09928 while (poll_thread_run) {
09929 struct timespec ts = { 0, };
09930 struct timeval wait;
09931
09932 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
09933 ts.tv_sec = wait.tv_sec;
09934 ts.tv_nsec = wait.tv_usec * 1000;
09935
09936 ast_mutex_lock(&poll_lock);
09937 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
09938 ast_mutex_unlock(&poll_lock);
09939
09940 if (!poll_thread_run)
09941 break;
09942
09943 poll_subscribed_mailboxes();
09944 }
09945
09946 return NULL;
09947 }
09948
09949 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
09950 {
09951 ast_free(mwi_sub);
09952 }
09953
09954 static int handle_unsubscribe(void *datap)
09955 {
09956 struct mwi_sub *mwi_sub;
09957 uint32_t *uniqueid = datap;
09958
09959 AST_RWLIST_WRLOCK(&mwi_subs);
09960 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
09961 if (mwi_sub->uniqueid == *uniqueid) {
09962 AST_LIST_REMOVE_CURRENT(entry);
09963 break;
09964 }
09965 }
09966 AST_RWLIST_TRAVERSE_SAFE_END
09967 AST_RWLIST_UNLOCK(&mwi_subs);
09968
09969 if (mwi_sub)
09970 mwi_sub_destroy(mwi_sub);
09971
09972 ast_free(uniqueid);
09973 return 0;
09974 }
09975
09976 static int handle_subscribe(void *datap)
09977 {
09978 unsigned int len;
09979 struct mwi_sub *mwi_sub;
09980 struct mwi_sub_task *p = datap;
09981
09982 len = sizeof(*mwi_sub);
09983 if (!ast_strlen_zero(p->mailbox))
09984 len += strlen(p->mailbox);
09985
09986 if (!ast_strlen_zero(p->context))
09987 len += strlen(p->context) + 1;
09988
09989 if (!(mwi_sub = ast_calloc(1, len)))
09990 return -1;
09991
09992 mwi_sub->uniqueid = p->uniqueid;
09993 if (!ast_strlen_zero(p->mailbox))
09994 strcpy(mwi_sub->mailbox, p->mailbox);
09995
09996 if (!ast_strlen_zero(p->context)) {
09997 strcat(mwi_sub->mailbox, "@");
09998 strcat(mwi_sub->mailbox, p->context);
09999 }
10000
10001 AST_RWLIST_WRLOCK(&mwi_subs);
10002 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
10003 AST_RWLIST_UNLOCK(&mwi_subs);
10004 ast_free((void *) p->mailbox);
10005 ast_free((void *) p->context);
10006 ast_free(p);
10007 return 0;
10008 }
10009
10010 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
10011 {
10012 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
10013 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
10014 return;
10015
10016 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10017 return;
10018
10019 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10020 *uniqueid = u;
10021 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
10022 ast_free(uniqueid);
10023 }
10024 }
10025
10026 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
10027 {
10028 struct mwi_sub_task *mwist;
10029
10030 if (ast_event_get_type(event) != AST_EVENT_SUB)
10031 return;
10032
10033 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10034 return;
10035
10036 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
10037 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
10038 return;
10039 }
10040 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
10041 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
10042 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10043
10044 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
10045 ast_free(mwist);
10046 }
10047 }
10048
10049 static void start_poll_thread(void)
10050 {
10051 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
10052 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10053 AST_EVENT_IE_END);
10054
10055 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
10056 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10057 AST_EVENT_IE_END);
10058
10059 if (mwi_sub_sub)
10060 ast_event_report_subs(mwi_sub_sub);
10061
10062 poll_thread_run = 1;
10063
10064 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
10065 }
10066
10067 static void stop_poll_thread(void)
10068 {
10069 poll_thread_run = 0;
10070
10071 if (mwi_sub_sub) {
10072 ast_event_unsubscribe(mwi_sub_sub);
10073 mwi_sub_sub = NULL;
10074 }
10075
10076 if (mwi_unsub_sub) {
10077 ast_event_unsubscribe(mwi_unsub_sub);
10078 mwi_unsub_sub = NULL;
10079 }
10080
10081 ast_mutex_lock(&poll_lock);
10082 ast_cond_signal(&poll_cond);
10083 ast_mutex_unlock(&poll_lock);
10084
10085 pthread_join(poll_thread, NULL);
10086
10087 poll_thread = AST_PTHREADT_NULL;
10088 }
10089
10090
10091 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
10092 {
10093 struct ast_vm_user *vmu = NULL;
10094 const char *id = astman_get_header(m, "ActionID");
10095 char actionid[128] = "";
10096
10097 if (!ast_strlen_zero(id))
10098 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
10099
10100 AST_LIST_LOCK(&users);
10101
10102 if (AST_LIST_EMPTY(&users)) {
10103 astman_send_ack(s, m, "There are no voicemail users currently defined.");
10104 AST_LIST_UNLOCK(&users);
10105 return RESULT_SUCCESS;
10106 }
10107
10108 astman_send_ack(s, m, "Voicemail user list will follow");
10109
10110 AST_LIST_TRAVERSE(&users, vmu, list) {
10111 char dirname[256];
10112
10113 #ifdef IMAP_STORAGE
10114 int new, old;
10115 inboxcount(vmu->mailbox, &new, &old);
10116 #endif
10117
10118 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
10119 astman_append(s,
10120 "%s"
10121 "Event: VoicemailUserEntry\r\n"
10122 "VMContext: %s\r\n"
10123 "VoiceMailbox: %s\r\n"
10124 "Fullname: %s\r\n"
10125 "Email: %s\r\n"
10126 "Pager: %s\r\n"
10127 "ServerEmail: %s\r\n"
10128 "MailCommand: %s\r\n"
10129 "Language: %s\r\n"
10130 "TimeZone: %s\r\n"
10131 "Callback: %s\r\n"
10132 "Dialout: %s\r\n"
10133 "UniqueID: %s\r\n"
10134 "ExitContext: %s\r\n"
10135 "SayDurationMinimum: %d\r\n"
10136 "SayEnvelope: %s\r\n"
10137 "SayCID: %s\r\n"
10138 "AttachMessage: %s\r\n"
10139 "AttachmentFormat: %s\r\n"
10140 "DeleteMessage: %s\r\n"
10141 "VolumeGain: %.2f\r\n"
10142 "CanReview: %s\r\n"
10143 "CallOperator: %s\r\n"
10144 "MaxMessageCount: %d\r\n"
10145 "MaxMessageLength: %d\r\n"
10146 "NewMessageCount: %d\r\n"
10147 #ifdef IMAP_STORAGE
10148 "OldMessageCount: %d\r\n"
10149 "IMAPUser: %s\r\n"
10150 #endif
10151 "\r\n",
10152 actionid,
10153 vmu->context,
10154 vmu->mailbox,
10155 vmu->fullname,
10156 vmu->email,
10157 vmu->pager,
10158 vmu->serveremail,
10159 vmu->mailcmd,
10160 vmu->language,
10161 vmu->zonetag,
10162 vmu->callback,
10163 vmu->dialout,
10164 vmu->uniqueid,
10165 vmu->exit,
10166 vmu->saydurationm,
10167 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
10168 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
10169 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
10170 vmu->attachfmt,
10171 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
10172 vmu->volgain,
10173 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
10174 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
10175 vmu->maxmsg,
10176 vmu->maxsecs,
10177 #ifdef IMAP_STORAGE
10178 new, old, vmu->imapuser
10179 #else
10180 count_messages(vmu, dirname)
10181 #endif
10182 );
10183 }
10184 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
10185
10186 AST_LIST_UNLOCK(&users);
10187
10188 return RESULT_SUCCESS;
10189 }
10190
10191
10192 static void free_vm_users(void)
10193 {
10194 struct ast_vm_user *current;
10195 AST_LIST_LOCK(&users);
10196 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
10197 ast_set_flag(current, VM_ALLOCED);
10198 free_user(current);
10199 }
10200 AST_LIST_UNLOCK(&users);
10201 }
10202
10203
10204 static void free_vm_zones(void)
10205 {
10206 struct vm_zone *zcur;
10207 AST_LIST_LOCK(&zones);
10208 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
10209 free_zone(zcur);
10210 AST_LIST_UNLOCK(&zones);
10211 }
10212
10213 static char *substitute_escapes(const char *value)
10214 {
10215 char *current, *result;
10216
10217
10218 struct ast_str *str = ast_str_create(strlen(value) + 16);
10219
10220
10221 for (current = (char *) value; *current; current++) {
10222 if (*current == '\\') {
10223 current++;
10224 if (!*current) {
10225 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
10226 break;
10227 }
10228 switch (*current) {
10229 case 'r':
10230 ast_str_append(&str, 0, "\r");
10231 break;
10232 case 'n':
10233 #ifdef IMAP_STORAGE
10234 if (!str->used || str->str[str->used - 1] != '\r') {
10235 ast_str_append(&str, 0, "\r");
10236 }
10237 #endif
10238 ast_str_append(&str, 0, "\n");
10239 break;
10240 case 't':
10241 ast_str_append(&str, 0, "\t");
10242 break;
10243 default:
10244 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
10245 break;
10246 }
10247 } else {
10248 ast_str_append(&str, 0, "%c", *current);
10249 }
10250 }
10251
10252 result = ast_strdup(str->str);
10253 ast_free(str);
10254
10255 return result;
10256 }
10257
10258 static int load_config(int reload)
10259 {
10260 struct ast_vm_user *current;
10261 struct ast_config *cfg, *ucfg;
10262 char *cat;
10263 struct ast_variable *var;
10264 const char *val;
10265 char *q, *stringp;
10266 int x;
10267 int tmpadsi[4];
10268 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10269
10270 ast_unload_realtime("voicemail");
10271 ast_unload_realtime("voicemail_data");
10272
10273 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
10274 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
10275 return 0;
10276 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10277 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
10278 } else {
10279 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10280 ucfg = ast_config_load("users.conf", config_flags);
10281 }
10282 #ifdef IMAP_STORAGE
10283 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
10284 #endif
10285
10286 strcpy(listen_control_forward_key,DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
10287 strcpy(listen_control_reverse_key,DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
10288 strcpy(listen_control_pause_key,DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
10289 strcpy(listen_control_restart_key,DEFAULT_LISTEN_CONTROL_RESTART_KEY);
10290 strcpy(listen_control_stop_key,DEFAULT_LISTEN_CONTROL_STOP_KEY);
10291
10292
10293 free_vm_users();
10294
10295
10296 free_vm_zones();
10297
10298 AST_LIST_LOCK(&users);
10299
10300 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
10301 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
10302
10303 if (cfg) {
10304
10305
10306 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
10307 val = "default";
10308 ast_copy_string(userscontext, val, sizeof(userscontext));
10309
10310 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
10311 val = "yes";
10312 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
10313
10314 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
10315 val = "no";
10316 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
10317
10318 volgain = 0.0;
10319 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
10320 sscanf(val, "%lf", &volgain);
10321
10322 #ifdef ODBC_STORAGE
10323 strcpy(odbc_database, "asterisk");
10324 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
10325 ast_copy_string(odbc_database, val, sizeof(odbc_database));
10326 }
10327 strcpy(odbc_table, "voicemessages");
10328 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
10329 ast_copy_string(odbc_table, val, sizeof(odbc_table));
10330 }
10331 #endif
10332
10333 strcpy(mailcmd, SENDMAIL);
10334 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
10335 ast_copy_string(mailcmd, val, sizeof(mailcmd));
10336
10337 maxsilence = 0;
10338 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
10339 maxsilence = atoi(val);
10340 if (maxsilence > 0)
10341 maxsilence *= 1000;
10342 }
10343
10344 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
10345 maxmsg = MAXMSG;
10346 } else {
10347 maxmsg = atoi(val);
10348 if (maxmsg <= 0) {
10349 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
10350 maxmsg = MAXMSG;
10351 } else if (maxmsg > MAXMSGLIMIT) {
10352 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10353 maxmsg = MAXMSGLIMIT;
10354 }
10355 }
10356
10357 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
10358 maxdeletedmsg = 0;
10359 } else {
10360 if (sscanf(val, "%d", &x) == 1)
10361 maxdeletedmsg = x;
10362 else if (ast_true(val))
10363 maxdeletedmsg = MAXMSG;
10364 else
10365 maxdeletedmsg = 0;
10366
10367 if (maxdeletedmsg < 0) {
10368 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
10369 maxdeletedmsg = MAXMSG;
10370 } else if (maxdeletedmsg > MAXMSGLIMIT) {
10371 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10372 maxdeletedmsg = MAXMSGLIMIT;
10373 }
10374 }
10375
10376
10377 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
10378 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
10379 }
10380
10381
10382 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
10383 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10384 pwdchange = PWDCHANGE_EXTERNAL;
10385 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
10386 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10387 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
10388 }
10389
10390
10391 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
10392 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
10393 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
10394 }
10395
10396 #ifdef IMAP_STORAGE
10397
10398 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
10399 ast_copy_string(imapserver, val, sizeof(imapserver));
10400 } else {
10401 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
10402 }
10403
10404 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
10405 ast_copy_string(imapport, val, sizeof(imapport));
10406 } else {
10407 ast_copy_string(imapport,"143", sizeof(imapport));
10408 }
10409
10410 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
10411 ast_copy_string(imapflags, val, sizeof(imapflags));
10412 }
10413
10414 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
10415 ast_copy_string(authuser, val, sizeof(authuser));
10416 }
10417
10418 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
10419 ast_copy_string(authpassword, val, sizeof(authpassword));
10420 }
10421
10422 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
10423 if (ast_false(val))
10424 expungeonhangup = 0;
10425 else
10426 expungeonhangup = 1;
10427 } else {
10428 expungeonhangup = 1;
10429 }
10430
10431 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
10432 ast_copy_string(imapfolder, val, sizeof(imapfolder));
10433 } else {
10434 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
10435 }
10436 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
10437 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
10438 }
10439 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
10440 imapgreetings = ast_true(val);
10441 } else {
10442 imapgreetings = 0;
10443 }
10444 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
10445 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
10446 } else {
10447 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
10448 }
10449
10450
10451
10452
10453
10454 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
10455 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
10456 } else {
10457 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
10458 }
10459
10460 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
10461 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
10462 } else {
10463 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
10464 }
10465
10466 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
10467 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
10468 } else {
10469 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
10470 }
10471
10472 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
10473 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
10474 } else {
10475 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
10476 }
10477
10478 #endif
10479
10480 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
10481 ast_copy_string(externnotify, val, sizeof(externnotify));
10482 ast_debug(1, "found externnotify: %s\n", externnotify);
10483 } else {
10484 externnotify[0] = '\0';
10485 }
10486
10487
10488 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
10489 ast_debug(1, "Enabled SMDI voicemail notification\n");
10490 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
10491 smdi_iface = ast_smdi_interface_find(val);
10492 } else {
10493 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
10494 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
10495 }
10496 if (!smdi_iface) {
10497 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
10498 }
10499 }
10500
10501
10502 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
10503 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
10504 silencethreshold = atoi(val);
10505
10506 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
10507 val = ASTERISK_USERNAME;
10508 ast_copy_string(serveremail, val, sizeof(serveremail));
10509
10510 vmmaxsecs = 0;
10511 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
10512 if (sscanf(val, "%d", &x) == 1) {
10513 vmmaxsecs = x;
10514 } else {
10515 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10516 }
10517 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
10518 static int maxmessage_deprecate = 0;
10519 if (maxmessage_deprecate == 0) {
10520 maxmessage_deprecate = 1;
10521 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
10522 }
10523 if (sscanf(val, "%d", &x) == 1) {
10524 vmmaxsecs = x;
10525 } else {
10526 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10527 }
10528 }
10529
10530 vmminsecs = 0;
10531 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
10532 if (sscanf(val, "%d", &x) == 1) {
10533 vmminsecs = x;
10534 if (maxsilence <= vmminsecs)
10535 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10536 } else {
10537 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10538 }
10539 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
10540 static int maxmessage_deprecate = 0;
10541 if (maxmessage_deprecate == 0) {
10542 maxmessage_deprecate = 1;
10543 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
10544 }
10545 if (sscanf(val, "%d", &x) == 1) {
10546 vmminsecs = x;
10547 if (maxsilence <= vmminsecs)
10548 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10549 } else {
10550 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10551 }
10552 }
10553
10554 val = ast_variable_retrieve(cfg, "general", "format");
10555 if (!val)
10556 val = "wav";
10557 ast_copy_string(vmfmts, val, sizeof(vmfmts));
10558
10559 skipms = 3000;
10560 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
10561 if (sscanf(val, "%d", &x) == 1) {
10562 maxgreet = x;
10563 } else {
10564 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
10565 }
10566 }
10567
10568 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
10569 if (sscanf(val, "%d", &x) == 1) {
10570 skipms = x;
10571 } else {
10572 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
10573 }
10574 }
10575
10576 maxlogins = 3;
10577 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
10578 if (sscanf(val, "%d", &x) == 1) {
10579 maxlogins = x;
10580 } else {
10581 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
10582 }
10583 }
10584
10585 minpassword = MINPASSWORD;
10586 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
10587 if (sscanf(val, "%d", &x) == 1) {
10588 minpassword = x;
10589 } else {
10590 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
10591 }
10592 }
10593
10594
10595 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
10596 val = "no";
10597 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
10598
10599
10600 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
10601 val = "no";
10602 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
10603
10604 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
10605 ast_debug(1, "VM_CID Internal context string: %s\n", val);
10606 stringp = ast_strdupa(val);
10607 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
10608 if (!ast_strlen_zero(stringp)) {
10609 q = strsep(&stringp, ",");
10610 while ((*q == ' ')||(*q == '\t'))
10611 q++;
10612 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
10613 ast_debug(1,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
10614 } else {
10615 cidinternalcontexts[x][0] = '\0';
10616 }
10617 }
10618 }
10619 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
10620 ast_debug(1,"VM Review Option disabled globally\n");
10621 val = "no";
10622 }
10623 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
10624
10625
10626 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
10627 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
10628 val = "no";
10629 } else {
10630 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
10631 }
10632 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
10633 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
10634 ast_debug(1, "VM next message wrap disabled globally\n");
10635 val = "no";
10636 }
10637 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
10638
10639 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
10640 ast_debug(1,"VM Operator break disabled globally\n");
10641 val = "no";
10642 }
10643 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
10644
10645 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
10646 ast_debug(1,"VM CID Info before msg disabled globally\n");
10647 val = "no";
10648 }
10649 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
10650
10651 if (!(val = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
10652 ast_debug(1,"Send Voicemail msg disabled globally\n");
10653 val = "no";
10654 }
10655 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
10656
10657 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
10658 ast_debug(1,"ENVELOPE before msg enabled globally\n");
10659 val = "yes";
10660 }
10661 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
10662
10663 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
10664 ast_debug(1,"Move Heard enabled globally\n");
10665 val = "yes";
10666 }
10667 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
10668
10669 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
10670 ast_debug(1,"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
10671 val = "no";
10672 }
10673 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
10674
10675 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
10676 ast_debug(1,"Duration info before msg enabled globally\n");
10677 val = "yes";
10678 }
10679 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
10680
10681 saydurationminfo = 2;
10682 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
10683 if (sscanf(val, "%d", &x) == 1) {
10684 saydurationminfo = x;
10685 } else {
10686 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
10687 }
10688 }
10689
10690 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
10691 ast_debug(1,"We are not going to skip to the next msg after save/delete\n");
10692 val = "no";
10693 }
10694 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
10695
10696 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
10697 ast_copy_string(dialcontext, val, sizeof(dialcontext));
10698 ast_debug(1, "found dialout context: %s\n", dialcontext);
10699 } else {
10700 dialcontext[0] = '\0';
10701 }
10702
10703 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
10704 ast_copy_string(callcontext, val, sizeof(callcontext));
10705 ast_debug(1, "found callback context: %s\n", callcontext);
10706 } else {
10707 callcontext[0] = '\0';
10708 }
10709
10710 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
10711 ast_copy_string(exitcontext, val, sizeof(exitcontext));
10712 ast_debug(1, "found operator context: %s\n", exitcontext);
10713 } else {
10714 exitcontext[0] = '\0';
10715 }
10716
10717
10718 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
10719 ast_copy_string(vm_password, val, sizeof(vm_password));
10720 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
10721 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
10722 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
10723 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
10724 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
10725 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
10726 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
10727 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
10728 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
10729 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
10730
10731 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
10732 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
10733 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
10734 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
10735 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
10736 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
10737 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
10738 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
10739 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
10740 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
10741
10742 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
10743 val = "no";
10744 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
10745
10746 poll_freq = DEFAULT_POLL_FREQ;
10747 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
10748 if (sscanf(val, "%u", &poll_freq) != 1) {
10749 poll_freq = DEFAULT_POLL_FREQ;
10750 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
10751 }
10752 }
10753
10754 poll_mailboxes = 0;
10755 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
10756 poll_mailboxes = ast_true(val);
10757
10758 if (ucfg) {
10759 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
10760 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
10761 continue;
10762 if ((current = find_or_create(userscontext, cat))) {
10763 populate_defaults(current);
10764 apply_options_full(current, ast_variable_browse(ucfg, cat));
10765 ast_copy_string(current->context, userscontext, sizeof(current->context));
10766 }
10767 }
10768 ast_config_destroy(ucfg);
10769 }
10770 cat = ast_category_browse(cfg, NULL);
10771 while (cat) {
10772 if (strcasecmp(cat, "general")) {
10773 var = ast_variable_browse(cfg, cat);
10774 if (strcasecmp(cat, "zonemessages")) {
10775
10776 while (var) {
10777 append_mailbox(cat, var->name, var->value);
10778 var = var->next;
10779 }
10780 } else {
10781
10782 while (var) {
10783 struct vm_zone *z;
10784 if ((z = ast_malloc(sizeof(*z)))) {
10785 char *msg_format, *tzone;
10786 msg_format = ast_strdupa(var->value);
10787 tzone = strsep(&msg_format, "|");
10788 if (msg_format) {
10789 ast_copy_string(z->name, var->name, sizeof(z->name));
10790 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
10791 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
10792 AST_LIST_LOCK(&zones);
10793 AST_LIST_INSERT_HEAD(&zones, z, list);
10794 AST_LIST_UNLOCK(&zones);
10795 } else {
10796 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
10797 ast_free(z);
10798 }
10799 } else {
10800 AST_LIST_UNLOCK(&users);
10801 ast_config_destroy(cfg);
10802 return -1;
10803 }
10804 var = var->next;
10805 }
10806 }
10807 }
10808 cat = ast_category_browse(cfg, cat);
10809 }
10810 memset(fromstring, 0, sizeof(fromstring));
10811 memset(pagerfromstring, 0, sizeof(pagerfromstring));
10812 strcpy(charset, "ISO-8859-1");
10813 if (emailbody) {
10814 ast_free(emailbody);
10815 emailbody = NULL;
10816 }
10817 if (emailsubject) {
10818 ast_free(emailsubject);
10819 emailsubject = NULL;
10820 }
10821 if (pagerbody) {
10822 ast_free(pagerbody);
10823 pagerbody = NULL;
10824 }
10825 if (pagersubject) {
10826 ast_free(pagersubject);
10827 pagersubject = NULL;
10828 }
10829 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
10830 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
10831 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
10832 ast_copy_string(fromstring, val, sizeof(fromstring));
10833 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
10834 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
10835 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
10836 ast_copy_string(charset, val, sizeof(charset));
10837 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
10838 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
10839 for (x = 0; x < 4; x++) {
10840 memcpy(&adsifdn[x], &tmpadsi[x], 1);
10841 }
10842 }
10843 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
10844 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
10845 for (x = 0; x < 4; x++) {
10846 memcpy(&adsisec[x], &tmpadsi[x], 1);
10847 }
10848 }
10849 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
10850 if (atoi(val)) {
10851 adsiver = atoi(val);
10852 }
10853 }
10854 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
10855 ast_copy_string(zonetag, val, sizeof(zonetag));
10856 }
10857 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
10858 emailsubject = ast_strdup(val);
10859 }
10860 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
10861 emailbody = substitute_escapes(val);
10862 }
10863 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
10864 pagersubject = ast_strdup(val);
10865 }
10866 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
10867 pagerbody = substitute_escapes(val);
10868 }
10869 AST_LIST_UNLOCK(&users);
10870 ast_config_destroy(cfg);
10871
10872 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
10873 start_poll_thread();
10874 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
10875 stop_poll_thread();;
10876
10877 return 0;
10878 } else {
10879 AST_LIST_UNLOCK(&users);
10880 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
10881 if (ucfg)
10882 ast_config_destroy(ucfg);
10883 return 0;
10884 }
10885 }
10886
10887 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
10888 {
10889 int res = -1;
10890 char dir[PATH_MAX];
10891 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
10892 ast_debug(2, "About to try retrieving name file %s\n", dir);
10893 RETRIEVE(dir, -1, mailbox, context);
10894 if (ast_fileexists(dir, NULL, NULL)) {
10895 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
10896 }
10897 DISPOSE(dir, -1);
10898 return res;
10899 }
10900
10901 static int reload(void)
10902 {
10903 return load_config(1);
10904 }
10905
10906 static int unload_module(void)
10907 {
10908 int res;
10909
10910 res = ast_unregister_application(app);
10911 res |= ast_unregister_application(app2);
10912 res |= ast_unregister_application(app3);
10913 res |= ast_unregister_application(app4);
10914 res |= ast_custom_function_unregister(&mailbox_exists_acf);
10915 res |= ast_manager_unregister("VoicemailUsersList");
10916 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
10917 ast_uninstall_vm_functions();
10918
10919 if (poll_thread != AST_PTHREADT_NULL)
10920 stop_poll_thread();
10921
10922 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
10923 ast_unload_realtime("voicemail");
10924 ast_unload_realtime("voicemail_data");
10925
10926 free_vm_users();
10927 free_vm_zones();
10928 return res;
10929 }
10930
10931 static int load_module(void)
10932 {
10933 int res;
10934 my_umask = umask(0);
10935 umask(my_umask);
10936
10937
10938 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
10939
10940 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
10941 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
10942 }
10943
10944 if ((res = load_config(0)))
10945 return res;
10946
10947 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
10948 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
10949 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
10950 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
10951 res |= ast_custom_function_register(&mailbox_exists_acf);
10952 res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users, "List All Voicemail User Information");
10953 if (res)
10954 return res;
10955
10956 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
10957
10958 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
10959 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
10960 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
10961
10962 return res;
10963 }
10964
10965 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
10966 {
10967 int cmd = 0;
10968 char destination[80] = "";
10969 int retries = 0;
10970
10971 if (!num) {
10972 ast_verb(3, "Destination number will be entered manually\n");
10973 while (retries < 3 && cmd != 't') {
10974 destination[1] = '\0';
10975 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
10976 if (!cmd)
10977 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
10978 if (!cmd)
10979 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
10980 if (!cmd) {
10981 cmd = ast_waitfordigit(chan, 6000);
10982 if (cmd)
10983 destination[0] = cmd;
10984 }
10985 if (!cmd) {
10986 retries++;
10987 } else {
10988
10989 if (cmd < 0)
10990 return 0;
10991 if (cmd == '*') {
10992 ast_verb(3, "User hit '*' to cancel outgoing call\n");
10993 return 0;
10994 }
10995 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
10996 retries++;
10997 else
10998 cmd = 't';
10999 }
11000 }
11001 if (retries >= 3) {
11002 return 0;
11003 }
11004
11005 } else {
11006 if (option_verbose > 2)
11007 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
11008 ast_copy_string(destination, num, sizeof(destination));
11009 }
11010
11011 if (!ast_strlen_zero(destination)) {
11012 if (destination[strlen(destination) -1 ] == '*')
11013 return 0;
11014 if (option_verbose > 2)
11015 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
11016 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
11017 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
11018 chan->priority = 0;
11019 return 9;
11020 }
11021 return 0;
11022 }
11023
11024
11025
11026
11027
11028
11029
11030
11031
11032
11033
11034
11035
11036
11037 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)
11038 {
11039 int res = 0;
11040 char filename[PATH_MAX];
11041 struct ast_config *msg_cfg = NULL;
11042 const char *origtime, *context;
11043 char *name, *num;
11044 int retries = 0;
11045 char *cid;
11046 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
11047
11048 vms->starting = 0;
11049
11050 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11051
11052
11053 snprintf(filename,sizeof(filename), "%s.txt", vms->fn);
11054 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
11055 msg_cfg = ast_config_load(filename, config_flags);
11056 DISPOSE(vms->curdir, vms->curmsg);
11057 if (!msg_cfg) {
11058 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
11059 return 0;
11060 }
11061
11062 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
11063 ast_config_destroy(msg_cfg);
11064 return 0;
11065 }
11066
11067 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
11068
11069 context = ast_variable_retrieve(msg_cfg, "message", "context");
11070 if (!strncasecmp("macro",context,5))
11071 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
11072 switch (option) {
11073 case 3:
11074 if (!res)
11075 res = play_message_datetime(chan, vmu, origtime, filename);
11076 if (!res)
11077 res = play_message_callerid(chan, vms, cid, context, 0);
11078
11079 res = 't';
11080 break;
11081
11082 case 2:
11083
11084 if (ast_strlen_zero(cid))
11085 break;
11086
11087 ast_callerid_parse(cid, &name, &num);
11088 while ((res > -1) && (res != 't')) {
11089 switch (res) {
11090 case '1':
11091 if (num) {
11092
11093 res = dialout(chan, vmu, num, vmu->callback);
11094 if (res) {
11095 ast_config_destroy(msg_cfg);
11096 return 9;
11097 }
11098 } else {
11099 res = '2';
11100 }
11101 break;
11102
11103 case '2':
11104
11105 if (!ast_strlen_zero(vmu->dialout)) {
11106 res = dialout(chan, vmu, NULL, vmu->dialout);
11107 if (res) {
11108 ast_config_destroy(msg_cfg);
11109 return 9;
11110 }
11111 } else {
11112 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
11113 res = ast_play_and_wait(chan, "vm-sorry");
11114 }
11115 ast_config_destroy(msg_cfg);
11116 return res;
11117 case '*':
11118 res = 't';
11119 break;
11120 case '3':
11121 case '4':
11122 case '5':
11123 case '6':
11124 case '7':
11125 case '8':
11126 case '9':
11127 case '0':
11128
11129 res = ast_play_and_wait(chan, "vm-sorry");
11130 retries++;
11131 break;
11132 default:
11133 if (num) {
11134 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
11135 res = ast_play_and_wait(chan, "vm-num-i-have");
11136 if (!res)
11137 res = play_message_callerid(chan, vms, num, vmu->context, 1);
11138 if (!res)
11139 res = ast_play_and_wait(chan, "vm-tocallnum");
11140
11141 if (!ast_strlen_zero(vmu->dialout)) {
11142 if (!res)
11143 res = ast_play_and_wait(chan, "vm-calldiffnum");
11144 }
11145 } else {
11146 res = ast_play_and_wait(chan, "vm-nonumber");
11147 if (!ast_strlen_zero(vmu->dialout)) {
11148 if (!res)
11149 res = ast_play_and_wait(chan, "vm-toenternumber");
11150 }
11151 }
11152 if (!res)
11153 res = ast_play_and_wait(chan, "vm-star-cancel");
11154 if (!res)
11155 res = ast_waitfordigit(chan, 6000);
11156 if (!res) {
11157 retries++;
11158 if (retries > 3)
11159 res = 't';
11160 }
11161 break;
11162
11163 }
11164 if (res == 't')
11165 res = 0;
11166 else if (res == '*')
11167 res = -1;
11168 }
11169 break;
11170
11171 case 1:
11172
11173 if (ast_strlen_zero(cid))
11174 break;
11175
11176 ast_callerid_parse(cid, &name, &num);
11177 if (!num) {
11178 ast_verb(3, "No CID number available, no reply sent\n");
11179 if (!res)
11180 res = ast_play_and_wait(chan, "vm-nonumber");
11181 ast_config_destroy(msg_cfg);
11182 return res;
11183 } else {
11184 struct ast_vm_user vmu2;
11185 if (find_user(&vmu2, vmu->context, num)) {
11186 struct leave_vm_options leave_options;
11187 char mailbox[AST_MAX_EXTENSION * 2 + 2];
11188 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
11189
11190 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
11191
11192 memset(&leave_options, 0, sizeof(leave_options));
11193 leave_options.record_gain = record_gain;
11194 res = leave_voicemail(chan, mailbox, &leave_options);
11195 if (!res)
11196 res = 't';
11197 ast_config_destroy(msg_cfg);
11198 return res;
11199 } else {
11200
11201 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
11202 ast_play_and_wait(chan, "vm-nobox");
11203 res = 't';
11204 ast_config_destroy(msg_cfg);
11205 return res;
11206 }
11207 }
11208 res = 0;
11209
11210 break;
11211 }
11212
11213 #ifndef IMAP_STORAGE
11214 ast_config_destroy(msg_cfg);
11215
11216 if (!res) {
11217 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11218 vms->heard[msg] = 1;
11219 res = wait_file(chan, vms, vms->fn);
11220 }
11221 #endif
11222 return res;
11223 }
11224
11225 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
11226 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
11227 signed char record_gain, struct vm_state *vms, char *flag)
11228 {
11229
11230 int res = 0;
11231 int cmd = 0;
11232 int max_attempts = 3;
11233 int attempts = 0;
11234 int recorded = 0;
11235 int msg_exists = 0;
11236 signed char zero_gain = 0;
11237 char tempfile[PATH_MAX];
11238 char *acceptdtmf = "#";
11239 char *canceldtmf = "";
11240
11241
11242
11243
11244 if (duration == NULL) {
11245 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
11246 return -1;
11247 }
11248
11249 if (!outsidecaller)
11250 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
11251 else
11252 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
11253
11254 cmd = '3';
11255
11256 while ((cmd >= 0) && (cmd != 't')) {
11257 switch (cmd) {
11258 case '1':
11259 if (!msg_exists) {
11260
11261 cmd = '3';
11262 break;
11263 } else {
11264
11265 ast_verb(3, "Saving message as is\n");
11266 if (!outsidecaller)
11267 ast_filerename(tempfile, recordfile, NULL);
11268 ast_stream_and_wait(chan, "vm-msgsaved", "");
11269 if (!outsidecaller) {
11270
11271 #ifndef IMAP_STORAGE
11272 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
11273 DISPOSE(recordfile, -1);
11274 #endif
11275 }
11276 cmd = 't';
11277 return res;
11278 }
11279 case '2':
11280
11281 ast_verb(3, "Reviewing the message\n");
11282 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
11283 break;
11284 case '3':
11285 msg_exists = 0;
11286
11287 if (recorded == 1)
11288 ast_verb(3, "Re-recording the message\n");
11289 else
11290 ast_verb(3, "Recording the message\n");
11291
11292 if (recorded && outsidecaller) {
11293 cmd = ast_play_and_wait(chan, INTRO);
11294 cmd = ast_play_and_wait(chan, "beep");
11295 }
11296 recorded = 1;
11297
11298 if (record_gain)
11299 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
11300 if (ast_test_flag(vmu, VM_OPERATOR))
11301 canceldtmf = "0";
11302 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
11303 if (record_gain)
11304 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
11305 if (cmd == -1) {
11306
11307 if (!outsidecaller) {
11308
11309 ast_filedelete(tempfile, NULL);
11310 }
11311 return cmd;
11312 }
11313 if (cmd == '0') {
11314 break;
11315 } else if (cmd == '*') {
11316 break;
11317 #if 0
11318 } else if (vmu->review && (*duration < 5)) {
11319
11320 ast_verb(3, "Message too short\n");
11321 cmd = ast_play_and_wait(chan, "vm-tooshort");
11322 cmd = ast_filedelete(tempfile, NULL);
11323 break;
11324 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
11325
11326 ast_verb(3, "Nothing recorded\n");
11327 cmd = ast_filedelete(tempfile, NULL);
11328 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
11329 if (!cmd)
11330 cmd = ast_play_and_wait(chan, "vm-speakup");
11331 break;
11332 #endif
11333 } else {
11334
11335 msg_exists = 1;
11336 cmd = 0;
11337 }
11338 break;
11339 case '4':
11340 if (outsidecaller) {
11341
11342 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11343 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
11344 ast_debug(1000, "This message is too urgent!\n");
11345 res = ast_play_and_wait(chan, "vm-marked-urgent");
11346 strcpy(flag, "Urgent");
11347 } else if (flag) {
11348 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
11349 res = ast_play_and_wait(chan, "vm-urgent-removed");
11350 strcpy(flag, "");
11351 } else {
11352 ast_play_and_wait(chan, "vm-sorry");
11353 }
11354 cmd = 0;
11355 } else {
11356 cmd = ast_play_and_wait(chan, "vm-sorry");
11357 }
11358 break;
11359 case '5':
11360 case '6':
11361 case '7':
11362 case '8':
11363 case '9':
11364 case '*':
11365 case '#':
11366 cmd = ast_play_and_wait(chan, "vm-sorry");
11367 break;
11368 #if 0
11369
11370
11371 case '*':
11372
11373 cmd = ast_play_and_wait(chan, "vm-deleted");
11374 cmd = ast_filedelete(tempfile, NULL);
11375 if (outsidecaller) {
11376 res = vm_exec(chan, NULL);
11377 return res;
11378 }
11379 else
11380 return 1;
11381 #endif
11382 case '0':
11383 if (!ast_test_flag(vmu, VM_OPERATOR)) {
11384 cmd = ast_play_and_wait(chan, "vm-sorry");
11385 break;
11386 }
11387 if (msg_exists || recorded) {
11388 cmd = ast_play_and_wait(chan, "vm-saveoper");
11389 if (!cmd)
11390 cmd = ast_waitfordigit(chan, 3000);
11391 if (cmd == '1') {
11392 ast_play_and_wait(chan, "vm-msgsaved");
11393 cmd = '0';
11394 } else if (cmd == '4') {
11395 if (flag) {
11396 ast_play_and_wait(chan, "vm-marked-urgent");
11397 strcpy(flag, "Urgent");
11398 }
11399 ast_play_and_wait(chan, "vm-msgsaved");
11400 cmd = '0';
11401 } else {
11402 ast_play_and_wait(chan, "vm-deleted");
11403 DELETE(recordfile, -1, recordfile, vmu);
11404 cmd = '0';
11405 }
11406 }
11407 return cmd;
11408 default:
11409
11410
11411
11412 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
11413 return cmd;
11414 if (msg_exists) {
11415 cmd = ast_play_and_wait(chan, "vm-review");
11416 if (!cmd && outsidecaller) {
11417 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11418 cmd = ast_play_and_wait(chan, "vm-review-urgent");
11419 } else if (flag) {
11420 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
11421 }
11422 }
11423 } else {
11424 cmd = ast_play_and_wait(chan, "vm-torerecord");
11425 if (!cmd)
11426 cmd = ast_waitfordigit(chan, 600);
11427 }
11428
11429 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
11430 cmd = ast_play_and_wait(chan, "vm-reachoper");
11431 if (!cmd)
11432 cmd = ast_waitfordigit(chan, 600);
11433 }
11434 #if 0
11435 if (!cmd)
11436 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
11437 #endif
11438 if (!cmd)
11439 cmd = ast_waitfordigit(chan, 6000);
11440 if (!cmd) {
11441 attempts++;
11442 }
11443 if (attempts > max_attempts) {
11444 cmd = 't';
11445 }
11446 }
11447 }
11448 if (outsidecaller)
11449 ast_play_and_wait(chan, "vm-goodbye");
11450 if (cmd == 't')
11451 cmd = 0;
11452 return cmd;
11453 }
11454
11455
11456
11457
11458
11459 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
11460 .load = load_module,
11461 .unload = unload_module,
11462 .reload = reload,
11463 );