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