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
00072
00073 #include "asterisk.h"
00074
00075 #ifdef IMAP_STORAGE
00076 #include <ctype.h>
00077 #include <signal.h>
00078 #include <pwd.h>
00079 #ifdef USE_SYSTEM_IMAP
00080 #include <imap/c-client.h>
00081 #include <imap/imap4r1.h>
00082 #include <imap/linkage.h>
00083 #elif defined (USE_SYSTEM_CCLIENT)
00084 #include <c-client/c-client.h>
00085 #include <c-client/imap4r1.h>
00086 #include <c-client/linkage.h>
00087 #else
00088 #include "c-client.h"
00089 #include "imap4r1.h"
00090 #include "linkage.h"
00091 #endif
00092 #endif
00093
00094 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 401743 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 #ifdef IMAP_STORAGE
00375 static char imapserver[48];
00376 static char imapport[8];
00377 static char imapflags[128];
00378 static char imapfolder[64];
00379 static char imapparentfolder[64] = "\0";
00380 static char greetingfolder[64];
00381 static char authuser[32];
00382 static char authpassword[42];
00383 static int imapversion = 1;
00384
00385 static int expungeonhangup = 1;
00386 static int imapgreetings = 0;
00387 static char delimiter = '\0';
00388
00389 struct vm_state;
00390 struct ast_vm_user;
00391
00392 AST_THREADSTORAGE(ts_vmstate);
00393
00394
00395 static int init_mailstream(struct vm_state *vms, int box);
00396 static void write_file(char *filename, char *buffer, unsigned long len);
00397 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00398 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00399 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00400 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00401 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00402 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00403 static void vmstate_insert(struct vm_state *vms);
00404 static void vmstate_delete(struct vm_state *vms);
00405 static void set_update(MAILSTREAM * stream);
00406 static void init_vm_state(struct vm_state *vms);
00407 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00408 static void get_mailbox_delimiter(MAILSTREAM *stream);
00409 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00410 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00411 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00412 static void update_messages_by_imapuser(const char *user, unsigned long number);
00413 static int vm_delete(char *file);
00414
00415 static int imap_remove_file (char *dir, int msgnum);
00416 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00417 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00418 static void check_quota(struct vm_state *vms, char *mailbox);
00419 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00420 struct vmstate {
00421 struct vm_state *vms;
00422 AST_LIST_ENTRY(vmstate) list;
00423 };
00424
00425 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00426
00427 #endif
00428
00429 #define SMDI_MWI_WAIT_TIMEOUT 1000
00430
00431 #define COMMAND_TIMEOUT 5000
00432
00433 #define VOICEMAIL_DIR_MODE 0777
00434 #define VOICEMAIL_FILE_MODE 0666
00435 #define CHUNKSIZE 65536
00436
00437 #define VOICEMAIL_CONFIG "voicemail.conf"
00438 #define ASTERISK_USERNAME "asterisk"
00439
00440
00441
00442
00443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00448 #define VALID_DTMF "1234567890*#"
00449
00450
00451
00452 #define SENDMAIL "/usr/sbin/sendmail -t"
00453
00454 #define INTRO "vm-intro"
00455
00456 #define MAXMSG 100
00457 #define MAXMSGLIMIT 9999
00458
00459 #define MINPASSWORD 0
00460
00461 #define BASELINELEN 72
00462 #define BASEMAXINLINE 256
00463 #ifdef IMAP_STORAGE
00464 #define ENDL "\r\n"
00465 #else
00466 #define ENDL "\n"
00467 #endif
00468
00469 #define MAX_DATETIME_FORMAT 512
00470 #define MAX_NUM_CID_CONTEXTS 10
00471
00472 #define VM_REVIEW (1 << 0)
00473 #define VM_OPERATOR (1 << 1)
00474 #define VM_SAYCID (1 << 2)
00475 #define VM_SVMAIL (1 << 3)
00476 #define VM_ENVELOPE (1 << 4)
00477 #define VM_SAYDURATION (1 << 5)
00478 #define VM_SKIPAFTERCMD (1 << 6)
00479 #define VM_FORCENAME (1 << 7)
00480 #define VM_FORCEGREET (1 << 8)
00481 #define VM_PBXSKIP (1 << 9)
00482 #define VM_DIRECFORWARD (1 << 10)
00483 #define VM_ATTACH (1 << 11)
00484 #define VM_DELETE (1 << 12)
00485 #define VM_ALLOCED (1 << 13)
00486 #define VM_SEARCH (1 << 14)
00487 #define VM_TEMPGREETWARN (1 << 15)
00488 #define VM_MOVEHEARD (1 << 16)
00489 #define VM_MESSAGEWRAP (1 << 17)
00490 #define VM_FWDURGAUTO (1 << 18)
00491 #define ERROR_LOCK_PATH -100
00492 #define OPERATOR_EXIT 300
00493
00494
00495 enum vm_box {
00496 NEW_FOLDER,
00497 OLD_FOLDER,
00498 WORK_FOLDER,
00499 FAMILY_FOLDER,
00500 FRIENDS_FOLDER,
00501 GREETINGS_FOLDER
00502 };
00503
00504 enum vm_option_flags {
00505 OPT_SILENT = (1 << 0),
00506 OPT_BUSY_GREETING = (1 << 1),
00507 OPT_UNAVAIL_GREETING = (1 << 2),
00508 OPT_RECORDGAIN = (1 << 3),
00509 OPT_PREPEND_MAILBOX = (1 << 4),
00510 OPT_AUTOPLAY = (1 << 6),
00511 OPT_DTMFEXIT = (1 << 7),
00512 OPT_MESSAGE_Urgent = (1 << 8),
00513 OPT_MESSAGE_PRIORITY = (1 << 9)
00514 };
00515
00516 enum vm_option_args {
00517 OPT_ARG_RECORDGAIN = 0,
00518 OPT_ARG_PLAYFOLDER = 1,
00519 OPT_ARG_DTMFEXIT = 2,
00520
00521 OPT_ARG_ARRAY_SIZE = 3,
00522 };
00523
00524 enum vm_passwordlocation {
00525 OPT_PWLOC_VOICEMAILCONF = 0,
00526 OPT_PWLOC_SPOOLDIR = 1,
00527 OPT_PWLOC_USERSCONF = 2,
00528 };
00529
00530 AST_APP_OPTIONS(vm_app_options, {
00531 AST_APP_OPTION('s', OPT_SILENT),
00532 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00533 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00534 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00535 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00536 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00537 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00538 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00539 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00540 });
00541
00542 static int load_config(int reload);
00543 #ifdef TEST_FRAMEWORK
00544 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00545 #endif
00546 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 struct baseio {
00632 int iocp;
00633 int iolen;
00634 int linelength;
00635 int ateof;
00636 unsigned char iobuf[BASEMAXINLINE];
00637 };
00638
00639
00640
00641 struct ast_vm_user {
00642 char context[AST_MAX_CONTEXT];
00643 char mailbox[AST_MAX_EXTENSION];
00644 char password[80];
00645 char fullname[80];
00646 char email[80];
00647 char *emailsubject;
00648 char *emailbody;
00649 char pager[80];
00650 char serveremail[80];
00651 char language[MAX_LANGUAGE];
00652 char zonetag[80];
00653 char locale[20];
00654 char callback[80];
00655 char dialout[80];
00656 char uniqueid[80];
00657 char exit[80];
00658 char attachfmt[20];
00659 unsigned int flags;
00660 int saydurationm;
00661 int minsecs;
00662 int maxmsg;
00663 int maxdeletedmsg;
00664 int maxsecs;
00665 int passwordlocation;
00666 #ifdef IMAP_STORAGE
00667 char imapuser[80];
00668 char imappassword[80];
00669 char imapfolder[64];
00670 char imapvmshareid[80];
00671 int imapversion;
00672 #endif
00673 double volgain;
00674 AST_LIST_ENTRY(ast_vm_user) list;
00675 };
00676
00677
00678 struct vm_zone {
00679 AST_LIST_ENTRY(vm_zone) list;
00680 char name[80];
00681 char timezone[80];
00682 char msg_format[512];
00683 };
00684
00685 #define VMSTATE_MAX_MSG_ARRAY 256
00686
00687
00688 struct vm_state {
00689 char curbox[80];
00690 char username[80];
00691 char context[80];
00692 char curdir[PATH_MAX];
00693 char vmbox[PATH_MAX];
00694 char fn[PATH_MAX];
00695 char intro[PATH_MAX];
00696 int *deleted;
00697 int *heard;
00698 int dh_arraysize;
00699 int curmsg;
00700 int lastmsg;
00701 int newmessages;
00702 int oldmessages;
00703 int urgentmessages;
00704 int starting;
00705 int repeats;
00706 #ifdef IMAP_STORAGE
00707 ast_mutex_t lock;
00708 int updated;
00709 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00710 MAILSTREAM *mailstream;
00711 int vmArrayIndex;
00712 char imapuser[80];
00713 char imapfolder[64];
00714 int imapversion;
00715 int interactive;
00716 char introfn[PATH_MAX];
00717 unsigned int quota_limit;
00718 unsigned int quota_usage;
00719 struct vm_state *persist_vms;
00720 #endif
00721 };
00722
00723 #ifdef ODBC_STORAGE
00724 static char odbc_database[80];
00725 static char odbc_table[80];
00726 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00727 #define DISPOSE(a,b) remove_file(a,b)
00728 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00729 #define EXISTS(a,b,c,d) (message_exists(a,b))
00730 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00731 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00732 #define DELETE(a,b,c,d) (delete_file(a,b))
00733 #else
00734 #ifdef IMAP_STORAGE
00735 #define DISPOSE(a,b) (imap_remove_file(a,b))
00736 #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))
00737 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00738 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00739 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00740 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00741 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00742 #else
00743 #define RETRIEVE(a,b,c,d)
00744 #define DISPOSE(a,b)
00745 #define STORE(a,b,c,d,e,f,g,h,i,j)
00746 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00747 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00748 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00749 #define DELETE(a,b,c,d) (vm_delete(c))
00750 #endif
00751 #endif
00752
00753 static char VM_SPOOL_DIR[PATH_MAX];
00754
00755 static char ext_pass_cmd[128];
00756 static char ext_pass_check_cmd[128];
00757
00758 static int my_umask;
00759
00760 #define PWDCHANGE_INTERNAL (1 << 1)
00761 #define PWDCHANGE_EXTERNAL (1 << 2)
00762 static int pwdchange = PWDCHANGE_INTERNAL;
00763
00764 #ifdef ODBC_STORAGE
00765 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00766 #else
00767 # ifdef IMAP_STORAGE
00768 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00769 # else
00770 # define tdesc "Comedian Mail (Voicemail System)"
00771 # endif
00772 #endif
00773
00774 static char userscontext[AST_MAX_EXTENSION] = "default";
00775
00776 static char *addesc = "Comedian Mail";
00777
00778
00779 static char *app = "VoiceMail";
00780
00781
00782 static char *app2 = "VoiceMailMain";
00783
00784 static char *app3 = "MailboxExists";
00785 static char *app4 = "VMAuthenticate";
00786
00787 static char *sayname_app = "VMSayName";
00788
00789 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00790 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00791 static char zonetag[80];
00792 static char locale[20];
00793 static int maxsilence;
00794 static int maxmsg;
00795 static int maxdeletedmsg;
00796 static int silencethreshold = 128;
00797 static char serveremail[80];
00798 static char mailcmd[160];
00799 static char externnotify[160];
00800 static struct ast_smdi_interface *smdi_iface = NULL;
00801 static char vmfmts[80];
00802 static double volgain;
00803 static int vmminsecs;
00804 static int vmmaxsecs;
00805 static int maxgreet;
00806 static int skipms;
00807 static int maxlogins;
00808 static int minpassword;
00809 static int passwordlocation;
00810
00811
00812
00813 static unsigned int poll_mailboxes;
00814
00815
00816 static unsigned int poll_freq;
00817
00818 #define DEFAULT_POLL_FREQ 30
00819
00820 AST_MUTEX_DEFINE_STATIC(poll_lock);
00821 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00822 static pthread_t poll_thread = AST_PTHREADT_NULL;
00823 static unsigned char poll_thread_run;
00824
00825
00826 static struct ast_event_sub *mwi_sub_sub;
00827
00828 static struct ast_event_sub *mwi_unsub_sub;
00829
00830
00831
00832
00833
00834
00835
00836
00837 struct mwi_sub {
00838 AST_RWLIST_ENTRY(mwi_sub) entry;
00839 int old_urgent;
00840 int old_new;
00841 int old_old;
00842 uint32_t uniqueid;
00843 char mailbox[1];
00844 };
00845
00846 struct mwi_sub_task {
00847 const char *mailbox;
00848 const char *context;
00849 uint32_t uniqueid;
00850 };
00851
00852 static struct ast_taskprocessor *mwi_subscription_tps;
00853
00854 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00855
00856
00857 static char listen_control_forward_key[12];
00858 static char listen_control_reverse_key[12];
00859 static char listen_control_pause_key[12];
00860 static char listen_control_restart_key[12];
00861 static char listen_control_stop_key[12];
00862
00863
00864 static char vm_password[80] = "vm-password";
00865 static char vm_newpassword[80] = "vm-newpassword";
00866 static char vm_passchanged[80] = "vm-passchanged";
00867 static char vm_reenterpassword[80] = "vm-reenterpassword";
00868 static char vm_mismatch[80] = "vm-mismatch";
00869 static char vm_invalid_password[80] = "vm-invalid-password";
00870 static char vm_pls_try_again[80] = "vm-pls-try-again";
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882 static char vm_prepend_timeout[80] = "vm-then-pound";
00883
00884 static struct ast_flags globalflags = {0};
00885
00886 static int saydurationminfo;
00887
00888 static char dialcontext[AST_MAX_CONTEXT] = "";
00889 static char callcontext[AST_MAX_CONTEXT] = "";
00890 static char exitcontext[AST_MAX_CONTEXT] = "";
00891
00892 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00893
00894
00895 static char *emailbody = NULL;
00896 static char *emailsubject = NULL;
00897 static char *pagerbody = NULL;
00898 static char *pagersubject = NULL;
00899 static char fromstring[100];
00900 static char pagerfromstring[100];
00901 static char charset[32] = "ISO-8859-1";
00902
00903 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00904 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00905 static int adsiver = 1;
00906 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00907 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00908
00909
00910 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00911 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);
00912 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00913 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00914 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00915 signed char record_gain, struct vm_state *vms, char *flag);
00916 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00917 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00918 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);
00919 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);
00920 static void apply_options(struct ast_vm_user *vmu, const char *options);
00921 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);
00922 static int is_valid_dtmf(const char *key);
00923 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00924 static int write_password_to_file(const char *secretfn, const char *password);
00925 static const char *substitute_escapes(const char *value);
00926 static void free_user(struct ast_vm_user *vmu);
00927
00928 struct ao2_container *inprocess_container;
00929
00930 struct inprocess {
00931 int count;
00932 char *context;
00933 char mailbox[0];
00934 };
00935
00936 static int inprocess_hash_fn(const void *obj, const int flags)
00937 {
00938 const struct inprocess *i = obj;
00939 return atoi(i->mailbox);
00940 }
00941
00942 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00943 {
00944 struct inprocess *i = obj, *j = arg;
00945 if (strcmp(i->mailbox, j->mailbox)) {
00946 return 0;
00947 }
00948 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00949 }
00950
00951 static int inprocess_count(const char *context, const char *mailbox, int delta)
00952 {
00953 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00954 arg->context = arg->mailbox + strlen(mailbox) + 1;
00955 strcpy(arg->mailbox, mailbox);
00956 strcpy(arg->context, context);
00957 ao2_lock(inprocess_container);
00958 if ((i = ao2_find(inprocess_container, arg, 0))) {
00959 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00960 ao2_unlock(inprocess_container);
00961 ao2_ref(i, -1);
00962 return ret;
00963 }
00964 if (delta < 0) {
00965 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00966 }
00967 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00968 ao2_unlock(inprocess_container);
00969 return 0;
00970 }
00971 i->context = i->mailbox + strlen(mailbox) + 1;
00972 strcpy(i->mailbox, mailbox);
00973 strcpy(i->context, context);
00974 i->count = delta;
00975 ao2_link(inprocess_container, i);
00976 ao2_unlock(inprocess_container);
00977 ao2_ref(i, -1);
00978 return 0;
00979 }
00980
00981 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00982 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00983 #endif
00984
00985
00986
00987
00988
00989
00990
00991 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00992 {
00993 char *bufptr = buf;
00994 for (; *input; input++) {
00995 if (*input < 32) {
00996 continue;
00997 }
00998 *bufptr++ = *input;
00999 if (bufptr == buf + buflen - 1) {
01000 break;
01001 }
01002 }
01003 *bufptr = '\0';
01004 return buf;
01005 }
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 static void populate_defaults(struct ast_vm_user *vmu)
01022 {
01023 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01024 vmu->passwordlocation = passwordlocation;
01025 if (saydurationminfo) {
01026 vmu->saydurationm = saydurationminfo;
01027 }
01028 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01029 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01030 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01031 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01032 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01033 if (vmminsecs) {
01034 vmu->minsecs = vmminsecs;
01035 }
01036 if (vmmaxsecs) {
01037 vmu->maxsecs = vmmaxsecs;
01038 }
01039 if (maxmsg) {
01040 vmu->maxmsg = maxmsg;
01041 }
01042 if (maxdeletedmsg) {
01043 vmu->maxdeletedmsg = maxdeletedmsg;
01044 }
01045 vmu->volgain = volgain;
01046 ast_free(vmu->emailsubject);
01047 vmu->emailsubject = NULL;
01048 ast_free(vmu->emailbody);
01049 vmu->emailbody = NULL;
01050 #ifdef IMAP_STORAGE
01051 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01052 #endif
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01064 {
01065 int x;
01066 if (!strcasecmp(var, "attach")) {
01067 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01068 } else if (!strcasecmp(var, "attachfmt")) {
01069 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01070 } else if (!strcasecmp(var, "serveremail")) {
01071 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01072 } else if (!strcasecmp(var, "emailbody")) {
01073 vmu->emailbody = ast_strdup(substitute_escapes(value));
01074 } else if (!strcasecmp(var, "emailsubject")) {
01075 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01076 } else if (!strcasecmp(var, "language")) {
01077 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01078 } else if (!strcasecmp(var, "tz")) {
01079 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01080 } else if (!strcasecmp(var, "locale")) {
01081 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01082 #ifdef IMAP_STORAGE
01083 } else if (!strcasecmp(var, "imapuser")) {
01084 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01085 vmu->imapversion = imapversion;
01086 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01087 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01088 vmu->imapversion = imapversion;
01089 } else if (!strcasecmp(var, "imapfolder")) {
01090 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01091 } else if (!strcasecmp(var, "imapvmshareid")) {
01092 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01093 vmu->imapversion = imapversion;
01094 #endif
01095 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01096 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01097 } else if (!strcasecmp(var, "saycid")){
01098 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01099 } else if (!strcasecmp(var, "sendvoicemail")){
01100 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01101 } else if (!strcasecmp(var, "review")){
01102 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01103 } else if (!strcasecmp(var, "tempgreetwarn")){
01104 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01105 } else if (!strcasecmp(var, "messagewrap")){
01106 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01107 } else if (!strcasecmp(var, "operator")) {
01108 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01109 } else if (!strcasecmp(var, "envelope")){
01110 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01111 } else if (!strcasecmp(var, "moveheard")){
01112 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01113 } else if (!strcasecmp(var, "sayduration")){
01114 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01115 } else if (!strcasecmp(var, "saydurationm")){
01116 if (sscanf(value, "%30d", &x) == 1) {
01117 vmu->saydurationm = x;
01118 } else {
01119 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01120 }
01121 } else if (!strcasecmp(var, "forcename")){
01122 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01123 } else if (!strcasecmp(var, "forcegreetings")){
01124 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01125 } else if (!strcasecmp(var, "callback")) {
01126 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01127 } else if (!strcasecmp(var, "dialout")) {
01128 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01129 } else if (!strcasecmp(var, "exitcontext")) {
01130 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01131 } else if (!strcasecmp(var, "minsecs")) {
01132 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01133 vmu->minsecs = x;
01134 } else {
01135 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01136 vmu->minsecs = vmminsecs;
01137 }
01138 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01139 vmu->maxsecs = atoi(value);
01140 if (vmu->maxsecs <= 0) {
01141 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01142 vmu->maxsecs = vmmaxsecs;
01143 } else {
01144 vmu->maxsecs = atoi(value);
01145 }
01146 if (!strcasecmp(var, "maxmessage"))
01147 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01148 } else if (!strcasecmp(var, "maxmsg")) {
01149 vmu->maxmsg = atoi(value);
01150
01151 if (vmu->maxmsg < 0) {
01152 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01153 vmu->maxmsg = MAXMSG;
01154 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01155 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01156 vmu->maxmsg = MAXMSGLIMIT;
01157 }
01158 } else if (!strcasecmp(var, "nextaftercmd")) {
01159 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01160 } else if (!strcasecmp(var, "backupdeleted")) {
01161 if (sscanf(value, "%30d", &x) == 1)
01162 vmu->maxdeletedmsg = x;
01163 else if (ast_true(value))
01164 vmu->maxdeletedmsg = MAXMSG;
01165 else
01166 vmu->maxdeletedmsg = 0;
01167
01168 if (vmu->maxdeletedmsg < 0) {
01169 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01170 vmu->maxdeletedmsg = MAXMSG;
01171 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01172 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01173 vmu->maxdeletedmsg = MAXMSGLIMIT;
01174 }
01175 } else if (!strcasecmp(var, "volgain")) {
01176 sscanf(value, "%30lf", &vmu->volgain);
01177 } else if (!strcasecmp(var, "passwordlocation")) {
01178 if (!strcasecmp(value, "spooldir")) {
01179 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01180 } else {
01181 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01182 }
01183 } else if (!strcasecmp(var, "options")) {
01184 apply_options(vmu, value);
01185 }
01186 }
01187
01188 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01189 {
01190 int fds[2], pid = 0;
01191
01192 memset(buf, 0, len);
01193
01194 if (pipe(fds)) {
01195 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01196 } else {
01197
01198 pid = ast_safe_fork(0);
01199
01200 if (pid < 0) {
01201
01202 close(fds[0]);
01203 close(fds[1]);
01204 snprintf(buf, len, "FAILURE: Fork failed");
01205 } else if (pid) {
01206
01207 close(fds[1]);
01208 if (read(fds[0], buf, len) < 0) {
01209 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01210 }
01211 close(fds[0]);
01212 } else {
01213
01214 AST_DECLARE_APP_ARGS(arg,
01215 AST_APP_ARG(v)[20];
01216 );
01217 char *mycmd = ast_strdupa(command);
01218
01219 close(fds[0]);
01220 dup2(fds[1], STDOUT_FILENO);
01221 close(fds[1]);
01222 ast_close_fds_above_n(STDOUT_FILENO);
01223
01224 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01225
01226 execv(arg.v[0], arg.v);
01227 printf("FAILURE: %s", strerror(errno));
01228 _exit(0);
01229 }
01230 }
01231 return buf;
01232 }
01233
01234
01235
01236
01237
01238
01239
01240
01241 static int check_password(struct ast_vm_user *vmu, char *password)
01242 {
01243
01244 if (strlen(password) < minpassword)
01245 return 1;
01246
01247 if (!ast_strlen_zero(password) && password[0] == '*')
01248 return 1;
01249 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01250 char cmd[255], buf[255];
01251
01252 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01253
01254 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01255 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01256 ast_debug(5, "Result: %s\n", buf);
01257 if (!strncasecmp(buf, "VALID", 5)) {
01258 ast_debug(3, "Passed password check: '%s'\n", buf);
01259 return 0;
01260 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01261 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01262 return 0;
01263 } else {
01264 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01265 return 1;
01266 }
01267 }
01268 }
01269 return 0;
01270 }
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01283 {
01284 int res = -1;
01285 if (!strcmp(vmu->password, password)) {
01286
01287 return 0;
01288 }
01289
01290 if (strlen(password) > 10) {
01291 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01292 }
01293 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01294 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01295 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01296 res = 0;
01297 }
01298 return res;
01299 }
01300
01301
01302
01303
01304 static void apply_options(struct ast_vm_user *vmu, const char *options)
01305 {
01306 char *stringp;
01307 char *s;
01308 char *var, *value;
01309 stringp = ast_strdupa(options);
01310 while ((s = strsep(&stringp, "|"))) {
01311 value = s;
01312 if ((var = strsep(&value, "=")) && value) {
01313 apply_option(vmu, var, value);
01314 }
01315 }
01316 }
01317
01318
01319
01320
01321
01322
01323 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01324 {
01325 for (; var; var = var->next) {
01326 if (!strcasecmp(var->name, "vmsecret")) {
01327 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01328 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01329 if (ast_strlen_zero(retval->password)) {
01330 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01331 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01332 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01333 } else {
01334 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01335 }
01336 }
01337 } else if (!strcasecmp(var->name, "uniqueid")) {
01338 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01339 } else if (!strcasecmp(var->name, "pager")) {
01340 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01341 } else if (!strcasecmp(var->name, "email")) {
01342 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01343 } else if (!strcasecmp(var->name, "fullname")) {
01344 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01345 } else if (!strcasecmp(var->name, "context")) {
01346 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01347 } else if (!strcasecmp(var->name, "emailsubject")) {
01348 ast_free(retval->emailsubject);
01349 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01350 } else if (!strcasecmp(var->name, "emailbody")) {
01351 ast_free(retval->emailbody);
01352 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01353 #ifdef IMAP_STORAGE
01354 } else if (!strcasecmp(var->name, "imapuser")) {
01355 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01356 retval->imapversion = imapversion;
01357 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01358 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01359 retval->imapversion = imapversion;
01360 } else if (!strcasecmp(var->name, "imapfolder")) {
01361 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01362 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01363 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01364 retval->imapversion = imapversion;
01365 #endif
01366 } else
01367 apply_option(retval, var->name, var->value);
01368 }
01369 }
01370
01371
01372
01373
01374
01375
01376
01377
01378 static int is_valid_dtmf(const char *key)
01379 {
01380 int i;
01381 char *local_key = ast_strdupa(key);
01382
01383 for (i = 0; i < strlen(key); ++i) {
01384 if (!strchr(VALID_DTMF, *local_key)) {
01385 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01386 return 0;
01387 }
01388 local_key++;
01389 }
01390 return 1;
01391 }
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01404 {
01405 struct ast_variable *var;
01406 struct ast_vm_user *retval;
01407
01408 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01409 if (ivm) {
01410 memset(retval, 0, sizeof(*retval));
01411 }
01412 populate_defaults(retval);
01413 if (!ivm) {
01414 ast_set_flag(retval, VM_ALLOCED);
01415 }
01416 if (mailbox) {
01417 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01418 }
01419 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01420 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01421 } else {
01422 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01423 }
01424 if (var) {
01425 apply_options_full(retval, var);
01426 ast_variables_destroy(var);
01427 } else {
01428 if (!ivm)
01429 free_user(retval);
01430 retval = NULL;
01431 }
01432 }
01433 return retval;
01434 }
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01445 {
01446
01447 struct ast_vm_user *vmu = NULL, *cur;
01448 AST_LIST_LOCK(&users);
01449
01450 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01451 context = "default";
01452
01453 AST_LIST_TRAVERSE(&users, cur, list) {
01454 #ifdef IMAP_STORAGE
01455 if (cur->imapversion != imapversion) {
01456 continue;
01457 }
01458 #endif
01459 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01460 break;
01461 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01462 break;
01463 }
01464 if (cur) {
01465
01466 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01467 *vmu = *cur;
01468 if (!ivm) {
01469 vmu->emailbody = ast_strdup(cur->emailbody);
01470 vmu->emailsubject = ast_strdup(cur->emailsubject);
01471 }
01472 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01473 AST_LIST_NEXT(vmu, list) = NULL;
01474 }
01475 } else
01476 vmu = find_user_realtime(ivm, context, mailbox);
01477 AST_LIST_UNLOCK(&users);
01478 return vmu;
01479 }
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01492 {
01493
01494 struct ast_vm_user *cur;
01495 int res = -1;
01496 AST_LIST_LOCK(&users);
01497 AST_LIST_TRAVERSE(&users, cur, list) {
01498 if ((!context || !strcasecmp(context, cur->context)) &&
01499 (!strcasecmp(mailbox, cur->mailbox)))
01500 break;
01501 }
01502 if (cur) {
01503 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01504 res = 0;
01505 }
01506 AST_LIST_UNLOCK(&users);
01507 return res;
01508 }
01509
01510
01511
01512
01513 static inline int valid_config(const struct ast_config *cfg)
01514 {
01515 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01516 }
01517
01518
01519
01520
01521
01522
01523
01524
01525 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01526 {
01527 struct ast_config *cfg = NULL;
01528 struct ast_variable *var = NULL;
01529 struct ast_category *cat = NULL;
01530 char *category = NULL, *value = NULL, *new = NULL;
01531 const char *tmp = NULL;
01532 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01533 char secretfn[PATH_MAX] = "";
01534 int found = 0;
01535
01536 if (!change_password_realtime(vmu, newpassword))
01537 return;
01538
01539
01540 switch (vmu->passwordlocation) {
01541 case OPT_PWLOC_SPOOLDIR:
01542 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01543 if (write_password_to_file(secretfn, newpassword) == 0) {
01544 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01545 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01546 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01547 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01548 break;
01549 } else {
01550 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01551 }
01552
01553 case OPT_PWLOC_VOICEMAILCONF:
01554 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01555 while ((category = ast_category_browse(cfg, category))) {
01556 if (!strcasecmp(category, vmu->context)) {
01557 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01558 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01559 break;
01560 }
01561 value = strstr(tmp, ",");
01562 if (!value) {
01563 new = ast_alloca(strlen(newpassword)+1);
01564 sprintf(new, "%s", newpassword);
01565 } else {
01566 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01567 sprintf(new, "%s%s", newpassword, value);
01568 }
01569 if (!(cat = ast_category_get(cfg, category))) {
01570 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01571 break;
01572 }
01573 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01574 found = 1;
01575 }
01576 }
01577
01578 if (found) {
01579 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01580 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01581 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01582 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01583 ast_config_destroy(cfg);
01584 break;
01585 }
01586
01587 ast_config_destroy(cfg);
01588 }
01589
01590 case OPT_PWLOC_USERSCONF:
01591
01592
01593 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01594 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01595 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01596 ast_debug(4, "users.conf: %s\n", category);
01597 if (!strcasecmp(category, vmu->mailbox)) {
01598 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01599 ast_debug(3, "looks like we need to make vmsecret!\n");
01600 var = ast_variable_new("vmsecret", newpassword, "");
01601 } else {
01602 var = NULL;
01603 }
01604 new = ast_alloca(strlen(newpassword) + 1);
01605 sprintf(new, "%s", newpassword);
01606 if (!(cat = ast_category_get(cfg, category))) {
01607 ast_debug(4, "failed to get category!\n");
01608 ast_free(var);
01609 break;
01610 }
01611 if (!var) {
01612 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01613 } else {
01614 ast_variable_append(cat, var);
01615 }
01616 found = 1;
01617 break;
01618 }
01619 }
01620
01621 if (found) {
01622 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01623 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01624 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01625 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01626 }
01627
01628 ast_config_destroy(cfg);
01629 }
01630 }
01631 }
01632
01633 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01634 {
01635 char buf[255];
01636 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01637 ast_debug(1, "External password: %s\n",buf);
01638 if (!ast_safe_system(buf)) {
01639 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01640 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01641
01642 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01643 }
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01660 {
01661 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01662 }
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676 static int make_file(char *dest, const int len, const char *dir, const int num)
01677 {
01678 return snprintf(dest, len, "%s/msg%04d", dir, num);
01679 }
01680
01681
01682 static FILE *vm_mkftemp(char *template)
01683 {
01684 FILE *p = NULL;
01685 int pfd = mkstemp(template);
01686 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01687 if (pfd > -1) {
01688 p = fdopen(pfd, "w+");
01689 if (!p) {
01690 close(pfd);
01691 pfd = -1;
01692 }
01693 }
01694 return p;
01695 }
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01706 {
01707 mode_t mode = VOICEMAIL_DIR_MODE;
01708 int res;
01709
01710 make_dir(dest, len, context, ext, folder);
01711 if ((res = ast_mkdir(dest, mode))) {
01712 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01713 return -1;
01714 }
01715 return 0;
01716 }
01717
01718 static const char * const mailbox_folders[] = {
01719 #ifdef IMAP_STORAGE
01720 imapfolder,
01721 #else
01722 "INBOX",
01723 #endif
01724 "Old",
01725 "Work",
01726 "Family",
01727 "Friends",
01728 "Cust1",
01729 "Cust2",
01730 "Cust3",
01731 "Cust4",
01732 "Cust5",
01733 "Deleted",
01734 "Urgent",
01735 };
01736
01737 static const char *mbox(struct ast_vm_user *vmu, int id)
01738 {
01739 #ifdef IMAP_STORAGE
01740 if (vmu && id == 0) {
01741 return vmu->imapfolder;
01742 }
01743 #endif
01744 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01745 }
01746
01747 static int get_folder_by_name(const char *name)
01748 {
01749 size_t i;
01750
01751 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01752 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01753 return i;
01754 }
01755 }
01756
01757 return -1;
01758 }
01759
01760 static void free_user(struct ast_vm_user *vmu)
01761 {
01762 if (ast_test_flag(vmu, VM_ALLOCED)) {
01763
01764 ast_free(vmu->emailbody);
01765 vmu->emailbody = NULL;
01766
01767 ast_free(vmu->emailsubject);
01768 vmu->emailsubject = NULL;
01769
01770 ast_free(vmu);
01771 }
01772 }
01773
01774 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01775
01776 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01777
01778
01779 if (vms->deleted) {
01780 ast_free(vms->deleted);
01781 vms->deleted = NULL;
01782 }
01783 if (vms->heard) {
01784 ast_free(vms->heard);
01785 vms->heard = NULL;
01786 }
01787 vms->dh_arraysize = 0;
01788
01789 if (arraysize > 0) {
01790 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01791 return -1;
01792 }
01793 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01794 ast_free(vms->deleted);
01795 vms->deleted = NULL;
01796 return -1;
01797 }
01798 vms->dh_arraysize = arraysize;
01799 }
01800
01801 return 0;
01802 }
01803
01804
01805
01806 #ifdef IMAP_STORAGE
01807 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01808 {
01809 char arg[10];
01810 struct vm_state *vms;
01811 unsigned long messageNum;
01812
01813
01814 if (msgnum < 0 && !imapgreetings) {
01815 ast_filedelete(file, NULL);
01816 return;
01817 }
01818
01819 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01820 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);
01821 return;
01822 }
01823
01824 if (msgnum < 0) {
01825 imap_delete_old_greeting(file, vms);
01826 return;
01827 }
01828
01829
01830
01831 messageNum = vms->msgArray[msgnum];
01832 if (messageNum == 0) {
01833 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01834 return;
01835 }
01836 if (option_debug > 2)
01837 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01838
01839 snprintf (arg, sizeof(arg), "%lu", messageNum);
01840 ast_mutex_lock(&vms->lock);
01841 mail_setflag (vms->mailstream, arg, "\\DELETED");
01842 mail_expunge(vms->mailstream);
01843 ast_mutex_unlock(&vms->lock);
01844 }
01845
01846 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01847 {
01848 struct vm_state *vms_p;
01849 char *file, *filename;
01850 char *attachment;
01851 int i;
01852 BODY *body;
01853
01854
01855
01856
01857 if (msgnum > -1 || !imapgreetings) {
01858 return 0;
01859 } else {
01860 file = strrchr(ast_strdupa(dir), '/');
01861 if (file)
01862 *file++ = '\0';
01863 else {
01864 ast_debug (1, "Failed to procure file name from directory passed.\n");
01865 return -1;
01866 }
01867 }
01868
01869
01870 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01871 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01872
01873
01874
01875
01876 if (!(vms_p = create_vm_state_from_user(vmu))) {
01877 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01878 return -1;
01879 }
01880 }
01881
01882
01883 *vms_p->introfn = '\0';
01884
01885 ast_mutex_lock(&vms_p->lock);
01886 init_mailstream(vms_p, GREETINGS_FOLDER);
01887 if (!vms_p->mailstream) {
01888 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01889 ast_mutex_unlock(&vms_p->lock);
01890 return -1;
01891 }
01892
01893
01894 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01895 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01896
01897 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01898 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01899 } else {
01900 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01901 ast_mutex_unlock(&vms_p->lock);
01902 return -1;
01903 }
01904 filename = strsep(&attachment, ".");
01905 if (!strcmp(filename, file)) {
01906 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01907 vms_p->msgArray[vms_p->curmsg] = i + 1;
01908 save_body(body, vms_p, "2", attachment, 0);
01909 ast_mutex_unlock(&vms_p->lock);
01910 return 0;
01911 }
01912 }
01913 ast_mutex_unlock(&vms_p->lock);
01914
01915 return -1;
01916 }
01917
01918 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01919 {
01920 BODY *body;
01921 char *header_content;
01922 char *attachedfilefmt;
01923 char buf[80];
01924 struct vm_state *vms;
01925 char text_file[PATH_MAX];
01926 FILE *text_file_ptr;
01927 int res = 0;
01928 struct ast_vm_user *vmu;
01929
01930 if (!(vmu = find_user(NULL, context, mailbox))) {
01931 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01932 return -1;
01933 }
01934
01935 if (msgnum < 0) {
01936 if (imapgreetings) {
01937 res = imap_retrieve_greeting(dir, msgnum, vmu);
01938 goto exit;
01939 } else {
01940 res = 0;
01941 goto exit;
01942 }
01943 }
01944
01945
01946
01947
01948 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01949
01950
01951
01952
01953
01954
01955
01956 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01957 res = -1;
01958 goto exit;
01959 }
01960
01961 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01962 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01963
01964
01965 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01966 res = 0;
01967 goto exit;
01968 }
01969
01970 if (option_debug > 2)
01971 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01972 if (vms->msgArray[msgnum] == 0) {
01973 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01974 res = -1;
01975 goto exit;
01976 }
01977
01978
01979 ast_mutex_lock(&vms->lock);
01980 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01981 ast_mutex_unlock(&vms->lock);
01982
01983 if (ast_strlen_zero(header_content)) {
01984 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01985 res = -1;
01986 goto exit;
01987 }
01988
01989 ast_mutex_lock(&vms->lock);
01990 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01991 ast_mutex_unlock(&vms->lock);
01992
01993
01994 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01995 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01996 } else {
01997 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01998 res = -1;
01999 goto exit;
02000 }
02001
02002
02003
02004 strsep(&attachedfilefmt, ".");
02005 if (!attachedfilefmt) {
02006 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02007 res = -1;
02008 goto exit;
02009 }
02010
02011 save_body(body, vms, "2", attachedfilefmt, 0);
02012 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02013 *vms->introfn = '\0';
02014 }
02015
02016
02017 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02018
02019 if (!(text_file_ptr = fopen(text_file, "w"))) {
02020 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02021 }
02022
02023 fprintf(text_file_ptr, "%s\n", "[message]");
02024
02025 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02026 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02027 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02028 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02029 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02030 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02031 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02032 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02033 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02034 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02035 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02036 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02037 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02038 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02039 fclose(text_file_ptr);
02040
02041 exit:
02042 free_user(vmu);
02043 return res;
02044 }
02045
02046 static int folder_int(const char *folder)
02047 {
02048
02049 if (!folder) {
02050 return 0;
02051 }
02052 if (!strcasecmp(folder, imapfolder)) {
02053 return 0;
02054 } else if (!strcasecmp(folder, "Old")) {
02055 return 1;
02056 } else if (!strcasecmp(folder, "Work")) {
02057 return 2;
02058 } else if (!strcasecmp(folder, "Family")) {
02059 return 3;
02060 } else if (!strcasecmp(folder, "Friends")) {
02061 return 4;
02062 } else if (!strcasecmp(folder, "Cust1")) {
02063 return 5;
02064 } else if (!strcasecmp(folder, "Cust2")) {
02065 return 6;
02066 } else if (!strcasecmp(folder, "Cust3")) {
02067 return 7;
02068 } else if (!strcasecmp(folder, "Cust4")) {
02069 return 8;
02070 } else if (!strcasecmp(folder, "Cust5")) {
02071 return 9;
02072 } else if (!strcasecmp(folder, "Urgent")) {
02073 return 11;
02074 } else {
02075 return 0;
02076 }
02077 }
02078
02079 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02080 {
02081 SEARCHPGM *pgm;
02082 SEARCHHEADER *hdr;
02083
02084 struct ast_vm_user *vmu, vmus;
02085 struct vm_state *vms_p;
02086 int ret = 0;
02087 int fold = folder_int(folder);
02088 int urgent = 0;
02089
02090
02091 if (fold == 11) {
02092 fold = NEW_FOLDER;
02093 urgent = 1;
02094 }
02095
02096 if (ast_strlen_zero(mailbox))
02097 return 0;
02098
02099
02100 vmu = find_user(&vmus, context, mailbox);
02101 if (!vmu) {
02102 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02103 return -1;
02104 } else {
02105
02106 if (vmu->imapuser[0] == '\0') {
02107 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02108 return -1;
02109 }
02110 }
02111
02112
02113 if (vmu->imapuser[0] == '\0') {
02114 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02115 free_user(vmu);
02116 return -1;
02117 }
02118
02119
02120 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02121 if (!vms_p) {
02122 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02123 }
02124 if (vms_p) {
02125 ast_debug(3, "Returning before search - user is logged in\n");
02126 if (fold == 0) {
02127 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02128 }
02129 if (fold == 1) {
02130 return vms_p->oldmessages;
02131 }
02132 }
02133
02134
02135 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02136 if (!vms_p) {
02137 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02138 }
02139
02140 if (!vms_p) {
02141 vms_p = create_vm_state_from_user(vmu);
02142 }
02143 ret = init_mailstream(vms_p, fold);
02144 if (!vms_p->mailstream) {
02145 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02146 return -1;
02147 }
02148 if (ret == 0) {
02149 ast_mutex_lock(&vms_p->lock);
02150 pgm = mail_newsearchpgm ();
02151 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02152 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02153 pgm->header = hdr;
02154 if (fold != OLD_FOLDER) {
02155 pgm->unseen = 1;
02156 pgm->seen = 0;
02157 }
02158
02159
02160
02161 else {
02162 pgm->unseen = 0;
02163 pgm->seen = 1;
02164 }
02165
02166 if (fold == NEW_FOLDER) {
02167 if (urgent) {
02168 pgm->flagged = 1;
02169 pgm->unflagged = 0;
02170 } else {
02171 pgm->flagged = 0;
02172 pgm->unflagged = 1;
02173 }
02174 }
02175 pgm->undeleted = 1;
02176 pgm->deleted = 0;
02177
02178 vms_p->vmArrayIndex = 0;
02179 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02180 if (fold == 0 && urgent == 0)
02181 vms_p->newmessages = vms_p->vmArrayIndex;
02182 if (fold == 1)
02183 vms_p->oldmessages = vms_p->vmArrayIndex;
02184 if (fold == 0 && urgent == 1)
02185 vms_p->urgentmessages = vms_p->vmArrayIndex;
02186
02187 mail_free_searchpgm(&pgm);
02188 ast_mutex_unlock(&vms_p->lock);
02189 vms_p->updated = 0;
02190 return vms_p->vmArrayIndex;
02191 } else {
02192 ast_mutex_lock(&vms_p->lock);
02193 mail_ping(vms_p->mailstream);
02194 ast_mutex_unlock(&vms_p->lock);
02195 }
02196 return 0;
02197 }
02198
02199 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02200 {
02201
02202 check_quota(vms, vmu->imapfolder);
02203 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02204 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02205 ast_play_and_wait(chan, "vm-mailboxfull");
02206 return -1;
02207 }
02208
02209
02210 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
02211 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02212 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02213 ast_play_and_wait(chan, "vm-mailboxfull");
02214 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02215 return -1;
02216 }
02217
02218 return 0;
02219 }
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230 static int messagecount(const char *context, const char *mailbox, const char *folder)
02231 {
02232 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02233 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02234 } else {
02235 return __messagecount(context, mailbox, folder);
02236 }
02237 }
02238
02239 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
02240 {
02241 char *myserveremail = serveremail;
02242 char fn[PATH_MAX];
02243 char introfn[PATH_MAX];
02244 char mailbox[256];
02245 char *stringp;
02246 FILE *p = NULL;
02247 char tmp[80] = "/tmp/astmail-XXXXXX";
02248 long len;
02249 void *buf;
02250 int tempcopy = 0;
02251 STRING str;
02252 int ret;
02253 char *imap_flags = NIL;
02254 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02255 int box = NEW_FOLDER;
02256
02257
02258 if (msgnum < 0) {
02259 if(!imapgreetings) {
02260 return 0;
02261 } else {
02262 box = GREETINGS_FOLDER;
02263 }
02264 }
02265
02266 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02267 return -1;
02268 }
02269
02270
02271 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02272 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02273 imap_flags = "\\FLAGGED";
02274 }
02275
02276
02277 fmt = ast_strdupa(fmt);
02278 stringp = fmt;
02279 strsep(&stringp, "|");
02280
02281 if (!ast_strlen_zero(vmu->serveremail))
02282 myserveremail = vmu->serveremail;
02283
02284 if (msgnum > -1)
02285 make_file(fn, sizeof(fn), dir, msgnum);
02286 else
02287 ast_copy_string (fn, dir, sizeof(fn));
02288
02289 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02290 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02291 *introfn = '\0';
02292 }
02293
02294 if (ast_strlen_zero(vmu->email)) {
02295
02296
02297
02298
02299
02300 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02301 tempcopy = 1;
02302 }
02303
02304 if (!strcmp(fmt, "wav49"))
02305 fmt = "WAV";
02306 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02307
02308
02309
02310 if (!(p = vm_mkftemp(tmp))) {
02311 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02312 if (tempcopy)
02313 *(vmu->email) = '\0';
02314 return -1;
02315 }
02316
02317 if (msgnum < 0 && imapgreetings) {
02318 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02319 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02320 return -1;
02321 }
02322 imap_delete_old_greeting(fn, vms);
02323 }
02324
02325 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02326 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02327 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02328 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02329
02330 len = ftell(p);
02331 rewind(p);
02332 if (!(buf = ast_malloc(len + 1))) {
02333 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02334 fclose(p);
02335 if (tempcopy)
02336 *(vmu->email) = '\0';
02337 return -1;
02338 }
02339 if (fread(buf, len, 1, p) < len) {
02340 if (ferror(p)) {
02341 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02342 return -1;
02343 }
02344 }
02345 ((char *) buf)[len] = '\0';
02346 INIT(&str, mail_string, buf, len);
02347 ret = init_mailstream(vms, box);
02348 if (ret == 0) {
02349 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02350 ast_mutex_lock(&vms->lock);
02351 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02352 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02353 ast_mutex_unlock(&vms->lock);
02354 fclose(p);
02355 unlink(tmp);
02356 ast_free(buf);
02357 } else {
02358 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02359 fclose(p);
02360 unlink(tmp);
02361 ast_free(buf);
02362 return -1;
02363 }
02364 ast_debug(3, "%s stored\n", fn);
02365
02366 if (tempcopy)
02367 *(vmu->email) = '\0';
02368 inprocess_count(vmu->mailbox, vmu->context, -1);
02369 return 0;
02370
02371 }
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02387 {
02388 char tmp[PATH_MAX] = "";
02389 char *mailboxnc;
02390 char *context;
02391 char *mb;
02392 char *cur;
02393 if (newmsgs)
02394 *newmsgs = 0;
02395 if (oldmsgs)
02396 *oldmsgs = 0;
02397 if (urgentmsgs)
02398 *urgentmsgs = 0;
02399
02400 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02401
02402 if (ast_strlen_zero(mailbox_context))
02403 return 0;
02404
02405 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02406 context = strchr(tmp, '@');
02407 if (strchr(mailbox_context, ',')) {
02408 int tmpnew, tmpold, tmpurgent;
02409 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02410 mb = tmp;
02411 while ((cur = strsep(&mb, ", "))) {
02412 if (!ast_strlen_zero(cur)) {
02413 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02414 return -1;
02415 else {
02416 if (newmsgs)
02417 *newmsgs += tmpnew;
02418 if (oldmsgs)
02419 *oldmsgs += tmpold;
02420 if (urgentmsgs)
02421 *urgentmsgs += tmpurgent;
02422 }
02423 }
02424 }
02425 return 0;
02426 }
02427 if (context) {
02428 *context = '\0';
02429 mailboxnc = tmp;
02430 context++;
02431 } else {
02432 context = "default";
02433 mailboxnc = (char *) mailbox_context;
02434 }
02435
02436 if (newmsgs) {
02437 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02438 if (!vmu) {
02439 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02440 return -1;
02441 }
02442 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02443 free_user(vmu);
02444 return -1;
02445 }
02446 free_user(vmu);
02447 }
02448 if (oldmsgs) {
02449 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02450 return -1;
02451 }
02452 }
02453 if (urgentmsgs) {
02454 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02455 return -1;
02456 }
02457 }
02458 return 0;
02459 }
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471 static int has_voicemail(const char *mailbox, const char *folder)
02472 {
02473 char tmp[256], *tmp2, *box, *context;
02474 ast_copy_string(tmp, mailbox, sizeof(tmp));
02475 tmp2 = tmp;
02476 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02477 while ((box = strsep(&tmp2, ",&"))) {
02478 if (!ast_strlen_zero(box)) {
02479 if (has_voicemail(box, folder)) {
02480 return 1;
02481 }
02482 }
02483 }
02484 }
02485 if ((context = strchr(tmp, '@'))) {
02486 *context++ = '\0';
02487 } else {
02488 context = "default";
02489 }
02490 return __messagecount(context, tmp, folder) ? 1 : 0;
02491 }
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508 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)
02509 {
02510 struct vm_state *sendvms = NULL, *destvms = NULL;
02511 char messagestring[10];
02512 if (msgnum >= recip->maxmsg) {
02513 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02514 return -1;
02515 }
02516 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02517 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02518 return -1;
02519 }
02520 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02521 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02522 return -1;
02523 }
02524 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02525 ast_mutex_lock(&sendvms->lock);
02526 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02527 ast_mutex_unlock(&sendvms->lock);
02528 return 0;
02529 }
02530 ast_mutex_unlock(&sendvms->lock);
02531 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02532 return -1;
02533 }
02534
02535 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02536 {
02537 char tmp[256], *t = tmp;
02538 size_t left = sizeof(tmp);
02539
02540 if (box == OLD_FOLDER) {
02541 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02542 } else {
02543 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02544 }
02545
02546 if (box == NEW_FOLDER) {
02547 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02548 } else {
02549 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02550 }
02551
02552
02553 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02554
02555
02556 if (!ast_strlen_zero(authuser))
02557 ast_build_string(&t, &left, "/authuser=%s", authuser);
02558
02559
02560 if (!ast_strlen_zero(imapflags))
02561 ast_build_string(&t, &left, "/%s", imapflags);
02562
02563
02564 #if 1
02565 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02566 #else
02567 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02568 #endif
02569 if (box == NEW_FOLDER || box == OLD_FOLDER)
02570 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02571 else if (box == GREETINGS_FOLDER)
02572 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02573 else {
02574 if (!ast_strlen_zero(imapparentfolder)) {
02575
02576 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02577 } else {
02578 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02579 }
02580 }
02581 }
02582
02583 static int init_mailstream(struct vm_state *vms, int box)
02584 {
02585 MAILSTREAM *stream = NIL;
02586 long debug;
02587 char tmp[256];
02588
02589 if (!vms) {
02590 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02591 return -1;
02592 }
02593 if (option_debug > 2)
02594 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02595 if (vms->mailstream == NIL || !vms->mailstream) {
02596 if (option_debug)
02597 ast_log(LOG_DEBUG, "mailstream not set.\n");
02598 } else {
02599 stream = vms->mailstream;
02600 }
02601
02602 debug = NIL;
02603
02604 if (delimiter == '\0') {
02605 char *cp;
02606 #ifdef USE_SYSTEM_IMAP
02607 #include <imap/linkage.c>
02608 #elif defined(USE_SYSTEM_CCLIENT)
02609 #include <c-client/linkage.c>
02610 #else
02611 #include "linkage.c"
02612 #endif
02613
02614 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02615 ast_mutex_lock(&vms->lock);
02616 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02617 ast_mutex_unlock(&vms->lock);
02618 if (stream == NIL) {
02619 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02620 return -1;
02621 }
02622 get_mailbox_delimiter(stream);
02623
02624 for (cp = vms->imapfolder; *cp; cp++)
02625 if (*cp == '/')
02626 *cp = delimiter;
02627 }
02628
02629 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02630 if (option_debug > 2)
02631 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02632 ast_mutex_lock(&vms->lock);
02633 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02634 ast_mutex_unlock(&vms->lock);
02635 if (vms->mailstream == NIL) {
02636 return -1;
02637 } else {
02638 return 0;
02639 }
02640 }
02641
02642 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02643 {
02644 SEARCHPGM *pgm;
02645 SEARCHHEADER *hdr;
02646 int ret, urgent = 0;
02647
02648
02649 if (box == 11) {
02650 box = NEW_FOLDER;
02651 urgent = 1;
02652 }
02653
02654 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02655 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02656 vms->imapversion = vmu->imapversion;
02657 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02658
02659 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02660 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02661 return -1;
02662 }
02663
02664 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02665
02666
02667 if (box == 0) {
02668 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02669 check_quota(vms, (char *) mbox(vmu, box));
02670 }
02671
02672 ast_mutex_lock(&vms->lock);
02673 pgm = mail_newsearchpgm();
02674
02675
02676 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02677 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02678 pgm->header = hdr;
02679 pgm->deleted = 0;
02680 pgm->undeleted = 1;
02681
02682
02683 if (box == NEW_FOLDER && urgent == 1) {
02684 pgm->unseen = 1;
02685 pgm->seen = 0;
02686 pgm->flagged = 1;
02687 pgm->unflagged = 0;
02688 } else if (box == NEW_FOLDER && urgent == 0) {
02689 pgm->unseen = 1;
02690 pgm->seen = 0;
02691 pgm->flagged = 0;
02692 pgm->unflagged = 1;
02693 } else if (box == OLD_FOLDER) {
02694 pgm->seen = 1;
02695 pgm->unseen = 0;
02696 }
02697
02698 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02699
02700 vms->vmArrayIndex = 0;
02701 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02702 vms->lastmsg = vms->vmArrayIndex - 1;
02703 mail_free_searchpgm(&pgm);
02704
02705
02706
02707
02708 if (box == 0 && !vms->dh_arraysize) {
02709 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02710 }
02711 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02712 ast_mutex_unlock(&vms->lock);
02713 return -1;
02714 }
02715
02716 ast_mutex_unlock(&vms->lock);
02717 return 0;
02718 }
02719
02720 static void write_file(char *filename, char *buffer, unsigned long len)
02721 {
02722 FILE *output;
02723
02724 output = fopen (filename, "w");
02725 if (fwrite(buffer, len, 1, output) != 1) {
02726 if (ferror(output)) {
02727 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02728 }
02729 }
02730 fclose (output);
02731 }
02732
02733 static void update_messages_by_imapuser(const char *user, unsigned long number)
02734 {
02735 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02736
02737 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02738 return;
02739 }
02740
02741 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02742 vms->msgArray[vms->vmArrayIndex++] = number;
02743 }
02744
02745 void mm_searched(MAILSTREAM *stream, unsigned long number)
02746 {
02747 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02748
02749 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02750 return;
02751
02752 update_messages_by_imapuser(user, number);
02753 }
02754
02755 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02756 {
02757 struct ast_variable *var;
02758 struct ast_vm_user *vmu;
02759
02760 vmu = ast_calloc(1, sizeof *vmu);
02761 if (!vmu)
02762 return NULL;
02763
02764 populate_defaults(vmu);
02765 ast_set_flag(vmu, VM_ALLOCED);
02766
02767 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02768 if (var) {
02769 apply_options_full(vmu, var);
02770 ast_variables_destroy(var);
02771 return vmu;
02772 } else {
02773 ast_free(vmu);
02774 return NULL;
02775 }
02776 }
02777
02778
02779
02780 void mm_exists(MAILSTREAM * stream, unsigned long number)
02781 {
02782
02783 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02784 if (number == 0) return;
02785 set_update(stream);
02786 }
02787
02788
02789 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02790 {
02791
02792 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02793 if (number == 0) return;
02794 set_update(stream);
02795 }
02796
02797
02798 void mm_flags(MAILSTREAM * stream, unsigned long number)
02799 {
02800
02801 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02802 if (number == 0) return;
02803 set_update(stream);
02804 }
02805
02806
02807 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02808 {
02809 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02810 mm_log (string, errflg);
02811 }
02812
02813
02814 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02815 {
02816 if (delimiter == '\0') {
02817 delimiter = delim;
02818 }
02819
02820 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02821 if (attributes & LATT_NOINFERIORS)
02822 ast_debug(5, "no inferiors\n");
02823 if (attributes & LATT_NOSELECT)
02824 ast_debug(5, "no select\n");
02825 if (attributes & LATT_MARKED)
02826 ast_debug(5, "marked\n");
02827 if (attributes & LATT_UNMARKED)
02828 ast_debug(5, "unmarked\n");
02829 }
02830
02831
02832 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02833 {
02834 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02835 if (attributes & LATT_NOINFERIORS)
02836 ast_debug(5, "no inferiors\n");
02837 if (attributes & LATT_NOSELECT)
02838 ast_debug(5, "no select\n");
02839 if (attributes & LATT_MARKED)
02840 ast_debug(5, "marked\n");
02841 if (attributes & LATT_UNMARKED)
02842 ast_debug(5, "unmarked\n");
02843 }
02844
02845
02846 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02847 {
02848 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02849 if (status->flags & SA_MESSAGES)
02850 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02851 if (status->flags & SA_RECENT)
02852 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02853 if (status->flags & SA_UNSEEN)
02854 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02855 if (status->flags & SA_UIDVALIDITY)
02856 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02857 if (status->flags & SA_UIDNEXT)
02858 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02859 ast_log(AST_LOG_NOTICE, "\n");
02860 }
02861
02862
02863 void mm_log(char *string, long errflg)
02864 {
02865 switch ((short) errflg) {
02866 case NIL:
02867 ast_debug(1, "IMAP Info: %s\n", string);
02868 break;
02869 case PARSE:
02870 case WARN:
02871 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02872 break;
02873 case ERROR:
02874 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02875 break;
02876 }
02877 }
02878
02879
02880 void mm_dlog(char *string)
02881 {
02882 ast_log(AST_LOG_NOTICE, "%s\n", string);
02883 }
02884
02885
02886 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02887 {
02888 struct ast_vm_user *vmu;
02889
02890 ast_debug(4, "Entering callback mm_login\n");
02891
02892 ast_copy_string(user, mb->user, MAILTMPLEN);
02893
02894
02895 if (!ast_strlen_zero(authpassword)) {
02896 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02897 } else {
02898 AST_LIST_TRAVERSE(&users, vmu, list) {
02899 if (!strcasecmp(mb->user, vmu->imapuser)) {
02900 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02901 break;
02902 }
02903 }
02904 if (!vmu) {
02905 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02906 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02907 free_user(vmu);
02908 }
02909 }
02910 }
02911 }
02912
02913
02914 void mm_critical(MAILSTREAM * stream)
02915 {
02916 }
02917
02918
02919 void mm_nocritical(MAILSTREAM * stream)
02920 {
02921 }
02922
02923
02924 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02925 {
02926 kill (getpid (), SIGSTOP);
02927 return NIL;
02928 }
02929
02930
02931 void mm_fatal(char *string)
02932 {
02933 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02934 }
02935
02936
02937 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02938 {
02939 struct vm_state *vms;
02940 char *mailbox = stream->mailbox, *user;
02941 char buf[1024] = "";
02942 unsigned long usage = 0, limit = 0;
02943
02944 while (pquota) {
02945 usage = pquota->usage;
02946 limit = pquota->limit;
02947 pquota = pquota->next;
02948 }
02949
02950 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)))) {
02951 ast_log(AST_LOG_ERROR, "No state found.\n");
02952 return;
02953 }
02954
02955 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02956
02957 vms->quota_usage = usage;
02958 vms->quota_limit = limit;
02959 }
02960
02961 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02962 {
02963 char *start, *eol_pnt;
02964 int taglen;
02965
02966 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02967 return NULL;
02968
02969 taglen = strlen(tag) + 1;
02970 if (taglen < 1)
02971 return NULL;
02972
02973 if (!(start = strstr(header, tag)))
02974 return NULL;
02975
02976
02977 memset(buf, 0, len);
02978
02979 ast_copy_string(buf, start+taglen, len);
02980 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02981 *eol_pnt = '\0';
02982 return buf;
02983 }
02984
02985 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02986 {
02987 char *start, *quote, *eol_pnt;
02988
02989 if (ast_strlen_zero(mailbox))
02990 return NULL;
02991
02992 if (!(start = strstr(mailbox, "/user=")))
02993 return NULL;
02994
02995 ast_copy_string(buf, start+6, len);
02996
02997 if (!(quote = strchr(buf, '\"'))) {
02998 if (!(eol_pnt = strchr(buf, '/')))
02999 eol_pnt = strchr(buf,'}');
03000 *eol_pnt = '\0';
03001 return buf;
03002 } else {
03003 eol_pnt = strchr(buf+1,'\"');
03004 *eol_pnt = '\0';
03005 return buf+1;
03006 }
03007 }
03008
03009 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03010 {
03011 struct vm_state *vms_p;
03012
03013 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03014 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03015 return vms_p;
03016 }
03017 if (option_debug > 4)
03018 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03019 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03020 return NULL;
03021 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03022 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03023 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03024 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03025 vms_p->mailstream = NIL;
03026 vms_p->imapversion = vmu->imapversion;
03027 if (option_debug > 4)
03028 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03029 vms_p->updated = 1;
03030
03031 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03032 init_vm_state(vms_p);
03033 vmstate_insert(vms_p);
03034 return vms_p;
03035 }
03036
03037 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03038 {
03039 struct vmstate *vlist = NULL;
03040
03041 if (interactive) {
03042 struct vm_state *vms;
03043 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03044 vms = pthread_getspecific(ts_vmstate.key);
03045 return vms;
03046 }
03047
03048 AST_LIST_LOCK(&vmstates);
03049 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03050 if (!vlist->vms) {
03051 ast_debug(3, "error: vms is NULL for %s\n", user);
03052 continue;
03053 }
03054 if (vlist->vms->imapversion != imapversion) {
03055 continue;
03056 }
03057 if (!vlist->vms->imapuser) {
03058 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03059 continue;
03060 }
03061
03062 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03063 AST_LIST_UNLOCK(&vmstates);
03064 return vlist->vms;
03065 }
03066 }
03067 AST_LIST_UNLOCK(&vmstates);
03068
03069 ast_debug(3, "%s not found in vmstates\n", user);
03070
03071 return NULL;
03072 }
03073
03074 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03075 {
03076
03077 struct vmstate *vlist = NULL;
03078 const char *local_context = S_OR(context, "default");
03079
03080 if (interactive) {
03081 struct vm_state *vms;
03082 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03083 vms = pthread_getspecific(ts_vmstate.key);
03084 return vms;
03085 }
03086
03087 AST_LIST_LOCK(&vmstates);
03088 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03089 if (!vlist->vms) {
03090 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03091 continue;
03092 }
03093 if (vlist->vms->imapversion != imapversion) {
03094 continue;
03095 }
03096 if (!vlist->vms->username || !vlist->vms->context) {
03097 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03098 continue;
03099 }
03100
03101 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);
03102
03103 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03104 ast_debug(3, "Found it!\n");
03105 AST_LIST_UNLOCK(&vmstates);
03106 return vlist->vms;
03107 }
03108 }
03109 AST_LIST_UNLOCK(&vmstates);
03110
03111 ast_debug(3, "%s not found in vmstates\n", mailbox);
03112
03113 return NULL;
03114 }
03115
03116 static void vmstate_insert(struct vm_state *vms)
03117 {
03118 struct vmstate *v;
03119 struct vm_state *altvms;
03120
03121
03122
03123
03124 if (vms->interactive == 1) {
03125 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03126 if (altvms) {
03127 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03128 vms->newmessages = altvms->newmessages;
03129 vms->oldmessages = altvms->oldmessages;
03130 vms->vmArrayIndex = altvms->vmArrayIndex;
03131 vms->lastmsg = altvms->lastmsg;
03132 vms->curmsg = altvms->curmsg;
03133
03134 vms->persist_vms = altvms;
03135
03136 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03137 vms->mailstream = altvms->mailstream;
03138 #else
03139 vms->mailstream = NIL;
03140 #endif
03141 }
03142 return;
03143 }
03144
03145 if (!(v = ast_calloc(1, sizeof(*v))))
03146 return;
03147
03148 v->vms = vms;
03149
03150 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03151
03152 AST_LIST_LOCK(&vmstates);
03153 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03154 AST_LIST_UNLOCK(&vmstates);
03155 }
03156
03157 static void vmstate_delete(struct vm_state *vms)
03158 {
03159 struct vmstate *vc = NULL;
03160 struct vm_state *altvms = NULL;
03161
03162
03163
03164 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03165 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03166 altvms->newmessages = vms->newmessages;
03167 altvms->oldmessages = vms->oldmessages;
03168 altvms->updated = 1;
03169 vms->mailstream = mail_close(vms->mailstream);
03170
03171
03172 return;
03173 }
03174
03175 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03176
03177 AST_LIST_LOCK(&vmstates);
03178 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03179 if (vc->vms == vms) {
03180 AST_LIST_REMOVE_CURRENT(list);
03181 break;
03182 }
03183 }
03184 AST_LIST_TRAVERSE_SAFE_END
03185 AST_LIST_UNLOCK(&vmstates);
03186
03187 if (vc) {
03188 ast_mutex_destroy(&vc->vms->lock);
03189 ast_free(vc);
03190 }
03191 else
03192 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03193 }
03194
03195 static void set_update(MAILSTREAM * stream)
03196 {
03197 struct vm_state *vms;
03198 char *mailbox = stream->mailbox, *user;
03199 char buf[1024] = "";
03200
03201 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03202 if (user && option_debug > 2)
03203 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03204 return;
03205 }
03206
03207 ast_debug(3, "User %s mailbox set for update.\n", user);
03208
03209 vms->updated = 1;
03210 }
03211
03212 static void init_vm_state(struct vm_state *vms)
03213 {
03214 int x;
03215 vms->vmArrayIndex = 0;
03216 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03217 vms->msgArray[x] = 0;
03218 }
03219 ast_mutex_init(&vms->lock);
03220 }
03221
03222 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03223 {
03224 char *body_content;
03225 char *body_decoded;
03226 char *fn = is_intro ? vms->introfn : vms->fn;
03227 unsigned long len;
03228 unsigned long newlen;
03229 char filename[256];
03230
03231 if (!body || body == NIL)
03232 return -1;
03233
03234 ast_mutex_lock(&vms->lock);
03235 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03236 ast_mutex_unlock(&vms->lock);
03237 if (body_content != NIL) {
03238 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03239
03240 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03241
03242 if (!newlen) {
03243 return -1;
03244 }
03245 write_file(filename, (char *) body_decoded, newlen);
03246 } else {
03247 ast_debug(5, "Body of message is NULL.\n");
03248 return -1;
03249 }
03250 return 0;
03251 }
03252
03253
03254
03255
03256
03257
03258
03259
03260 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03261 char tmp[50];
03262 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03263 mail_list(stream, tmp, "*");
03264 }
03265
03266
03267
03268
03269
03270
03271
03272
03273 static void check_quota(struct vm_state *vms, char *mailbox) {
03274 ast_mutex_lock(&vms->lock);
03275 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03276 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03277 if (vms && vms->mailstream != NULL) {
03278 imap_getquotaroot(vms->mailstream, mailbox);
03279 } else {
03280 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03281 }
03282 ast_mutex_unlock(&vms->lock);
03283 }
03284
03285 #endif
03286
03287
03288
03289
03290
03291 static int vm_lock_path(const char *path)
03292 {
03293 switch (ast_lock_path(path)) {
03294 case AST_LOCK_TIMEOUT:
03295 return -1;
03296 default:
03297 return 0;
03298 }
03299 }
03300
03301
03302 #ifdef ODBC_STORAGE
03303 struct generic_prepare_struct {
03304 char *sql;
03305 int argc;
03306 char **argv;
03307 };
03308
03309 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03310 {
03311 struct generic_prepare_struct *gps = data;
03312 int res, i;
03313 SQLHSTMT stmt;
03314
03315 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03316 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03317 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03318 return NULL;
03319 }
03320 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03321 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03322 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03323 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03324 return NULL;
03325 }
03326 for (i = 0; i < gps->argc; i++)
03327 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03328
03329 return stmt;
03330 }
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346 static int retrieve_file(char *dir, int msgnum)
03347 {
03348 int x = 0;
03349 int res;
03350 int fd = -1;
03351 size_t fdlen = 0;
03352 void *fdm = MAP_FAILED;
03353 SQLSMALLINT colcount = 0;
03354 SQLHSTMT stmt;
03355 char sql[PATH_MAX];
03356 char fmt[80]="";
03357 char *c;
03358 char coltitle[256];
03359 SQLSMALLINT collen;
03360 SQLSMALLINT datatype;
03361 SQLSMALLINT decimaldigits;
03362 SQLSMALLINT nullable;
03363 SQLULEN colsize;
03364 SQLLEN colsize2;
03365 FILE *f = NULL;
03366 char rowdata[80];
03367 char fn[PATH_MAX];
03368 char full_fn[PATH_MAX];
03369 char msgnums[80];
03370 char *argv[] = { dir, msgnums };
03371 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03372
03373 struct odbc_obj *obj;
03374 obj = ast_odbc_request_obj(odbc_database, 0);
03375 if (obj) {
03376 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03377 c = strchr(fmt, '|');
03378 if (c)
03379 *c = '\0';
03380 if (!strcasecmp(fmt, "wav49"))
03381 strcpy(fmt, "WAV");
03382 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03383 if (msgnum > -1)
03384 make_file(fn, sizeof(fn), dir, msgnum);
03385 else
03386 ast_copy_string(fn, dir, sizeof(fn));
03387
03388
03389 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03390
03391 if (!(f = fopen(full_fn, "w+"))) {
03392 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03393 goto yuck;
03394 }
03395
03396 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03397 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03398 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03399 if (!stmt) {
03400 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03401 ast_odbc_release_obj(obj);
03402 goto yuck;
03403 }
03404 res = SQLFetch(stmt);
03405 if (res == SQL_NO_DATA) {
03406 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03407 ast_odbc_release_obj(obj);
03408 goto yuck;
03409 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03410 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03411 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03412 ast_odbc_release_obj(obj);
03413 goto yuck;
03414 }
03415 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03416 if (fd < 0) {
03417 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03418 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03419 ast_odbc_release_obj(obj);
03420 goto yuck;
03421 }
03422 res = SQLNumResultCols(stmt, &colcount);
03423 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03424 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03425 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03426 ast_odbc_release_obj(obj);
03427 goto yuck;
03428 }
03429 if (f)
03430 fprintf(f, "[message]\n");
03431 for (x = 0; x < colcount; x++) {
03432 rowdata[0] = '\0';
03433 colsize = 0;
03434 collen = sizeof(coltitle);
03435 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03436 &datatype, &colsize, &decimaldigits, &nullable);
03437 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03438 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03440 ast_odbc_release_obj(obj);
03441 goto yuck;
03442 }
03443 if (!strcasecmp(coltitle, "recording")) {
03444 off_t offset;
03445 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03446 fdlen = colsize2;
03447 if (fd > -1) {
03448 char tmp[1]="";
03449 lseek(fd, fdlen - 1, SEEK_SET);
03450 if (write(fd, tmp, 1) != 1) {
03451 close(fd);
03452 fd = -1;
03453 continue;
03454 }
03455
03456 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03457 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03458 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03459 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03460 ast_odbc_release_obj(obj);
03461 goto yuck;
03462 } else {
03463 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03464 munmap(fdm, CHUNKSIZE);
03465 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03466 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03467 unlink(full_fn);
03468 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03469 ast_odbc_release_obj(obj);
03470 goto yuck;
03471 }
03472 }
03473 }
03474 if (truncate(full_fn, fdlen) < 0) {
03475 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03476 }
03477 }
03478 } else {
03479 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03480 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03481 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03482 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03483 ast_odbc_release_obj(obj);
03484 goto yuck;
03485 }
03486 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03487 fprintf(f, "%s=%s\n", coltitle, rowdata);
03488 }
03489 }
03490 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03491 ast_odbc_release_obj(obj);
03492 } else
03493 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03494 yuck:
03495 if (f)
03496 fclose(f);
03497 if (fd > -1)
03498 close(fd);
03499 return x - 1;
03500 }
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03514 {
03515 int x = 0;
03516 int res;
03517 SQLHSTMT stmt;
03518 char sql[PATH_MAX];
03519 char rowdata[20];
03520 char *argv[] = { dir };
03521 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03522
03523 struct odbc_obj *obj;
03524 obj = ast_odbc_request_obj(odbc_database, 0);
03525 if (obj) {
03526 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03527
03528 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03529 if (!stmt) {
03530 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03531 ast_odbc_release_obj(obj);
03532 goto yuck;
03533 }
03534 res = SQLFetch(stmt);
03535 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03536 if (res == SQL_NO_DATA) {
03537 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03538 } else {
03539 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03540 }
03541
03542 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03543 ast_odbc_release_obj(obj);
03544 goto yuck;
03545 }
03546 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03547 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03548 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03549 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03550 ast_odbc_release_obj(obj);
03551 goto yuck;
03552 }
03553 if (sscanf(rowdata, "%30d", &x) != 1)
03554 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03555 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03556 ast_odbc_release_obj(obj);
03557 return x;
03558 } else
03559 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03560 yuck:
03561 return x - 1;
03562 }
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573 static int message_exists(char *dir, int msgnum)
03574 {
03575 int x = 0;
03576 int res;
03577 SQLHSTMT stmt;
03578 char sql[PATH_MAX];
03579 char rowdata[20];
03580 char msgnums[20];
03581 char *argv[] = { dir, msgnums };
03582 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03583
03584 struct odbc_obj *obj;
03585 obj = ast_odbc_request_obj(odbc_database, 0);
03586 if (obj) {
03587 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03588 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03589 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03590 if (!stmt) {
03591 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03592 ast_odbc_release_obj(obj);
03593 goto yuck;
03594 }
03595 res = SQLFetch(stmt);
03596 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03597 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03598 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03599 ast_odbc_release_obj(obj);
03600 goto yuck;
03601 }
03602 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03603 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03604 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03605 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03606 ast_odbc_release_obj(obj);
03607 goto yuck;
03608 }
03609 if (sscanf(rowdata, "%30d", &x) != 1)
03610 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03611 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03612 ast_odbc_release_obj(obj);
03613 } else
03614 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03615 yuck:
03616 return x;
03617 }
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628 static int count_messages(struct ast_vm_user *vmu, char *dir)
03629 {
03630 int x = 0;
03631 int res;
03632 SQLHSTMT stmt;
03633 char sql[PATH_MAX];
03634 char rowdata[20];
03635 char *argv[] = { dir };
03636 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03637
03638 struct odbc_obj *obj;
03639 obj = ast_odbc_request_obj(odbc_database, 0);
03640 if (obj) {
03641 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03642 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03643 if (!stmt) {
03644 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03645 ast_odbc_release_obj(obj);
03646 goto yuck;
03647 }
03648 res = SQLFetch(stmt);
03649 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03650 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03651 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03652 ast_odbc_release_obj(obj);
03653 goto yuck;
03654 }
03655 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03656 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03657 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03658 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03659 ast_odbc_release_obj(obj);
03660 goto yuck;
03661 }
03662 if (sscanf(rowdata, "%30d", &x) != 1)
03663 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03664 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03665 ast_odbc_release_obj(obj);
03666 return x;
03667 } else
03668 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03669 yuck:
03670 return x - 1;
03671
03672 }
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684 static void delete_file(const char *sdir, int smsg)
03685 {
03686 SQLHSTMT stmt;
03687 char sql[PATH_MAX];
03688 char msgnums[20];
03689 char *argv[] = { NULL, msgnums };
03690 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03691 struct odbc_obj *obj;
03692
03693 argv[0] = ast_strdupa(sdir);
03694
03695 obj = ast_odbc_request_obj(odbc_database, 0);
03696 if (obj) {
03697 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03698 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03699 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03700 if (!stmt)
03701 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03702 else
03703 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03704 ast_odbc_release_obj(obj);
03705 } else
03706 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03707 return;
03708 }
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03722 {
03723 SQLHSTMT stmt;
03724 char sql[512];
03725 char msgnums[20];
03726 char msgnumd[20];
03727 struct odbc_obj *obj;
03728 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03729 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03730
03731 delete_file(ddir, dmsg);
03732 obj = ast_odbc_request_obj(odbc_database, 0);
03733 if (obj) {
03734 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03735 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03736 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);
03737 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03738 if (!stmt)
03739 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03740 else
03741 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03742 ast_odbc_release_obj(obj);
03743 } else
03744 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03745 return;
03746 }
03747
03748 struct insert_data {
03749 char *sql;
03750 const char *dir;
03751 const char *msgnums;
03752 void *data;
03753 SQLLEN datalen;
03754 SQLLEN indlen;
03755 const char *context;
03756 const char *macrocontext;
03757 const char *callerid;
03758 const char *origtime;
03759 const char *duration;
03760 const char *mailboxuser;
03761 const char *mailboxcontext;
03762 const char *category;
03763 const char *flag;
03764 };
03765
03766 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03767 {
03768 struct insert_data *data = vdata;
03769 int res;
03770 SQLHSTMT stmt;
03771
03772 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03773 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03774 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03775 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03776 return NULL;
03777 }
03778
03779 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03780 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03781 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03782 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03783 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03784 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03785 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03786 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03787 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03788 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03789 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03790 if (!ast_strlen_zero(data->category)) {
03791 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03792 }
03793 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03794 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03795 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03797 return NULL;
03798 }
03799
03800 return stmt;
03801 }
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03817 {
03818 int res = 0;
03819 int fd = -1;
03820 void *fdm = MAP_FAILED;
03821 off_t fdlen = -1;
03822 SQLHSTMT stmt;
03823 char sql[PATH_MAX];
03824 char msgnums[20];
03825 char fn[PATH_MAX];
03826 char full_fn[PATH_MAX];
03827 char fmt[80]="";
03828 char *c;
03829 struct ast_config *cfg = NULL;
03830 struct odbc_obj *obj;
03831 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03832 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03833 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03834
03835 delete_file(dir, msgnum);
03836 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03837 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03838 return -1;
03839 }
03840
03841 do {
03842 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03843 c = strchr(fmt, '|');
03844 if (c)
03845 *c = '\0';
03846 if (!strcasecmp(fmt, "wav49"))
03847 strcpy(fmt, "WAV");
03848 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03849 if (msgnum > -1)
03850 make_file(fn, sizeof(fn), dir, msgnum);
03851 else
03852 ast_copy_string(fn, dir, sizeof(fn));
03853 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03854 cfg = ast_config_load(full_fn, config_flags);
03855 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03856 fd = open(full_fn, O_RDWR);
03857 if (fd < 0) {
03858 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03859 res = -1;
03860 break;
03861 }
03862 if (valid_config(cfg)) {
03863 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03864 idata.context = "";
03865 }
03866 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03867 idata.macrocontext = "";
03868 }
03869 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03870 idata.callerid = "";
03871 }
03872 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03873 idata.origtime = "";
03874 }
03875 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03876 idata.duration = "";
03877 }
03878 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03879 idata.category = "";
03880 }
03881 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03882 idata.flag = "";
03883 }
03884 }
03885 fdlen = lseek(fd, 0, SEEK_END);
03886 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03887 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03888 res = -1;
03889 break;
03890 }
03891 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03892 if (fdm == MAP_FAILED) {
03893 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03894 res = -1;
03895 break;
03896 }
03897 idata.data = fdm;
03898 idata.datalen = idata.indlen = fdlen;
03899
03900 if (!ast_strlen_zero(idata.category))
03901 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03902 else
03903 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03904
03905 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03906 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03907 } else {
03908 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03909 res = -1;
03910 }
03911 } while (0);
03912 if (obj) {
03913 ast_odbc_release_obj(obj);
03914 }
03915 if (valid_config(cfg))
03916 ast_config_destroy(cfg);
03917 if (fdm != MAP_FAILED)
03918 munmap(fdm, fdlen);
03919 if (fd > -1)
03920 close(fd);
03921 return res;
03922 }
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03938 {
03939 SQLHSTMT stmt;
03940 char sql[PATH_MAX];
03941 char msgnums[20];
03942 char msgnumd[20];
03943 struct odbc_obj *obj;
03944 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03945 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03946
03947 delete_file(ddir, dmsg);
03948 obj = ast_odbc_request_obj(odbc_database, 0);
03949 if (obj) {
03950 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03951 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03952 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03953 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03954 if (!stmt)
03955 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03956 else
03957 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03958 ast_odbc_release_obj(obj);
03959 } else
03960 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03961 return;
03962 }
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975 static int remove_file(char *dir, int msgnum)
03976 {
03977 char fn[PATH_MAX];
03978 char full_fn[PATH_MAX];
03979 char msgnums[80];
03980
03981 if (msgnum > -1) {
03982 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03983 make_file(fn, sizeof(fn), dir, msgnum);
03984 } else
03985 ast_copy_string(fn, dir, sizeof(fn));
03986 ast_filedelete(fn, NULL);
03987 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03988 unlink(full_fn);
03989 return 0;
03990 }
03991 #else
03992 #ifndef IMAP_STORAGE
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002 static int count_messages(struct ast_vm_user *vmu, char *dir)
04003 {
04004
04005 int vmcount = 0;
04006 DIR *vmdir = NULL;
04007 struct dirent *vment = NULL;
04008
04009 if (vm_lock_path(dir))
04010 return ERROR_LOCK_PATH;
04011
04012 if ((vmdir = opendir(dir))) {
04013 while ((vment = readdir(vmdir))) {
04014 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04015 vmcount++;
04016 }
04017 }
04018 closedir(vmdir);
04019 }
04020 ast_unlock_path(dir);
04021
04022 return vmcount;
04023 }
04024
04025
04026
04027
04028
04029
04030
04031
04032 static void rename_file(char *sfn, char *dfn)
04033 {
04034 char stxt[PATH_MAX];
04035 char dtxt[PATH_MAX];
04036 ast_filerename(sfn, dfn, NULL);
04037 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04038 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04039 if (ast_check_realtime("voicemail_data")) {
04040 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04041 }
04042 rename(stxt, dtxt);
04043 }
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04057 {
04058 int x;
04059 unsigned char map[MAXMSGLIMIT] = "";
04060 DIR *msgdir;
04061 struct dirent *msgdirent;
04062 int msgdirint;
04063 char extension[4];
04064 int stopcount = 0;
04065
04066
04067
04068
04069
04070 if (!(msgdir = opendir(dir))) {
04071 return -1;
04072 }
04073
04074 while ((msgdirent = readdir(msgdir))) {
04075 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04076 map[msgdirint] = 1;
04077 stopcount++;
04078 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04079 }
04080 }
04081 closedir(msgdir);
04082
04083 for (x = 0; x < vmu->maxmsg; x++) {
04084 if (map[x] == 1) {
04085 stopcount--;
04086 } else if (map[x] == 0 && !stopcount) {
04087 break;
04088 }
04089 }
04090
04091 return x - 1;
04092 }
04093
04094 #endif
04095 #endif
04096 #ifndef IMAP_STORAGE
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107 static int copy(char *infile, char *outfile)
04108 {
04109 int ifd;
04110 int ofd;
04111 int res;
04112 int len;
04113 char buf[4096];
04114
04115 #ifdef HARDLINK_WHEN_POSSIBLE
04116
04117 if (link(infile, outfile)) {
04118 #endif
04119 if ((ifd = open(infile, O_RDONLY)) < 0) {
04120 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04121 return -1;
04122 }
04123 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04124 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04125 close(ifd);
04126 return -1;
04127 }
04128 do {
04129 len = read(ifd, buf, sizeof(buf));
04130 if (len < 0) {
04131 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04132 close(ifd);
04133 close(ofd);
04134 unlink(outfile);
04135 } else if (len) {
04136 res = write(ofd, buf, len);
04137 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04138 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04139 close(ifd);
04140 close(ofd);
04141 unlink(outfile);
04142 }
04143 }
04144 } while (len);
04145 close(ifd);
04146 close(ofd);
04147 return 0;
04148 #ifdef HARDLINK_WHEN_POSSIBLE
04149 } else {
04150
04151 return 0;
04152 }
04153 #endif
04154 }
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165 static void copy_plain_file(char *frompath, char *topath)
04166 {
04167 char frompath2[PATH_MAX], topath2[PATH_MAX];
04168 struct ast_variable *tmp,*var = NULL;
04169 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04170 ast_filecopy(frompath, topath, NULL);
04171 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04172 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04173 if (ast_check_realtime("voicemail_data")) {
04174 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04175
04176 for (tmp = var; tmp; tmp = tmp->next) {
04177 if (!strcasecmp(tmp->name, "origmailbox")) {
04178 origmailbox = tmp->value;
04179 } else if (!strcasecmp(tmp->name, "context")) {
04180 context = tmp->value;
04181 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04182 macrocontext = tmp->value;
04183 } else if (!strcasecmp(tmp->name, "exten")) {
04184 exten = tmp->value;
04185 } else if (!strcasecmp(tmp->name, "priority")) {
04186 priority = tmp->value;
04187 } else if (!strcasecmp(tmp->name, "callerchan")) {
04188 callerchan = tmp->value;
04189 } else if (!strcasecmp(tmp->name, "callerid")) {
04190 callerid = tmp->value;
04191 } else if (!strcasecmp(tmp->name, "origdate")) {
04192 origdate = tmp->value;
04193 } else if (!strcasecmp(tmp->name, "origtime")) {
04194 origtime = tmp->value;
04195 } else if (!strcasecmp(tmp->name, "category")) {
04196 category = tmp->value;
04197 } else if (!strcasecmp(tmp->name, "duration")) {
04198 duration = tmp->value;
04199 }
04200 }
04201 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);
04202 }
04203 copy(frompath2, topath2);
04204 ast_variables_destroy(var);
04205 }
04206 #endif
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216 static int vm_delete(char *file)
04217 {
04218 char *txt;
04219 int txtsize = 0;
04220
04221 txtsize = (strlen(file) + 5)*sizeof(char);
04222 txt = ast_alloca(txtsize);
04223
04224
04225
04226 if (ast_check_realtime("voicemail_data")) {
04227 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04228 }
04229 snprintf(txt, txtsize, "%s.txt", file);
04230 unlink(txt);
04231 return ast_filedelete(file, NULL);
04232 }
04233
04234
04235
04236
04237 static int inbuf(struct baseio *bio, FILE *fi)
04238 {
04239 int l;
04240
04241 if (bio->ateof)
04242 return 0;
04243
04244 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04245 if (ferror(fi))
04246 return -1;
04247
04248 bio->ateof = 1;
04249 return 0;
04250 }
04251
04252 bio->iolen = l;
04253 bio->iocp = 0;
04254
04255 return 1;
04256 }
04257
04258
04259
04260
04261 static int inchar(struct baseio *bio, FILE *fi)
04262 {
04263 if (bio->iocp>=bio->iolen) {
04264 if (!inbuf(bio, fi))
04265 return EOF;
04266 }
04267
04268 return bio->iobuf[bio->iocp++];
04269 }
04270
04271
04272
04273
04274 static int ochar(struct baseio *bio, int c, FILE *so)
04275 {
04276 if (bio->linelength >= BASELINELEN) {
04277 if (fputs(ENDL, so) == EOF) {
04278 return -1;
04279 }
04280
04281 bio->linelength = 0;
04282 }
04283
04284 if (putc(((unsigned char) c), so) == EOF) {
04285 return -1;
04286 }
04287
04288 bio->linelength++;
04289
04290 return 1;
04291 }
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302 static int base_encode(char *filename, FILE *so)
04303 {
04304 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04305 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04306 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04307 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04308 int i, hiteof = 0;
04309 FILE *fi;
04310 struct baseio bio;
04311
04312 memset(&bio, 0, sizeof(bio));
04313 bio.iocp = BASEMAXINLINE;
04314
04315 if (!(fi = fopen(filename, "rb"))) {
04316 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04317 return -1;
04318 }
04319
04320 while (!hiteof){
04321 unsigned char igroup[3], ogroup[4];
04322 int c, n;
04323
04324 memset(igroup, 0, sizeof(igroup));
04325
04326 for (n = 0; n < 3; n++) {
04327 if ((c = inchar(&bio, fi)) == EOF) {
04328 hiteof = 1;
04329 break;
04330 }
04331
04332 igroup[n] = (unsigned char) c;
04333 }
04334
04335 if (n > 0) {
04336 ogroup[0]= dtable[igroup[0] >> 2];
04337 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04338 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04339 ogroup[3]= dtable[igroup[2] & 0x3F];
04340
04341 if (n < 3) {
04342 ogroup[3] = '=';
04343
04344 if (n < 2)
04345 ogroup[2] = '=';
04346 }
04347
04348 for (i = 0; i < 4; i++)
04349 ochar(&bio, ogroup[i], so);
04350 }
04351 }
04352
04353 fclose(fi);
04354
04355 if (fputs(ENDL, so) == EOF) {
04356 return 0;
04357 }
04358
04359 return 1;
04360 }
04361
04362 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, const char *category, const char *flag)
04363 {
04364 char callerid[256];
04365 char num[12];
04366 char fromdir[256], fromfile[256];
04367 struct ast_config *msg_cfg;
04368 const char *origcallerid, *origtime;
04369 char origcidname[80], origcidnum[80], origdate[80];
04370 int inttime;
04371 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04372
04373
04374 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04375 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04376 snprintf(num, sizeof(num), "%d", msgnum);
04377 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04378 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04379 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04380 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04381 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04382 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04383 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04384 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04385 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04386 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04387
04388
04389 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04390 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04391 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04392 strcat(fromfile, ".txt");
04393 }
04394 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04395 if (option_debug > 0) {
04396 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04397 }
04398 return;
04399 }
04400
04401 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04402 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04403 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04404 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04405 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04406 }
04407
04408 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04409 struct timeval tv = { inttime, };
04410 struct ast_tm tm;
04411 ast_localtime(&tv, &tm, NULL);
04412 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04413 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04414 }
04415 ast_config_destroy(msg_cfg);
04416 }
04417
04418
04419
04420
04421
04422
04423
04424
04425
04426 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04427 {
04428 const char *ptr;
04429
04430
04431 ast_str_set(buf, maxlen, "\"");
04432 for (ptr = from; *ptr; ptr++) {
04433 if (*ptr == '"' || *ptr == '\\') {
04434 ast_str_append(buf, maxlen, "\\%c", *ptr);
04435 } else {
04436 ast_str_append(buf, maxlen, "%c", *ptr);
04437 }
04438 }
04439 ast_str_append(buf, maxlen, "\"");
04440
04441 return ast_str_buffer(*buf);
04442 }
04443
04444
04445
04446
04447
04448 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04449 {
04450 const struct vm_zone *z = NULL;
04451 struct timeval t = ast_tvnow();
04452
04453
04454 if (!ast_strlen_zero(vmu->zonetag)) {
04455
04456 AST_LIST_LOCK(&zones);
04457 AST_LIST_TRAVERSE(&zones, z, list) {
04458 if (!strcmp(z->name, vmu->zonetag))
04459 break;
04460 }
04461 AST_LIST_UNLOCK(&zones);
04462 }
04463 ast_localtime(&t, tm, z ? z->timezone : NULL);
04464 return tm;
04465 }
04466
04467
04468
04469
04470
04471 static int check_mime(const char *str)
04472 {
04473 for (; *str; str++) {
04474 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04475 return 1;
04476 }
04477 }
04478 return 0;
04479 }
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04499 {
04500 struct ast_str *tmp = ast_str_alloca(80);
04501 int first_section = 1;
04502
04503 ast_str_reset(*end);
04504 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04505 for (; *start; start++) {
04506 int need_encoding = 0;
04507 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04508 need_encoding = 1;
04509 }
04510 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04511 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04512 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04513 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04514
04515 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04516 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04517 first_section = 0;
04518 }
04519 if (need_encoding && *start == ' ') {
04520 ast_str_append(&tmp, -1, "_");
04521 } else if (need_encoding) {
04522 ast_str_append(&tmp, -1, "=%hhX", *start);
04523 } else {
04524 ast_str_append(&tmp, -1, "%c", *start);
04525 }
04526 }
04527 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04528 return ast_str_buffer(*end);
04529 }
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554 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)
04555 {
04556 char date[256];
04557 char host[MAXHOSTNAMELEN] = "";
04558 char who[256];
04559 char bound[256];
04560 char dur[256];
04561 struct ast_tm tm;
04562 char enc_cidnum[256] = "", enc_cidname[256] = "";
04563 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04564 char *greeting_attachment;
04565 char filename[256];
04566
04567 if (!str1 || !str2) {
04568 ast_free(str1);
04569 ast_free(str2);
04570 return;
04571 }
04572
04573 if (cidnum) {
04574 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04575 }
04576 if (cidname) {
04577 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04578 }
04579 gethostname(host, sizeof(host) - 1);
04580
04581 if (strchr(srcemail, '@')) {
04582 ast_copy_string(who, srcemail, sizeof(who));
04583 } else {
04584 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04585 }
04586
04587 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04588 if (greeting_attachment) {
04589 *greeting_attachment++ = '\0';
04590 }
04591
04592 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04593 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04594 fprintf(p, "Date: %s" ENDL, date);
04595
04596
04597 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04598
04599 if (!ast_strlen_zero(fromstring)) {
04600 struct ast_channel *ast;
04601 if ((ast = ast_dummy_channel_alloc())) {
04602 char *ptr;
04603 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04604 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04605
04606 if (check_mime(ast_str_buffer(str1))) {
04607 int first_line = 1;
04608 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04609 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04610 *ptr = '\0';
04611 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04612 first_line = 0;
04613
04614 ast_str_set(&str2, 0, "%s", ptr + 1);
04615 }
04616 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04617 } else {
04618 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04619 }
04620 ast = ast_channel_unref(ast);
04621 } else {
04622 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04623 }
04624 } else {
04625 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04626 }
04627
04628 if (check_mime(vmu->fullname)) {
04629 int first_line = 1;
04630 char *ptr;
04631 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04632 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04633 *ptr = '\0';
04634 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04635 first_line = 0;
04636
04637 ast_str_set(&str2, 0, "%s", ptr + 1);
04638 }
04639 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04640 } else {
04641 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04642 }
04643
04644 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04645 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04646 struct ast_channel *ast;
04647 if ((ast = ast_dummy_channel_alloc())) {
04648 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04649 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04650 if (check_mime(ast_str_buffer(str1))) {
04651 int first_line = 1;
04652 char *ptr;
04653 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04654 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04655 *ptr = '\0';
04656 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04657 first_line = 0;
04658
04659 ast_str_set(&str2, 0, "%s", ptr + 1);
04660 }
04661 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04662 } else {
04663 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04664 }
04665 ast = ast_channel_unref(ast);
04666 } else {
04667 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04668 }
04669 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04670 if (ast_strlen_zero(flag)) {
04671 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04672 } else {
04673 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04674 }
04675 } else {
04676 if (ast_strlen_zero(flag)) {
04677 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04678 } else {
04679 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04680 }
04681 }
04682
04683 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04684 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04685 if (imap) {
04686
04687 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04688
04689 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04690 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04691 #ifdef IMAP_STORAGE
04692 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04693 #else
04694 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04695 #endif
04696
04697 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04698 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04699 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04700 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04701 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04702 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04703 if (!ast_strlen_zero(category)) {
04704 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04705 } else {
04706 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04707 }
04708 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04709 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04710 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04711 }
04712 if (!ast_strlen_zero(cidnum)) {
04713 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04714 }
04715 if (!ast_strlen_zero(cidname)) {
04716 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04717 }
04718 fprintf(p, "MIME-Version: 1.0" ENDL);
04719 if (attach_user_voicemail) {
04720
04721 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04722 (int) getpid(), (unsigned int) ast_random());
04723
04724 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04725 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04726 fprintf(p, "--%s" ENDL, bound);
04727 }
04728 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04729 if (emailbody || vmu->emailbody) {
04730 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04731 struct ast_channel *ast;
04732 if ((ast = ast_dummy_channel_alloc())) {
04733 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04734 ast_str_substitute_variables(&str1, 0, ast, e_body);
04735 #ifdef IMAP_STORAGE
04736 {
04737
04738 char *line = ast_str_buffer(str1), *next;
04739 do {
04740
04741 if ((next = strchr(line, '\n'))) {
04742 *next++ = '\0';
04743 }
04744 fprintf(p, "%s" ENDL, line);
04745 line = next;
04746 } while (!ast_strlen_zero(line));
04747 }
04748 #else
04749 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04750 #endif
04751 ast = ast_channel_unref(ast);
04752 } else {
04753 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04754 }
04755 } else if (msgnum > -1) {
04756 if (strcmp(vmu->mailbox, mailbox)) {
04757
04758 struct ast_config *msg_cfg;
04759 const char *v;
04760 int inttime;
04761 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04762 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04763
04764 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04765 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04766 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04767 strcat(fromfile, ".txt");
04768 }
04769 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04770 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04771 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04772 }
04773
04774
04775
04776 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04777 struct timeval tv = { inttime, };
04778 struct ast_tm tm;
04779 ast_localtime(&tv, &tm, NULL);
04780 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04781 }
04782 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04783 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04784 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04785 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04786 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04787 date, origcallerid, origdate);
04788 ast_config_destroy(msg_cfg);
04789 } else {
04790 goto plain_message;
04791 }
04792 } else {
04793 plain_message:
04794 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04795 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04796 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04797 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04798 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04799 }
04800 } else {
04801 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04802 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04803 }
04804
04805 if (imap || attach_user_voicemail) {
04806 if (!ast_strlen_zero(attach2)) {
04807 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04808 ast_debug(5, "creating second attachment filename %s\n", filename);
04809 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04810 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04811 ast_debug(5, "creating attachment filename %s\n", filename);
04812 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04813 } else {
04814 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04815 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04816 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04817 }
04818 }
04819 ast_free(str1);
04820 ast_free(str2);
04821 }
04822
04823 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)
04824 {
04825 char tmpdir[256], newtmp[256];
04826 char fname[256];
04827 char tmpcmd[256];
04828 int tmpfd = -1;
04829 int soxstatus = 0;
04830
04831
04832 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04833
04834 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04835 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04836 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04837 tmpfd = mkstemp(newtmp);
04838 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04839 ast_debug(3, "newtmp: %s\n", newtmp);
04840 if (tmpfd > -1) {
04841 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04842 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04843 attach = newtmp;
04844 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04845 } else {
04846 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04847 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04848 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04849 }
04850 }
04851 }
04852 fprintf(p, "--%s" ENDL, bound);
04853 if (msgnum > -1)
04854 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04855 else
04856 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04857 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04858 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04859 if (msgnum > -1)
04860 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04861 else
04862 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04863 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04864 base_encode(fname, p);
04865 if (last)
04866 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04867 if (tmpfd > -1) {
04868 if (soxstatus == 0) {
04869 unlink(fname);
04870 }
04871 close(tmpfd);
04872 unlink(newtmp);
04873 }
04874 return 0;
04875 }
04876
04877 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)
04878 {
04879 FILE *p = NULL;
04880 char tmp[80] = "/tmp/astmail-XXXXXX";
04881 char tmp2[256];
04882 char *stringp;
04883
04884 if (vmu && ast_strlen_zero(vmu->email)) {
04885 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04886 return(0);
04887 }
04888
04889
04890 format = ast_strdupa(format);
04891 stringp = format;
04892 strsep(&stringp, "|");
04893
04894 if (!strcmp(format, "wav49"))
04895 format = "WAV";
04896 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));
04897
04898
04899 if ((p = vm_mkftemp(tmp)) == NULL) {
04900 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04901 return -1;
04902 } else {
04903 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04904 fclose(p);
04905 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04906 ast_safe_system(tmp2);
04907 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04908 }
04909 return 0;
04910 }
04911
04912 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)
04913 {
04914 char enc_cidnum[256], enc_cidname[256];
04915 char date[256];
04916 char host[MAXHOSTNAMELEN] = "";
04917 char who[256];
04918 char dur[PATH_MAX];
04919 char tmp[80] = "/tmp/astmail-XXXXXX";
04920 char tmp2[PATH_MAX];
04921 struct ast_tm tm;
04922 FILE *p;
04923 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04924
04925 if (!str1 || !str2) {
04926 ast_free(str1);
04927 ast_free(str2);
04928 return -1;
04929 }
04930
04931 if (cidnum) {
04932 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04933 }
04934 if (cidname) {
04935 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04936 }
04937
04938 if ((p = vm_mkftemp(tmp)) == NULL) {
04939 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04940 ast_free(str1);
04941 ast_free(str2);
04942 return -1;
04943 }
04944 gethostname(host, sizeof(host)-1);
04945 if (strchr(srcemail, '@')) {
04946 ast_copy_string(who, srcemail, sizeof(who));
04947 } else {
04948 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04949 }
04950 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04951 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04952 fprintf(p, "Date: %s\n", date);
04953
04954
04955 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04956
04957 if (!ast_strlen_zero(pagerfromstring)) {
04958 struct ast_channel *ast;
04959 if ((ast = ast_dummy_channel_alloc())) {
04960 char *ptr;
04961 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04962 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04963
04964 if (check_mime(ast_str_buffer(str1))) {
04965 int first_line = 1;
04966 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04967 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04968 *ptr = '\0';
04969 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04970 first_line = 0;
04971
04972 ast_str_set(&str2, 0, "%s", ptr + 1);
04973 }
04974 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04975 } else {
04976 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04977 }
04978 ast = ast_channel_unref(ast);
04979 } else {
04980 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04981 }
04982 } else {
04983 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04984 }
04985
04986 if (check_mime(vmu->fullname)) {
04987 int first_line = 1;
04988 char *ptr;
04989 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04990 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04991 *ptr = '\0';
04992 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04993 first_line = 0;
04994
04995 ast_str_set(&str2, 0, "%s", ptr + 1);
04996 }
04997 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04998 } else {
04999 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05000 }
05001
05002 if (!ast_strlen_zero(pagersubject)) {
05003 struct ast_channel *ast;
05004 if ((ast = ast_dummy_channel_alloc())) {
05005 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05006 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05007 if (check_mime(ast_str_buffer(str1))) {
05008 int first_line = 1;
05009 char *ptr;
05010 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05011 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05012 *ptr = '\0';
05013 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05014 first_line = 0;
05015
05016 ast_str_set(&str2, 0, "%s", ptr + 1);
05017 }
05018 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05019 } else {
05020 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05021 }
05022 ast = ast_channel_unref(ast);
05023 } else {
05024 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05025 }
05026 } else {
05027 if (ast_strlen_zero(flag)) {
05028 fprintf(p, "Subject: New VM\n\n");
05029 } else {
05030 fprintf(p, "Subject: New %s VM\n\n", flag);
05031 }
05032 }
05033
05034 if (pagerbody) {
05035 struct ast_channel *ast;
05036 if ((ast = ast_dummy_channel_alloc())) {
05037 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05038 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05039 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05040 ast = ast_channel_unref(ast);
05041 } else {
05042 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05043 }
05044 } else {
05045 fprintf(p, "New %s long %s msg in box %s\n"
05046 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05047 }
05048
05049 fclose(p);
05050 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05051 ast_safe_system(tmp2);
05052 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05053 ast_free(str1);
05054 ast_free(str2);
05055 return 0;
05056 }
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067 static int get_date(char *s, int len)
05068 {
05069 struct ast_tm tm;
05070 struct timeval t = ast_tvnow();
05071
05072 ast_localtime(&t, &tm, "UTC");
05073
05074 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05075 }
05076
05077 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05078 {
05079 int res;
05080 char fn[PATH_MAX];
05081 char dest[PATH_MAX];
05082
05083 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05084
05085 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05086 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05087 return -1;
05088 }
05089
05090 RETRIEVE(fn, -1, ext, context);
05091 if (ast_fileexists(fn, NULL, NULL) > 0) {
05092 res = ast_stream_and_wait(chan, fn, ecodes);
05093 if (res) {
05094 DISPOSE(fn, -1);
05095 return res;
05096 }
05097 } else {
05098
05099 DISPOSE(fn, -1);
05100 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05101 if (res)
05102 return res;
05103 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05104 if (res)
05105 return res;
05106 }
05107 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05108 return res;
05109 }
05110
05111 static void free_zone(struct vm_zone *z)
05112 {
05113 ast_free(z);
05114 }
05115
05116 #ifdef ODBC_STORAGE
05117 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05118 {
05119 int x = -1;
05120 int res;
05121 SQLHSTMT stmt = NULL;
05122 char sql[PATH_MAX];
05123 char rowdata[20];
05124 char tmp[PATH_MAX] = "";
05125 struct odbc_obj *obj = NULL;
05126 char *context;
05127 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05128
05129 if (newmsgs)
05130 *newmsgs = 0;
05131 if (oldmsgs)
05132 *oldmsgs = 0;
05133 if (urgentmsgs)
05134 *urgentmsgs = 0;
05135
05136
05137 if (ast_strlen_zero(mailbox))
05138 return 0;
05139
05140 ast_copy_string(tmp, mailbox, sizeof(tmp));
05141
05142 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05143 int u, n, o;
05144 char *next, *remaining = tmp;
05145 while ((next = strsep(&remaining, " ,"))) {
05146 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05147 return -1;
05148 }
05149 if (urgentmsgs) {
05150 *urgentmsgs += u;
05151 }
05152 if (newmsgs) {
05153 *newmsgs += n;
05154 }
05155 if (oldmsgs) {
05156 *oldmsgs += o;
05157 }
05158 }
05159 return 0;
05160 }
05161
05162 context = strchr(tmp, '@');
05163 if (context) {
05164 *context = '\0';
05165 context++;
05166 } else
05167 context = "default";
05168
05169 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05170 do {
05171 if (newmsgs) {
05172 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05173 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05174 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05175 break;
05176 }
05177 res = SQLFetch(stmt);
05178 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05179 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05180 break;
05181 }
05182 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05183 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05184 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05185 break;
05186 }
05187 *newmsgs = atoi(rowdata);
05188 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05189 }
05190
05191 if (oldmsgs) {
05192 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05193 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05194 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05195 break;
05196 }
05197 res = SQLFetch(stmt);
05198 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05199 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05200 break;
05201 }
05202 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05203 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05204 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05205 break;
05206 }
05207 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05208 *oldmsgs = atoi(rowdata);
05209 }
05210
05211 if (urgentmsgs) {
05212 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05213 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05214 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05215 break;
05216 }
05217 res = SQLFetch(stmt);
05218 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05219 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05220 break;
05221 }
05222 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05223 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05224 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05225 break;
05226 }
05227 *urgentmsgs = atoi(rowdata);
05228 }
05229
05230 x = 0;
05231 } while (0);
05232 } else {
05233 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05234 }
05235
05236 if (stmt) {
05237 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05238 }
05239 if (obj) {
05240 ast_odbc_release_obj(obj);
05241 }
05242 return x;
05243 }
05244
05245
05246
05247
05248
05249
05250
05251
05252
05253
05254 static int messagecount(const char *context, const char *mailbox, const char *folder)
05255 {
05256 struct odbc_obj *obj = NULL;
05257 int nummsgs = 0;
05258 int res;
05259 SQLHSTMT stmt = NULL;
05260 char sql[PATH_MAX];
05261 char rowdata[20];
05262 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05263 if (!folder)
05264 folder = "INBOX";
05265
05266 if (ast_strlen_zero(mailbox))
05267 return 0;
05268
05269 obj = ast_odbc_request_obj(odbc_database, 0);
05270 if (obj) {
05271 if (!strcmp(folder, "INBOX")) {
05272 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
05273 } else {
05274 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05275 }
05276 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05277 if (!stmt) {
05278 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05279 goto yuck;
05280 }
05281 res = SQLFetch(stmt);
05282 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05283 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05284 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05285 goto yuck;
05286 }
05287 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05288 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05289 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05290 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05291 goto yuck;
05292 }
05293 nummsgs = atoi(rowdata);
05294 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05295 } else
05296 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05297
05298 yuck:
05299 if (obj)
05300 ast_odbc_release_obj(obj);
05301 return nummsgs;
05302 }
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312 static int has_voicemail(const char *mailbox, const char *folder)
05313 {
05314 char tmp[256], *tmp2 = tmp, *box, *context;
05315 ast_copy_string(tmp, mailbox, sizeof(tmp));
05316 while ((context = box = strsep(&tmp2, ",&"))) {
05317 strsep(&context, "@");
05318 if (ast_strlen_zero(context))
05319 context = "default";
05320 if (messagecount(context, box, folder))
05321 return 1;
05322 }
05323 return 0;
05324 }
05325 #endif
05326 #ifndef IMAP_STORAGE
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337
05338
05339
05340
05341
05342
05343 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)
05344 {
05345 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05346 const char *frombox = mbox(vmu, imbox);
05347 const char *userfolder;
05348 int recipmsgnum;
05349 int res = 0;
05350
05351 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05352
05353 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05354 userfolder = "Urgent";
05355 } else {
05356 userfolder = "INBOX";
05357 }
05358
05359 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05360
05361 if (!dir)
05362 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05363 else
05364 ast_copy_string(fromdir, dir, sizeof(fromdir));
05365
05366 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05367 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05368
05369 if (vm_lock_path(todir))
05370 return ERROR_LOCK_PATH;
05371
05372 recipmsgnum = last_message_index(recip, todir) + 1;
05373 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05374 make_file(topath, sizeof(topath), todir, recipmsgnum);
05375 #ifndef ODBC_STORAGE
05376 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05377 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05378 } else {
05379 #endif
05380
05381
05382
05383 copy_plain_file(frompath, topath);
05384 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05385 vm_delete(topath);
05386 #ifndef ODBC_STORAGE
05387 }
05388 #endif
05389 } else {
05390 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05391 res = -1;
05392 }
05393 ast_unlock_path(todir);
05394 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05395 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05396 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05397 flag);
05398
05399 return res;
05400 }
05401 #endif
05402 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05403
05404 static int messagecount(const char *context, const char *mailbox, const char *folder)
05405 {
05406 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05407 }
05408
05409 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05410 {
05411 DIR *dir;
05412 struct dirent *de;
05413 char fn[256];
05414 int ret = 0;
05415
05416
05417 if (ast_strlen_zero(mailbox))
05418 return 0;
05419
05420 if (ast_strlen_zero(folder))
05421 folder = "INBOX";
05422 if (ast_strlen_zero(context))
05423 context = "default";
05424
05425 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05426
05427 if (!(dir = opendir(fn)))
05428 return 0;
05429
05430 while ((de = readdir(dir))) {
05431 if (!strncasecmp(de->d_name, "msg", 3)) {
05432 if (shortcircuit) {
05433 ret = 1;
05434 break;
05435 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05436 ret++;
05437 }
05438 }
05439 }
05440
05441 closedir(dir);
05442
05443 return ret;
05444 }
05445
05446
05447
05448
05449
05450
05451
05452
05453
05454
05455 static int has_voicemail(const char *mailbox, const char *folder)
05456 {
05457 char tmp[256], *tmp2 = tmp, *box, *context;
05458 ast_copy_string(tmp, mailbox, sizeof(tmp));
05459 if (ast_strlen_zero(folder)) {
05460 folder = "INBOX";
05461 }
05462 while ((box = strsep(&tmp2, ",&"))) {
05463 if ((context = strchr(box, '@')))
05464 *context++ = '\0';
05465 else
05466 context = "default";
05467 if (__has_voicemail(context, box, folder, 1))
05468 return 1;
05469
05470 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05471 return 1;
05472 }
05473 }
05474 return 0;
05475 }
05476
05477
05478 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05479 {
05480 char tmp[256];
05481 char *context;
05482
05483
05484 if (ast_strlen_zero(mailbox))
05485 return 0;
05486
05487 if (newmsgs)
05488 *newmsgs = 0;
05489 if (oldmsgs)
05490 *oldmsgs = 0;
05491 if (urgentmsgs)
05492 *urgentmsgs = 0;
05493
05494 if (strchr(mailbox, ',')) {
05495 int tmpnew, tmpold, tmpurgent;
05496 char *mb, *cur;
05497
05498 ast_copy_string(tmp, mailbox, sizeof(tmp));
05499 mb = tmp;
05500 while ((cur = strsep(&mb, ", "))) {
05501 if (!ast_strlen_zero(cur)) {
05502 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05503 return -1;
05504 else {
05505 if (newmsgs)
05506 *newmsgs += tmpnew;
05507 if (oldmsgs)
05508 *oldmsgs += tmpold;
05509 if (urgentmsgs)
05510 *urgentmsgs += tmpurgent;
05511 }
05512 }
05513 }
05514 return 0;
05515 }
05516
05517 ast_copy_string(tmp, mailbox, sizeof(tmp));
05518
05519 if ((context = strchr(tmp, '@')))
05520 *context++ = '\0';
05521 else
05522 context = "default";
05523
05524 if (newmsgs)
05525 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05526 if (oldmsgs)
05527 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05528 if (urgentmsgs)
05529 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05530
05531 return 0;
05532 }
05533
05534 #endif
05535
05536
05537 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05538 {
05539 int urgentmsgs = 0;
05540 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05541 if (newmsgs) {
05542 *newmsgs += urgentmsgs;
05543 }
05544 return res;
05545 }
05546
05547 static void run_externnotify(char *context, char *extension, const char *flag)
05548 {
05549 char arguments[255];
05550 char ext_context[256] = "";
05551 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05552 struct ast_smdi_mwi_message *mwi_msg;
05553
05554 if (!ast_strlen_zero(context))
05555 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05556 else
05557 ast_copy_string(ext_context, extension, sizeof(ext_context));
05558
05559 if (smdi_iface) {
05560 if (ast_app_has_voicemail(ext_context, NULL))
05561 ast_smdi_mwi_set(smdi_iface, extension);
05562 else
05563 ast_smdi_mwi_unset(smdi_iface, extension);
05564
05565 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05566 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05567 if (!strncmp(mwi_msg->cause, "INV", 3))
05568 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05569 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05570 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05571 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05572 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05573 } else {
05574 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05575 }
05576 }
05577
05578 if (!ast_strlen_zero(externnotify)) {
05579 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05580 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05581 } else {
05582 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05583 externnotify, S_OR(context, "\"\""),
05584 extension, newvoicemails,
05585 oldvoicemails, urgentvoicemails);
05586 ast_debug(1, "Executing %s\n", arguments);
05587 ast_safe_system(arguments);
05588 }
05589 }
05590 }
05591
05592
05593
05594
05595
05596
05597 struct leave_vm_options {
05598 unsigned int flags;
05599 signed char record_gain;
05600 char *exitcontext;
05601 };
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05614 {
05615 #ifdef IMAP_STORAGE
05616 int newmsgs, oldmsgs;
05617 #else
05618 char urgdir[PATH_MAX];
05619 #endif
05620 char txtfile[PATH_MAX];
05621 char tmptxtfile[PATH_MAX];
05622 struct vm_state *vms = NULL;
05623 char callerid[256];
05624 FILE *txt;
05625 char date[256];
05626 int txtdes;
05627 int res = 0;
05628 int msgnum;
05629 int duration = 0;
05630 int sound_duration = 0;
05631 int ausemacro = 0;
05632 int ousemacro = 0;
05633 int ouseexten = 0;
05634 char tmpdur[16];
05635 char priority[16];
05636 char origtime[16];
05637 char dir[PATH_MAX];
05638 char tmpdir[PATH_MAX];
05639 char fn[PATH_MAX];
05640 char prefile[PATH_MAX] = "";
05641 char tempfile[PATH_MAX] = "";
05642 char ext_context[256] = "";
05643 char fmt[80];
05644 char *context;
05645 char ecodes[17] = "#";
05646 struct ast_str *tmp = ast_str_create(16);
05647 char *tmpptr;
05648 struct ast_vm_user *vmu;
05649 struct ast_vm_user svm;
05650 const char *category = NULL;
05651 const char *code;
05652 const char *alldtmf = "0123456789ABCD*#";
05653 char flag[80];
05654
05655 if (!tmp) {
05656 return -1;
05657 }
05658
05659 ast_str_set(&tmp, 0, "%s", ext);
05660 ext = ast_str_buffer(tmp);
05661 if ((context = strchr(ext, '@'))) {
05662 *context++ = '\0';
05663 tmpptr = strchr(context, '&');
05664 } else {
05665 tmpptr = strchr(ext, '&');
05666 }
05667
05668 if (tmpptr)
05669 *tmpptr++ = '\0';
05670
05671 ast_channel_lock(chan);
05672 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05673 category = ast_strdupa(category);
05674 }
05675 ast_channel_unlock(chan);
05676
05677 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05678 ast_copy_string(flag, "Urgent", sizeof(flag));
05679 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05680 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05681 } else {
05682 flag[0] = '\0';
05683 }
05684
05685 ast_debug(3, "Before find_user\n");
05686 if (!(vmu = find_user(&svm, context, ext))) {
05687 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05688 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05689 ast_free(tmp);
05690 return res;
05691 }
05692
05693 if (strcmp(vmu->context, "default"))
05694 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05695 else
05696 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05697
05698
05699
05700
05701
05702
05703 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05704 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05705 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05706 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05707 }
05708
05709
05710
05711
05712 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05713 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05714 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05715 ast_free(tmp);
05716 return -1;
05717 }
05718 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05719 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05720 ast_copy_string(prefile, tempfile, sizeof(prefile));
05721
05722 DISPOSE(tempfile, -1);
05723
05724 #ifndef IMAP_STORAGE
05725 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05726 #else
05727 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05728 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05729 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05730 }
05731 #endif
05732
05733
05734 if (ast_test_flag(vmu, VM_OPERATOR)) {
05735 if (!ast_strlen_zero(vmu->exit)) {
05736 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05737 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05738 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05739 ouseexten = 1;
05740 }
05741 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05742 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05743 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05744 ouseexten = 1;
05745 } else if (!ast_strlen_zero(chan->macrocontext)
05746 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05747 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05748 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05749 ousemacro = 1;
05750 }
05751 }
05752
05753 if (!ast_strlen_zero(vmu->exit)) {
05754 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05755 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05756 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05757 }
05758 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05759 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05760 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05761 } else if (!ast_strlen_zero(chan->macrocontext)
05762 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05763 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05764 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05765 ausemacro = 1;
05766 }
05767
05768 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05769 for (code = alldtmf; *code; code++) {
05770 char e[2] = "";
05771 e[0] = *code;
05772 if (strchr(ecodes, e[0]) == NULL
05773 && ast_canmatch_extension(chan,
05774 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05775 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05776 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05777 }
05778 }
05779 }
05780
05781
05782 if (!ast_strlen_zero(prefile)) {
05783 #ifdef ODBC_STORAGE
05784 int success =
05785 #endif
05786 RETRIEVE(prefile, -1, ext, context);
05787 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05788 if (ast_streamfile(chan, prefile, chan->language) > -1)
05789 res = ast_waitstream(chan, ecodes);
05790 #ifdef ODBC_STORAGE
05791 if (success == -1) {
05792
05793 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05794 store_file(prefile, vmu->mailbox, vmu->context, -1);
05795 }
05796 #endif
05797 } else {
05798 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05799 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05800 }
05801 DISPOSE(prefile, -1);
05802 if (res < 0) {
05803 ast_debug(1, "Hang up during prefile playback\n");
05804 free_user(vmu);
05805 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05806 ast_free(tmp);
05807 return -1;
05808 }
05809 }
05810 if (res == '#') {
05811
05812 ast_set_flag(options, OPT_SILENT);
05813 res = 0;
05814 }
05815
05816 if (vmu->maxmsg == 0) {
05817 if (option_debug > 2)
05818 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05819 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05820 goto leave_vm_out;
05821 }
05822 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05823 res = ast_stream_and_wait(chan, INTRO, ecodes);
05824 if (res == '#') {
05825 ast_set_flag(options, OPT_SILENT);
05826 res = 0;
05827 }
05828 }
05829 if (res > 0)
05830 ast_stopstream(chan);
05831
05832
05833 if (res == '*') {
05834 chan->exten[0] = 'a';
05835 chan->exten[1] = '\0';
05836 if (!ast_strlen_zero(vmu->exit)) {
05837 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05838 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05839 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05840 }
05841 chan->priority = 0;
05842 free_user(vmu);
05843 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05844 ast_free(tmp);
05845 return 0;
05846 }
05847
05848
05849 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05850 transfer:
05851 if (ouseexten || ousemacro) {
05852 chan->exten[0] = 'o';
05853 chan->exten[1] = '\0';
05854 if (!ast_strlen_zero(vmu->exit)) {
05855 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05856 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05857 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05858 }
05859 ast_play_and_wait(chan, "transfer");
05860 chan->priority = 0;
05861 free_user(vmu);
05862 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05863 }
05864 ast_free(tmp);
05865 return OPERATOR_EXIT;
05866 }
05867
05868
05869 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05870 if (!ast_strlen_zero(options->exitcontext)) {
05871 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05872 }
05873 free_user(vmu);
05874 ast_free(tmp);
05875 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05876 return res;
05877 }
05878
05879 if (res < 0) {
05880 free_user(vmu);
05881 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05882 ast_free(tmp);
05883 return -1;
05884 }
05885
05886 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05887 if (!ast_strlen_zero(fmt)) {
05888 msgnum = 0;
05889
05890 #ifdef IMAP_STORAGE
05891
05892
05893 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05894 if (res < 0) {
05895 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05896 ast_free(tmp);
05897 return -1;
05898 }
05899 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05900
05901
05902
05903
05904 if (!(vms = create_vm_state_from_user(vmu))) {
05905 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05906 ast_free(tmp);
05907 return -1;
05908 }
05909 }
05910 vms->newmessages++;
05911
05912
05913 msgnum = newmsgs + oldmsgs;
05914 ast_debug(3, "Messagecount set to %d\n", msgnum);
05915 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05916
05917 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05918
05919 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05920 goto leave_vm_out;
05921 }
05922 #else
05923 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05924 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05925 if (!res)
05926 res = ast_waitstream(chan, "");
05927 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05928 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05929 inprocess_count(vmu->mailbox, vmu->context, -1);
05930 goto leave_vm_out;
05931 }
05932
05933 #endif
05934 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05935 txtdes = mkstemp(tmptxtfile);
05936 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05937 if (txtdes < 0) {
05938 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05939 if (!res)
05940 res = ast_waitstream(chan, "");
05941 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05942 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05943 inprocess_count(vmu->mailbox, vmu->context, -1);
05944 goto leave_vm_out;
05945 }
05946
05947
05948 if (res >= 0) {
05949
05950 res = ast_stream_and_wait(chan, "beep", "");
05951 }
05952
05953
05954 if (ast_check_realtime("voicemail_data")) {
05955 snprintf(priority, sizeof(priority), "%d", chan->priority);
05956 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05957 get_date(date, sizeof(date));
05958 ast_callerid_merge(callerid, sizeof(callerid),
05959 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05960 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05961 "Unknown");
05962 ast_store_realtime("voicemail_data",
05963 "origmailbox", ext,
05964 "context", chan->context,
05965 "macrocontext", chan->macrocontext,
05966 "exten", chan->exten,
05967 "priority", priority,
05968 "callerchan", chan->name,
05969 "callerid", callerid,
05970 "origdate", date,
05971 "origtime", origtime,
05972 "category", S_OR(category, ""),
05973 "filename", tmptxtfile,
05974 SENTINEL);
05975 }
05976
05977
05978 txt = fdopen(txtdes, "w+");
05979 if (txt) {
05980 get_date(date, sizeof(date));
05981 ast_callerid_merge(callerid, sizeof(callerid),
05982 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05983 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05984 "Unknown");
05985 fprintf(txt,
05986 ";\n"
05987 "; Message Information file\n"
05988 ";\n"
05989 "[message]\n"
05990 "origmailbox=%s\n"
05991 "context=%s\n"
05992 "macrocontext=%s\n"
05993 "exten=%s\n"
05994 "rdnis=%s\n"
05995 "priority=%d\n"
05996 "callerchan=%s\n"
05997 "callerid=%s\n"
05998 "origdate=%s\n"
05999 "origtime=%ld\n"
06000 "category=%s\n",
06001 ext,
06002 chan->context,
06003 chan->macrocontext,
06004 chan->exten,
06005 S_COR(chan->redirecting.from.number.valid,
06006 chan->redirecting.from.number.str, "unknown"),
06007 chan->priority,
06008 chan->name,
06009 callerid,
06010 date, (long) time(NULL),
06011 category ? category : "");
06012 } else {
06013 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06014 inprocess_count(vmu->mailbox, vmu->context, -1);
06015 if (ast_check_realtime("voicemail_data")) {
06016 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06017 }
06018 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06019 goto leave_vm_out;
06020 }
06021 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06022
06023 if (txt) {
06024 fprintf(txt, "flag=%s\n", flag);
06025 if (sound_duration < vmu->minsecs) {
06026 fclose(txt);
06027 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06028 ast_filedelete(tmptxtfile, NULL);
06029 unlink(tmptxtfile);
06030 if (ast_check_realtime("voicemail_data")) {
06031 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06032 }
06033 inprocess_count(vmu->mailbox, vmu->context, -1);
06034 } else {
06035 fprintf(txt, "duration=%d\n", duration);
06036 fclose(txt);
06037 if (vm_lock_path(dir)) {
06038 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06039
06040 ast_filedelete(tmptxtfile, NULL);
06041 unlink(tmptxtfile);
06042 inprocess_count(vmu->mailbox, vmu->context, -1);
06043 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06044 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06045 unlink(tmptxtfile);
06046 ast_unlock_path(dir);
06047 inprocess_count(vmu->mailbox, vmu->context, -1);
06048 if (ast_check_realtime("voicemail_data")) {
06049 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06050 }
06051 } else {
06052 #ifndef IMAP_STORAGE
06053 msgnum = last_message_index(vmu, dir) + 1;
06054 #endif
06055 make_file(fn, sizeof(fn), dir, msgnum);
06056
06057
06058 #ifndef IMAP_STORAGE
06059 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06060 #else
06061 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06062 #endif
06063
06064 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06065 ast_filerename(tmptxtfile, fn, NULL);
06066 rename(tmptxtfile, txtfile);
06067 inprocess_count(vmu->mailbox, vmu->context, -1);
06068
06069
06070
06071 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06072 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06073
06074 ast_unlock_path(dir);
06075 if (ast_check_realtime("voicemail_data")) {
06076 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06077 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06078 }
06079
06080
06081
06082 if (ast_fileexists(fn, NULL, NULL) > 0) {
06083 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06084 }
06085
06086
06087 while (tmpptr) {
06088 struct ast_vm_user recipu, *recip;
06089 char *exten, *cntx;
06090
06091 exten = strsep(&tmpptr, "&");
06092 cntx = strchr(exten, '@');
06093 if (cntx) {
06094 *cntx = '\0';
06095 cntx++;
06096 }
06097 if ((recip = find_user(&recipu, cntx, exten))) {
06098 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06099 free_user(recip);
06100 }
06101 }
06102 #ifndef IMAP_STORAGE
06103 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06104
06105 char sfn[PATH_MAX];
06106 char dfn[PATH_MAX];
06107 int x;
06108
06109 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06110 x = last_message_index(vmu, urgdir) + 1;
06111 make_file(sfn, sizeof(sfn), dir, msgnum);
06112 make_file(dfn, sizeof(dfn), urgdir, x);
06113 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06114 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06115
06116 ast_copy_string(fn, dfn, sizeof(fn));
06117 msgnum = x;
06118 }
06119 #endif
06120
06121 if (ast_fileexists(fn, NULL, NULL)) {
06122 #ifdef IMAP_STORAGE
06123 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06124 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06125 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06126 flag);
06127 #else
06128 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06129 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06130 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06131 flag);
06132 #endif
06133 }
06134
06135
06136 if (ast_fileexists(fn, NULL, NULL)) {
06137 DISPOSE(dir, msgnum);
06138 }
06139 }
06140 }
06141 } else {
06142 inprocess_count(vmu->mailbox, vmu->context, -1);
06143 }
06144 if (res == '0') {
06145 goto transfer;
06146 } else if (res > 0 && res != 't')
06147 res = 0;
06148
06149 if (sound_duration < vmu->minsecs)
06150
06151 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06152 else
06153 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06154 } else
06155 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06156 leave_vm_out:
06157 free_user(vmu);
06158
06159 #ifdef IMAP_STORAGE
06160
06161 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06162 if (expungeonhangup == 1) {
06163 ast_mutex_lock(&vms->lock);
06164 #ifdef HAVE_IMAP_TK2006
06165 if (LEVELUIDPLUS (vms->mailstream)) {
06166 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06167 } else
06168 #endif
06169 mail_expunge(vms->mailstream);
06170 ast_mutex_unlock(&vms->lock);
06171 }
06172 #endif
06173
06174 ast_free(tmp);
06175 return res;
06176 }
06177
06178 #if !defined(IMAP_STORAGE)
06179 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06180 {
06181
06182
06183 int x, dest;
06184 char sfn[PATH_MAX];
06185 char dfn[PATH_MAX];
06186
06187 if (vm_lock_path(dir)) {
06188 return ERROR_LOCK_PATH;
06189 }
06190
06191 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06192 make_file(sfn, sizeof(sfn), dir, x);
06193 if (EXISTS(dir, x, sfn, NULL)) {
06194
06195 if (x != dest) {
06196 make_file(dfn, sizeof(dfn), dir, dest);
06197 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06198 }
06199
06200 dest++;
06201 }
06202 }
06203 ast_unlock_path(dir);
06204
06205 return dest;
06206 }
06207 #endif
06208
06209 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06210 {
06211 int d;
06212 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06213 return d;
06214 }
06215
06216 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06217 {
06218 #ifdef IMAP_STORAGE
06219
06220
06221 char sequence[10];
06222 char mailbox[256];
06223 int res;
06224
06225
06226 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06227
06228 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06229 ast_mutex_lock(&vms->lock);
06230
06231 if (box == OLD_FOLDER) {
06232 mail_setflag(vms->mailstream, sequence, "\\Seen");
06233 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06234 } else if (box == NEW_FOLDER) {
06235 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06236 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06237 }
06238 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06239 ast_mutex_unlock(&vms->lock);
06240 return 0;
06241 }
06242
06243 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06244 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06245 if (mail_create(vms->mailstream, mailbox) == NIL)
06246 ast_debug(5, "Folder exists.\n");
06247 else
06248 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06249 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06250 ast_mutex_unlock(&vms->lock);
06251 return res;
06252 #else
06253 char *dir = vms->curdir;
06254 char *username = vms->username;
06255 char *context = vmu->context;
06256 char sfn[PATH_MAX];
06257 char dfn[PATH_MAX];
06258 char ddir[PATH_MAX];
06259 const char *dbox = mbox(vmu, box);
06260 int x, i;
06261 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06262
06263 if (vm_lock_path(ddir))
06264 return ERROR_LOCK_PATH;
06265
06266 x = last_message_index(vmu, ddir) + 1;
06267
06268 if (box == 10 && x >= vmu->maxdeletedmsg) {
06269 x--;
06270 for (i = 1; i <= x; i++) {
06271
06272 make_file(sfn, sizeof(sfn), ddir, i);
06273 make_file(dfn, sizeof(dfn), ddir, i - 1);
06274 if (EXISTS(ddir, i, sfn, NULL)) {
06275 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06276 } else
06277 break;
06278 }
06279 } else {
06280 if (x >= vmu->maxmsg) {
06281 ast_unlock_path(ddir);
06282 return -1;
06283 }
06284 }
06285 make_file(sfn, sizeof(sfn), dir, msg);
06286 make_file(dfn, sizeof(dfn), ddir, x);
06287 if (strcmp(sfn, dfn)) {
06288 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06289 }
06290 ast_unlock_path(ddir);
06291 #endif
06292 return 0;
06293 }
06294
06295 static int adsi_logo(unsigned char *buf)
06296 {
06297 int bytes = 0;
06298 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06299 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06300 return bytes;
06301 }
06302
06303 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06304 {
06305 unsigned char buf[256];
06306 int bytes = 0;
06307 int x;
06308 char num[5];
06309
06310 *useadsi = 0;
06311 bytes += ast_adsi_data_mode(buf + bytes);
06312 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06313
06314 bytes = 0;
06315 bytes += adsi_logo(buf);
06316 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06317 #ifdef DISPLAY
06318 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06319 #endif
06320 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06321 bytes += ast_adsi_data_mode(buf + bytes);
06322 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06323
06324 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06325 bytes = 0;
06326 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06327 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06328 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06329 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06330 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06331 return 0;
06332 }
06333
06334 #ifdef DISPLAY
06335
06336 bytes = 0;
06337 bytes += ast_adsi_logo(buf);
06338 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06340 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06341 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06342 #endif
06343 bytes = 0;
06344 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06345 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06346 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06347 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06348 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06349 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06350 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06351
06352 #ifdef DISPLAY
06353
06354 bytes = 0;
06355 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06356 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06357
06358 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06359 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06360 #endif
06361
06362 bytes = 0;
06363
06364 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06365 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06366 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06368 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06370 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06371
06372 #ifdef DISPLAY
06373
06374 bytes = 0;
06375 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06376 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06377 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06378 #endif
06379
06380 bytes = 0;
06381 for (x = 0; x < 5; x++) {
06382 snprintf(num, sizeof(num), "%d", x);
06383 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06384 }
06385 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06386 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06387
06388 #ifdef DISPLAY
06389
06390 bytes = 0;
06391 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06392 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06393 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06394 #endif
06395
06396 if (ast_adsi_end_download(chan)) {
06397 bytes = 0;
06398 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06399 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06400 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06401 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06402 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06403 return 0;
06404 }
06405 bytes = 0;
06406 bytes += ast_adsi_download_disconnect(buf + bytes);
06407 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06408 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06409
06410 ast_debug(1, "Done downloading scripts...\n");
06411
06412 #ifdef DISPLAY
06413
06414 bytes = 0;
06415 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06416 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06417 #endif
06418 ast_debug(1, "Restarting session...\n");
06419
06420 bytes = 0;
06421
06422 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06423 *useadsi = 1;
06424 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06425 } else
06426 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06427
06428 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06429 return 0;
06430 }
06431
06432 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06433 {
06434 int x;
06435 if (!ast_adsi_available(chan))
06436 return;
06437 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06438 if (x < 0)
06439 return;
06440 if (!x) {
06441 if (adsi_load_vmail(chan, useadsi)) {
06442 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06443 return;
06444 }
06445 } else
06446 *useadsi = 1;
06447 }
06448
06449 static void adsi_login(struct ast_channel *chan)
06450 {
06451 unsigned char buf[256];
06452 int bytes = 0;
06453 unsigned char keys[8];
06454 int x;
06455 if (!ast_adsi_available(chan))
06456 return;
06457
06458 for (x = 0; x < 8; x++)
06459 keys[x] = 0;
06460
06461 keys[3] = ADSI_KEY_APPS + 3;
06462
06463 bytes += adsi_logo(buf + bytes);
06464 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06465 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06466 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06467 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06468 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06469 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06470 bytes += ast_adsi_set_keys(buf + bytes, keys);
06471 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06472 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06473 }
06474
06475 static void adsi_password(struct ast_channel *chan)
06476 {
06477 unsigned char buf[256];
06478 int bytes = 0;
06479 unsigned char keys[8];
06480 int x;
06481 if (!ast_adsi_available(chan))
06482 return;
06483
06484 for (x = 0; x < 8; x++)
06485 keys[x] = 0;
06486
06487 keys[3] = ADSI_KEY_APPS + 3;
06488
06489 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06490 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06491 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06492 bytes += ast_adsi_set_keys(buf + bytes, keys);
06493 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06494 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06495 }
06496
06497 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06498 {
06499 unsigned char buf[256];
06500 int bytes = 0;
06501 unsigned char keys[8];
06502 int x, y;
06503
06504 if (!ast_adsi_available(chan))
06505 return;
06506
06507 for (x = 0; x < 5; x++) {
06508 y = ADSI_KEY_APPS + 12 + start + x;
06509 if (y > ADSI_KEY_APPS + 12 + 4)
06510 y = 0;
06511 keys[x] = ADSI_KEY_SKT | y;
06512 }
06513 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06514 keys[6] = 0;
06515 keys[7] = 0;
06516
06517 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06518 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06519 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06520 bytes += ast_adsi_set_keys(buf + bytes, keys);
06521 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06522
06523 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06524 }
06525
06526 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06527 {
06528 int bytes = 0;
06529 unsigned char buf[256];
06530 char buf1[256], buf2[256];
06531 char fn2[PATH_MAX];
06532
06533 char cid[256] = "";
06534 char *val;
06535 char *name, *num;
06536 char datetime[21] = "";
06537 FILE *f;
06538
06539 unsigned char keys[8];
06540
06541 int x;
06542
06543 if (!ast_adsi_available(chan))
06544 return;
06545
06546
06547 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06548 f = fopen(fn2, "r");
06549 if (f) {
06550 while (!feof(f)) {
06551 if (!fgets((char *) buf, sizeof(buf), f)) {
06552 continue;
06553 }
06554 if (!feof(f)) {
06555 char *stringp = NULL;
06556 stringp = (char *) buf;
06557 strsep(&stringp, "=");
06558 val = strsep(&stringp, "=");
06559 if (!ast_strlen_zero(val)) {
06560 if (!strcmp((char *) buf, "callerid"))
06561 ast_copy_string(cid, val, sizeof(cid));
06562 if (!strcmp((char *) buf, "origdate"))
06563 ast_copy_string(datetime, val, sizeof(datetime));
06564 }
06565 }
06566 }
06567 fclose(f);
06568 }
06569
06570 for (x = 0; x < 5; x++)
06571 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06572 keys[6] = 0x0;
06573 keys[7] = 0x0;
06574
06575 if (!vms->curmsg) {
06576
06577 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06578 }
06579 if (vms->curmsg >= vms->lastmsg) {
06580
06581 if (vms->curmsg) {
06582
06583 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06584 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06585
06586 } else {
06587
06588 keys[3] = 1;
06589 }
06590 }
06591
06592 if (!ast_strlen_zero(cid)) {
06593 ast_callerid_parse(cid, &name, &num);
06594 if (!name)
06595 name = num;
06596 } else
06597 name = "Unknown Caller";
06598
06599
06600 #ifdef IMAP_STORAGE
06601 ast_mutex_lock(&vms->lock);
06602 #endif
06603 if (vms->deleted[vms->curmsg]) {
06604 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06605 }
06606 #ifdef IMAP_STORAGE
06607 ast_mutex_unlock(&vms->lock);
06608 #endif
06609
06610
06611 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06612 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06613 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06614 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06615
06616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06617 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06618 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06619 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06620 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06621 bytes += ast_adsi_set_keys(buf + bytes, keys);
06622 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06623
06624 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06625 }
06626
06627 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06628 {
06629 int bytes = 0;
06630 unsigned char buf[256];
06631 unsigned char keys[8];
06632
06633 int x;
06634
06635 if (!ast_adsi_available(chan))
06636 return;
06637
06638
06639 for (x = 0; x < 5; x++)
06640 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06641
06642 keys[6] = 0x0;
06643 keys[7] = 0x0;
06644
06645 if (!vms->curmsg) {
06646
06647 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06648 }
06649 if (vms->curmsg >= vms->lastmsg) {
06650
06651 if (vms->curmsg) {
06652
06653 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06654 } else {
06655
06656 keys[3] = 1;
06657 }
06658 }
06659
06660
06661 #ifdef IMAP_STORAGE
06662 ast_mutex_lock(&vms->lock);
06663 #endif
06664 if (vms->deleted[vms->curmsg]) {
06665 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06666 }
06667 #ifdef IMAP_STORAGE
06668 ast_mutex_unlock(&vms->lock);
06669 #endif
06670
06671
06672 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06673 bytes += ast_adsi_set_keys(buf + bytes, keys);
06674 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06675
06676 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06677 }
06678
06679 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06680 {
06681 unsigned char buf[256] = "";
06682 char buf1[256] = "", buf2[256] = "";
06683 int bytes = 0;
06684 unsigned char keys[8];
06685 int x;
06686
06687 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06688 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06689 if (!ast_adsi_available(chan))
06690 return;
06691 if (vms->newmessages) {
06692 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06693 if (vms->oldmessages) {
06694 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06695 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06696 } else {
06697 snprintf(buf2, sizeof(buf2), "%s.", newm);
06698 }
06699 } else if (vms->oldmessages) {
06700 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06701 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06702 } else {
06703 strcpy(buf1, "You have no messages.");
06704 buf2[0] = ' ';
06705 buf2[1] = '\0';
06706 }
06707 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06708 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06709 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06710
06711 for (x = 0; x < 6; x++)
06712 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06713 keys[6] = 0;
06714 keys[7] = 0;
06715
06716
06717 if (vms->lastmsg < 0)
06718 keys[0] = 1;
06719 bytes += ast_adsi_set_keys(buf + bytes, keys);
06720
06721 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06722
06723 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06724 }
06725
06726 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06727 {
06728 unsigned char buf[256] = "";
06729 char buf1[256] = "", buf2[256] = "";
06730 int bytes = 0;
06731 unsigned char keys[8];
06732 int x;
06733
06734 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06735
06736 if (!ast_adsi_available(chan))
06737 return;
06738
06739
06740 for (x = 0; x < 6; x++)
06741 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06742
06743 keys[6] = 0;
06744 keys[7] = 0;
06745
06746 if ((vms->lastmsg + 1) < 1)
06747 keys[0] = 0;
06748
06749 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06750 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06751
06752 if (vms->lastmsg + 1)
06753 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06754 else
06755 strcpy(buf2, "no messages.");
06756 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06757 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06758 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06759 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06760 bytes += ast_adsi_set_keys(buf + bytes, keys);
06761
06762 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06763
06764 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06765
06766 }
06767
06768
06769
06770
06771
06772
06773
06774
06775
06776
06777
06778
06779
06780
06781
06782 static void adsi_goodbye(struct ast_channel *chan)
06783 {
06784 unsigned char buf[256];
06785 int bytes = 0;
06786
06787 if (!ast_adsi_available(chan))
06788 return;
06789 bytes += adsi_logo(buf + bytes);
06790 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06791 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06792 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06793 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06794
06795 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06796 }
06797
06798
06799
06800
06801
06802 static int get_folder(struct ast_channel *chan, int start)
06803 {
06804 int x;
06805 int d;
06806 char fn[PATH_MAX];
06807 d = ast_play_and_wait(chan, "vm-press");
06808 if (d)
06809 return d;
06810 for (x = start; x < 5; x++) {
06811 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06812 return d;
06813 d = ast_play_and_wait(chan, "vm-for");
06814 if (d)
06815 return d;
06816 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06817
06818
06819
06820
06821 if (x == 0) {
06822 if (ast_fileexists(fn, NULL, NULL)) {
06823 d = vm_play_folder_name(chan, fn);
06824 } else {
06825 ast_verb(1, "failed to find %s\n", fn);
06826 d = vm_play_folder_name(chan, "vm-INBOX");
06827 }
06828 } else {
06829 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06830 d = vm_play_folder_name(chan, fn);
06831 }
06832
06833 if (d)
06834 return d;
06835 d = ast_waitfordigit(chan, 500);
06836 if (d)
06837 return d;
06838 }
06839
06840 d = ast_play_and_wait(chan, "vm-tocancel");
06841 if (d)
06842 return d;
06843 d = ast_waitfordigit(chan, 4000);
06844 return d;
06845 }
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06860 {
06861 int res = 0;
06862 int loops = 0;
06863
06864 res = ast_play_and_wait(chan, fn);
06865 while (((res < '0') || (res > '9')) &&
06866 (res != '#') && (res >= 0) &&
06867 loops < 4) {
06868 res = get_folder(chan, 0);
06869 loops++;
06870 }
06871 if (loops == 4) {
06872 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06873 return '#';
06874 }
06875 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06876 return res;
06877 }
06878
06879
06880
06881
06882
06883
06884
06885
06886
06887
06888
06889
06890
06891
06892
06893
06894
06895
06896
06897 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06898 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06899 {
06900 int cmd = 0;
06901 int retries = 0, prepend_duration = 0, already_recorded = 0;
06902 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06903 char textfile[PATH_MAX];
06904 struct ast_config *msg_cfg;
06905 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06906 #ifndef IMAP_STORAGE
06907 signed char zero_gain = 0;
06908 #endif
06909 const char *duration_str;
06910
06911
06912 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06913 strcpy(textfile, msgfile);
06914 strcpy(backup, msgfile);
06915 strcpy(backup_textfile, msgfile);
06916 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06917 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06918 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06919
06920 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06921 *duration = atoi(duration_str);
06922 } else {
06923 *duration = 0;
06924 }
06925
06926 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06927 if (cmd)
06928 retries = 0;
06929 switch (cmd) {
06930 case '1':
06931
06932 #ifdef IMAP_STORAGE
06933
06934 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06935 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06936 ast_play_and_wait(chan, INTRO);
06937 ast_play_and_wait(chan, "beep");
06938 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06939 if (cmd == -1) {
06940 break;
06941 }
06942 cmd = 't';
06943 #else
06944
06945
06946
06947 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06948 strcpy(textfile, msgfile);
06949 strncat(textfile, ".txt", sizeof(textfile) - 1);
06950 *duration = 0;
06951
06952
06953 if (!valid_config(msg_cfg)) {
06954 cmd = 0;
06955 break;
06956 }
06957
06958
06959 #ifndef IMAP_STORAGE
06960 if (already_recorded) {
06961 ast_filecopy(backup, msgfile, NULL);
06962 copy(backup_textfile, textfile);
06963 }
06964 else {
06965 ast_filecopy(msgfile, backup, NULL);
06966 copy(textfile, backup_textfile);
06967 }
06968 #endif
06969 already_recorded = 1;
06970
06971 if (record_gain)
06972 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06973
06974 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06975
06976 if (cmd == 'S') {
06977 ast_stream_and_wait(chan, vm_pls_try_again, "");
06978 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06979 ast_filerename(backup, msgfile, NULL);
06980 }
06981
06982 if (record_gain)
06983 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06984
06985
06986 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06987 *duration = atoi(duration_str);
06988
06989 if (prepend_duration) {
06990 struct ast_category *msg_cat;
06991
06992 char duration_buf[12];
06993
06994 *duration += prepend_duration;
06995 msg_cat = ast_category_get(msg_cfg, "message");
06996 snprintf(duration_buf, 11, "%ld", *duration);
06997 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06998 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06999 }
07000 }
07001
07002 #endif
07003 break;
07004 case '2':
07005
07006 #ifdef IMAP_STORAGE
07007 *vms->introfn = '\0';
07008 #endif
07009 cmd = 't';
07010 break;
07011 case '*':
07012 cmd = '*';
07013 break;
07014 default:
07015
07016 already_recorded = 0;
07017
07018 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07019
07020 if (!cmd) {
07021 cmd = ast_play_and_wait(chan, "vm-starmain");
07022
07023 }
07024 if (!cmd) {
07025 cmd = ast_waitfordigit(chan, 6000);
07026 }
07027 if (!cmd) {
07028 retries++;
07029 }
07030 if (retries > 3) {
07031 cmd = '*';
07032 }
07033 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07034 }
07035 }
07036
07037 if (valid_config(msg_cfg))
07038 ast_config_destroy(msg_cfg);
07039 if (prepend_duration)
07040 *duration = prepend_duration;
07041
07042 if (already_recorded && cmd == -1) {
07043
07044 ast_filerename(backup, msgfile, NULL);
07045 rename(backup_textfile, textfile);
07046 }
07047
07048 if (cmd == 't' || cmd == 'S')
07049 cmd = 0;
07050 return cmd;
07051 }
07052
07053 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07054 {
07055 struct ast_event *event;
07056 char *mailbox, *context;
07057
07058
07059 context = mailbox = ast_strdupa(box);
07060 strsep(&context, "@");
07061 if (ast_strlen_zero(context))
07062 context = "default";
07063
07064 if (!(event = ast_event_new(AST_EVENT_MWI,
07065 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07066 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07067 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07068 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07069 AST_EVENT_IE_END))) {
07070 return;
07071 }
07072
07073 ast_event_queue_and_cache(event);
07074 }
07075
07076
07077
07078
07079
07080
07081
07082
07083
07084
07085
07086
07087
07088
07089
07090 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)
07091 {
07092 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07093 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07094 const char *category;
07095 char *myserveremail = serveremail;
07096
07097 ast_channel_lock(chan);
07098 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07099 category = ast_strdupa(category);
07100 }
07101 ast_channel_unlock(chan);
07102
07103 #ifndef IMAP_STORAGE
07104 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07105 #else
07106 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07107 #endif
07108 make_file(fn, sizeof(fn), todir, msgnum);
07109 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07110
07111 if (!ast_strlen_zero(vmu->attachfmt)) {
07112 if (strstr(fmt, vmu->attachfmt))
07113 fmt = vmu->attachfmt;
07114 else
07115 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);
07116 }
07117
07118
07119 fmt = ast_strdupa(fmt);
07120 stringp = fmt;
07121 strsep(&stringp, "|");
07122
07123 if (!ast_strlen_zero(vmu->serveremail))
07124 myserveremail = vmu->serveremail;
07125
07126 if (!ast_strlen_zero(vmu->email)) {
07127 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07128
07129 if (attach_user_voicemail)
07130 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07131
07132
07133 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07134
07135 if (attach_user_voicemail)
07136 DISPOSE(todir, msgnum);
07137 }
07138
07139 if (!ast_strlen_zero(vmu->pager)) {
07140 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07141 }
07142
07143 if (ast_test_flag(vmu, VM_DELETE))
07144 DELETE(todir, msgnum, fn, vmu);
07145
07146
07147 if (ast_app_has_voicemail(ext_context, NULL))
07148 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07149
07150 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07151
07152 ast_manager_event(chan, 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);
07153 run_externnotify(vmu->context, vmu->mailbox, flag);
07154
07155 #ifdef IMAP_STORAGE
07156 vm_delete(fn);
07157 if (ast_test_flag(vmu, VM_DELETE)) {
07158 vm_imap_delete(NULL, vms->curmsg, vmu);
07159 vms->newmessages--;
07160 }
07161 #endif
07162
07163 return 0;
07164 }
07165
07166
07167
07168
07169
07170
07171
07172
07173
07174
07175
07176
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193 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)
07194 {
07195 #ifdef IMAP_STORAGE
07196 int todircount = 0;
07197 struct vm_state *dstvms;
07198 #endif
07199 char username[70]="";
07200 char fn[PATH_MAX];
07201 char ecodes[16] = "#";
07202 int res = 0, cmd = 0;
07203 struct ast_vm_user *receiver = NULL, *vmtmp;
07204 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07205 char *stringp;
07206 const char *s;
07207 int saved_messages = 0;
07208 int valid_extensions = 0;
07209 char *dir;
07210 int curmsg;
07211 char urgent_str[7] = "";
07212 int prompt_played = 0;
07213 #ifndef IMAP_STORAGE
07214 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07215 #endif
07216 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07217 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07218 }
07219
07220 if (vms == NULL) return -1;
07221 dir = vms->curdir;
07222 curmsg = vms->curmsg;
07223
07224 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07225 while (!res && !valid_extensions) {
07226 int use_directory = 0;
07227 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07228 int done = 0;
07229 int retries = 0;
07230 cmd = 0;
07231 while ((cmd >= 0) && !done ){
07232 if (cmd)
07233 retries = 0;
07234 switch (cmd) {
07235 case '1':
07236 use_directory = 0;
07237 done = 1;
07238 break;
07239 case '2':
07240 use_directory = 1;
07241 done = 1;
07242 break;
07243 case '*':
07244 cmd = 't';
07245 done = 1;
07246 break;
07247 default:
07248
07249 cmd = ast_play_and_wait(chan, "vm-forward");
07250 if (!cmd) {
07251 cmd = ast_waitfordigit(chan, 3000);
07252 }
07253 if (!cmd) {
07254 retries++;
07255 }
07256 if (retries > 3) {
07257 cmd = 't';
07258 done = 1;
07259 }
07260 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07261 }
07262 }
07263 if (cmd < 0 || cmd == 't')
07264 break;
07265 }
07266
07267 if (use_directory) {
07268
07269
07270 char old_context[sizeof(chan->context)];
07271 char old_exten[sizeof(chan->exten)];
07272 int old_priority;
07273 struct ast_app* directory_app;
07274
07275 directory_app = pbx_findapp("Directory");
07276 if (directory_app) {
07277 char vmcontext[256];
07278
07279 memcpy(old_context, chan->context, sizeof(chan->context));
07280 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07281 old_priority = chan->priority;
07282
07283
07284 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07285 res = pbx_exec(chan, directory_app, vmcontext);
07286
07287 ast_copy_string(username, chan->exten, sizeof(username));
07288
07289
07290 memcpy(chan->context, old_context, sizeof(chan->context));
07291 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07292 chan->priority = old_priority;
07293 } else {
07294 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07295 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07296 }
07297 } else {
07298
07299 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07300 res = ast_streamfile(chan, "vm-extension", chan->language);
07301 prompt_played++;
07302 if (res || prompt_played > 4)
07303 break;
07304 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07305 break;
07306 }
07307
07308
07309 if (ast_strlen_zero(username))
07310 continue;
07311 stringp = username;
07312 s = strsep(&stringp, "*");
07313
07314 valid_extensions = 1;
07315 while (s) {
07316 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07317 int oldmsgs;
07318 int newmsgs;
07319 int capacity;
07320 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07321 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07322
07323 res = ast_play_and_wait(chan, "pbx-invalid");
07324 valid_extensions = 0;
07325 break;
07326 }
07327 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07328 if ((newmsgs + oldmsgs) >= capacity) {
07329 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07330 res = ast_play_and_wait(chan, "vm-mailboxfull");
07331 valid_extensions = 0;
07332 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07333 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07334 free_user(vmtmp);
07335 }
07336 inprocess_count(receiver->mailbox, receiver->context, -1);
07337 break;
07338 }
07339 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07340 } else {
07341
07342
07343
07344
07345
07346 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07347 free_user(receiver);
07348 }
07349 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07350
07351 res = ast_play_and_wait(chan, "pbx-invalid");
07352 valid_extensions = 0;
07353 break;
07354 }
07355
07356
07357 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07358 RETRIEVE(fn, -1, s, receiver->context);
07359 if (ast_fileexists(fn, NULL, NULL) > 0) {
07360 res = ast_stream_and_wait(chan, fn, ecodes);
07361 if (res) {
07362 DISPOSE(fn, -1);
07363 return res;
07364 }
07365 } else {
07366 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07367 }
07368 DISPOSE(fn, -1);
07369
07370 s = strsep(&stringp, "*");
07371 }
07372
07373 if (valid_extensions)
07374 break;
07375 }
07376
07377 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07378 return res;
07379 if (is_new_message == 1) {
07380 struct leave_vm_options leave_options;
07381 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07382 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07383
07384
07385 memset(&leave_options, 0, sizeof(leave_options));
07386 leave_options.record_gain = record_gain;
07387 cmd = leave_voicemail(chan, mailbox, &leave_options);
07388 } else {
07389
07390 long duration = 0;
07391 struct vm_state vmstmp;
07392 int copy_msg_result = 0;
07393 memcpy(&vmstmp, vms, sizeof(vmstmp));
07394
07395 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07396
07397 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07398 if (!cmd) {
07399 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07400 #ifdef IMAP_STORAGE
07401 int attach_user_voicemail;
07402 char *myserveremail = serveremail;
07403
07404
07405 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07406 if (!dstvms) {
07407 dstvms = create_vm_state_from_user(vmtmp);
07408 }
07409 if (dstvms) {
07410 init_mailstream(dstvms, 0);
07411 if (!dstvms->mailstream) {
07412 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07413 } else {
07414 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07415 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07416 }
07417 } else {
07418 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07419 }
07420 if (!ast_strlen_zero(vmtmp->serveremail))
07421 myserveremail = vmtmp->serveremail;
07422 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07423
07424 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07425 dstvms->curbox,
07426 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07427 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07428 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07429 NULL, urgent_str);
07430 #else
07431 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07432 #endif
07433 saved_messages++;
07434 AST_LIST_REMOVE_CURRENT(list);
07435 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07436 free_user(vmtmp);
07437 if (res)
07438 break;
07439 }
07440 AST_LIST_TRAVERSE_SAFE_END;
07441 if (saved_messages > 0 && !copy_msg_result) {
07442
07443
07444
07445
07446
07447
07448
07449
07450 #ifdef IMAP_STORAGE
07451
07452 if (ast_strlen_zero(vmstmp.introfn))
07453 #endif
07454 res = ast_play_and_wait(chan, "vm-msgsaved");
07455 }
07456 #ifndef IMAP_STORAGE
07457 else {
07458
07459 res = ast_play_and_wait(chan, "vm-mailboxfull");
07460 }
07461
07462 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07463 strcpy(textfile, msgfile);
07464 strcpy(backup, msgfile);
07465 strcpy(backup_textfile, msgfile);
07466 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07467 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07468 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07469 if (ast_fileexists(backup, NULL, NULL) > 0) {
07470 ast_filerename(backup, msgfile, NULL);
07471 rename(backup_textfile, textfile);
07472 }
07473 #endif
07474 }
07475 DISPOSE(dir, curmsg);
07476 #ifndef IMAP_STORAGE
07477 if (cmd) {
07478 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07479 strcpy(textfile, msgfile);
07480 strcpy(backup_textfile, msgfile);
07481 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07482 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07483 rename(backup_textfile, textfile);
07484 }
07485 #endif
07486 }
07487
07488
07489 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07490 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07491 free_user(vmtmp);
07492 }
07493 return res ? res : cmd;
07494 }
07495
07496 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07497 {
07498 int res;
07499 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07500 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07501 return res;
07502 }
07503
07504 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07505 {
07506 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07507 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);
07508 }
07509
07510 static int play_message_category(struct ast_channel *chan, const char *category)
07511 {
07512 int res = 0;
07513
07514 if (!ast_strlen_zero(category))
07515 res = ast_play_and_wait(chan, category);
07516
07517 if (res) {
07518 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07519 res = 0;
07520 }
07521
07522 return res;
07523 }
07524
07525 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07526 {
07527 int res = 0;
07528 struct vm_zone *the_zone = NULL;
07529 time_t t;
07530
07531 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07532 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07533 return 0;
07534 }
07535
07536
07537 if (!ast_strlen_zero(vmu->zonetag)) {
07538
07539 struct vm_zone *z;
07540 AST_LIST_LOCK(&zones);
07541 AST_LIST_TRAVERSE(&zones, z, list) {
07542 if (!strcmp(z->name, vmu->zonetag)) {
07543 the_zone = z;
07544 break;
07545 }
07546 }
07547 AST_LIST_UNLOCK(&zones);
07548 }
07549
07550
07551 #if 0
07552
07553 ast_localtime(&t, &time_now, NULL);
07554 tv_now = ast_tvnow();
07555 ast_localtime(&tv_now, &time_then, NULL);
07556
07557
07558 if (time_now.tm_year == time_then.tm_year)
07559 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07560 else
07561 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07562 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07563
07564
07565 #endif
07566 if (the_zone) {
07567 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07568 } else if (!strncasecmp(chan->language, "de", 2)) {
07569 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07570 } else if (!strncasecmp(chan->language, "gr", 2)) {
07571 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07572 } else if (!strncasecmp(chan->language, "it", 2)) {
07573 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);
07574 } else if (!strncasecmp(chan->language, "nl", 2)) {
07575 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07576 } else if (!strncasecmp(chan->language, "no", 2)) {
07577 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07578 } else if (!strncasecmp(chan->language, "pl", 2)) {
07579 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07580 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07581 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);
07582 } else if (!strncasecmp(chan->language, "se", 2)) {
07583 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07584 } else if (!strncasecmp(chan->language, "zh", 2)) {
07585 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07586 } else if (!strncasecmp(chan->language, "vi", 2)) {
07587 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07588 } else {
07589 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07590 }
07591 #if 0
07592 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07593 #endif
07594 return res;
07595 }
07596
07597
07598
07599 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07600 {
07601 int res = 0;
07602 int i;
07603 char *callerid, *name;
07604 char prefile[PATH_MAX] = "";
07605
07606
07607
07608
07609
07610
07611
07612
07613
07614 if ((cid == NULL)||(context == NULL))
07615 return res;
07616
07617
07618 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07619 ast_callerid_parse(cid, &name, &callerid);
07620 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07621
07622
07623 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07624 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07625 if ((strcmp(cidinternalcontexts[i], context) == 0))
07626 break;
07627 }
07628 if (i != MAX_NUM_CID_CONTEXTS){
07629 if (!res) {
07630 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07631 if (!ast_strlen_zero(prefile)) {
07632
07633 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07634 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07635 if (!callback)
07636 res = wait_file2(chan, vms, "vm-from");
07637 res = ast_stream_and_wait(chan, prefile, "");
07638 } else {
07639 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07640
07641 if (!callback)
07642 res = wait_file2(chan, vms, "vm-from-extension");
07643 res = ast_say_digit_str(chan, callerid, "", chan->language);
07644 }
07645 }
07646 }
07647 } else if (!res) {
07648 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07649
07650 if (!callback)
07651 res = wait_file2(chan, vms, "vm-from-phonenumber");
07652 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07653 }
07654 } else {
07655
07656 ast_debug(1, "VM-CID: From an unknown number\n");
07657
07658 res = wait_file2(chan, vms, "vm-unknown-caller");
07659 }
07660 return res;
07661 }
07662
07663 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07664 {
07665 int res = 0;
07666 int durationm;
07667 int durations;
07668
07669 if (duration == NULL)
07670 return res;
07671
07672
07673 durations = atoi(duration);
07674 durationm = (durations / 60);
07675
07676 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07677
07678 if ((!res) && (durationm >= minduration)) {
07679 res = wait_file2(chan, vms, "vm-duration");
07680
07681
07682 if (!strncasecmp(chan->language, "pl", 2)) {
07683 div_t num = div(durationm, 10);
07684
07685 if (durationm == 1) {
07686 res = ast_play_and_wait(chan, "digits/1z");
07687 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07688 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07689 if (num.rem == 2) {
07690 if (!num.quot) {
07691 res = ast_play_and_wait(chan, "digits/2-ie");
07692 } else {
07693 res = say_and_wait(chan, durationm - 2 , chan->language);
07694 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07695 }
07696 } else {
07697 res = say_and_wait(chan, durationm, chan->language);
07698 }
07699 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07700 } else {
07701 res = say_and_wait(chan, durationm, chan->language);
07702 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07703 }
07704
07705 } else {
07706 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07707 res = wait_file2(chan, vms, "vm-minutes");
07708 }
07709 }
07710 return res;
07711 }
07712
07713 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07714 {
07715 int res = 0;
07716 char filename[256], *cid;
07717 const char *origtime, *context, *category, *duration, *flag;
07718 struct ast_config *msg_cfg;
07719 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07720
07721 vms->starting = 0;
07722 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07723 adsi_message(chan, vms);
07724 if (!vms->curmsg) {
07725 res = wait_file2(chan, vms, "vm-first");
07726 } else if (vms->curmsg == vms->lastmsg) {
07727 res = wait_file2(chan, vms, "vm-last");
07728 }
07729
07730 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07731 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07732 msg_cfg = ast_config_load(filename, config_flags);
07733 if (!valid_config(msg_cfg)) {
07734 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07735 return 0;
07736 }
07737 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07738
07739
07740 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07741 res = wait_file2(chan, vms, "vm-Urgent");
07742 }
07743
07744 if (!res) {
07745
07746
07747 if (!strncasecmp(chan->language, "pl", 2)) {
07748 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07749 int ten, one;
07750 char nextmsg[256];
07751 ten = (vms->curmsg + 1) / 10;
07752 one = (vms->curmsg + 1) % 10;
07753
07754 if (vms->curmsg < 20) {
07755 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07756 res = wait_file2(chan, vms, nextmsg);
07757 } else {
07758 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07759 res = wait_file2(chan, vms, nextmsg);
07760 if (one > 0) {
07761 if (!res) {
07762 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07763 res = wait_file2(chan, vms, nextmsg);
07764 }
07765 }
07766 }
07767 }
07768 if (!res)
07769 res = wait_file2(chan, vms, "vm-message");
07770
07771 } else if (!strncasecmp(chan->language, "he", 2)) {
07772 if (!vms->curmsg) {
07773 res = wait_file2(chan, vms, "vm-message");
07774 res = wait_file2(chan, vms, "vm-first");
07775 } else if (vms->curmsg == vms->lastmsg) {
07776 res = wait_file2(chan, vms, "vm-message");
07777 res = wait_file2(chan, vms, "vm-last");
07778 } else {
07779 res = wait_file2(chan, vms, "vm-message");
07780 res = wait_file2(chan, vms, "vm-number");
07781 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07782 }
07783
07784 } else if (!strncasecmp(chan->language, "vi", 2)) {
07785 if (!vms->curmsg) {
07786 res = wait_file2(chan, vms, "vm-message");
07787 res = wait_file2(chan, vms, "vm-first");
07788 } else if (vms->curmsg == vms->lastmsg) {
07789 res = wait_file2(chan, vms, "vm-message");
07790 res = wait_file2(chan, vms, "vm-last");
07791 } else {
07792 res = wait_file2(chan, vms, "vm-message");
07793 res = wait_file2(chan, vms, "vm-number");
07794 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07795 }
07796 } else {
07797 if (!strncasecmp(chan->language, "se", 2)) {
07798 res = wait_file2(chan, vms, "vm-meddelandet");
07799 } else {
07800 res = wait_file2(chan, vms, "vm-message");
07801 }
07802 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07803 if (!res) {
07804 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07805 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07806 }
07807 }
07808 }
07809 }
07810
07811 if (!valid_config(msg_cfg)) {
07812 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07813 return 0;
07814 }
07815
07816 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07817 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07818 DISPOSE(vms->curdir, vms->curmsg);
07819 ast_config_destroy(msg_cfg);
07820 return 0;
07821 }
07822
07823 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07824 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07825 category = ast_variable_retrieve(msg_cfg, "message", "category");
07826
07827 context = ast_variable_retrieve(msg_cfg, "message", "context");
07828 if (!strncasecmp("macro", context, 5))
07829 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07830 if (!res) {
07831 res = play_message_category(chan, category);
07832 }
07833 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07834 res = play_message_datetime(chan, vmu, origtime, filename);
07835 }
07836 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07837 res = play_message_callerid(chan, vms, cid, context, 0);
07838 }
07839 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07840 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07841 }
07842
07843 if (res == '1') {
07844 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07845 res = 0;
07846 }
07847 ast_config_destroy(msg_cfg);
07848
07849 if (!res) {
07850 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07851 #ifdef IMAP_STORAGE
07852 ast_mutex_lock(&vms->lock);
07853 #endif
07854 vms->heard[vms->curmsg] = 1;
07855 #ifdef IMAP_STORAGE
07856 ast_mutex_unlock(&vms->lock);
07857
07858
07859
07860 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07861 wait_file(chan, vms, vms->introfn);
07862 }
07863 #endif
07864 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07865 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07866 res = 0;
07867 }
07868 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07869 }
07870 DISPOSE(vms->curdir, vms->curmsg);
07871 return res;
07872 }
07873
07874 #ifdef IMAP_STORAGE
07875 static int imap_remove_file(char *dir, int msgnum)
07876 {
07877 char fn[PATH_MAX];
07878 char full_fn[PATH_MAX];
07879 char intro[PATH_MAX] = {0,};
07880
07881 if (msgnum > -1) {
07882 make_file(fn, sizeof(fn), dir, msgnum);
07883 snprintf(intro, sizeof(intro), "%sintro", fn);
07884 } else
07885 ast_copy_string(fn, dir, sizeof(fn));
07886
07887 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07888 ast_filedelete(fn, NULL);
07889 if (!ast_strlen_zero(intro)) {
07890 ast_filedelete(intro, NULL);
07891 }
07892 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07893 unlink(full_fn);
07894 }
07895 return 0;
07896 }
07897
07898
07899
07900 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07901 {
07902 char *file, *filename;
07903 char *attachment;
07904 char arg[10];
07905 int i;
07906 BODY* body;
07907
07908 file = strrchr(ast_strdupa(dir), '/');
07909 if (file) {
07910 *file++ = '\0';
07911 } else {
07912 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07913 return -1;
07914 }
07915
07916 ast_mutex_lock(&vms->lock);
07917 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07918 mail_fetchstructure(vms->mailstream, i + 1, &body);
07919
07920 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07921 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07922 } else {
07923 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07924 ast_mutex_unlock(&vms->lock);
07925 return -1;
07926 }
07927 filename = strsep(&attachment, ".");
07928 if (!strcmp(filename, file)) {
07929 sprintf(arg, "%d", i + 1);
07930 mail_setflag(vms->mailstream, arg, "\\DELETED");
07931 }
07932 }
07933 mail_expunge(vms->mailstream);
07934 ast_mutex_unlock(&vms->lock);
07935 return 0;
07936 }
07937
07938 #elif !defined(IMAP_STORAGE)
07939 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07940 {
07941 int count_msg, last_msg;
07942
07943 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07944
07945
07946
07947
07948 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07949
07950
07951 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07952
07953
07954 count_msg = count_messages(vmu, vms->curdir);
07955 if (count_msg < 0) {
07956 return count_msg;
07957 } else {
07958 vms->lastmsg = count_msg - 1;
07959 }
07960
07961 if (vm_allocate_dh(vms, vmu, count_msg)) {
07962 return -1;
07963 }
07964
07965
07966
07967
07968
07969
07970
07971
07972 if (vm_lock_path(vms->curdir)) {
07973 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07974 return ERROR_LOCK_PATH;
07975 }
07976
07977
07978 last_msg = last_message_index(vmu, vms->curdir);
07979 ast_unlock_path(vms->curdir);
07980
07981 if (last_msg < -1) {
07982 return last_msg;
07983 } else if (vms->lastmsg != last_msg) {
07984 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07985 resequence_mailbox(vmu, vms->curdir, count_msg);
07986 }
07987
07988 return 0;
07989 }
07990 #endif
07991
07992 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07993 {
07994 int x = 0;
07995 int last_msg_idx = 0;
07996
07997 #ifndef IMAP_STORAGE
07998 int res = 0, nummsg;
07999 char fn2[PATH_MAX];
08000 #endif
08001
08002 if (vms->lastmsg <= -1) {
08003 goto done;
08004 }
08005
08006 vms->curmsg = -1;
08007 #ifndef IMAP_STORAGE
08008
08009 if (vm_lock_path(vms->curdir)) {
08010 return ERROR_LOCK_PATH;
08011 }
08012
08013
08014 last_msg_idx = last_message_index(vmu, vms->curdir);
08015 if (last_msg_idx != vms->lastmsg) {
08016 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08017 }
08018
08019
08020 for (x = 0; x < last_msg_idx + 1; x++) {
08021 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08022
08023 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08024 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08025 break;
08026 }
08027 vms->curmsg++;
08028 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08029 if (strcmp(vms->fn, fn2)) {
08030 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08031 }
08032 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08033
08034 res = save_to_folder(vmu, vms, x, 1);
08035 if (res == ERROR_LOCK_PATH) {
08036
08037 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08038 vms->deleted[x] = 0;
08039 vms->heard[x] = 0;
08040 --x;
08041 }
08042 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08043
08044 res = save_to_folder(vmu, vms, x, 10);
08045 if (res == ERROR_LOCK_PATH) {
08046
08047 vms->deleted[x] = 0;
08048 vms->heard[x] = 0;
08049 --x;
08050 }
08051 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08052
08053
08054 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08055 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08056 DELETE(vms->curdir, x, vms->fn, vmu);
08057 }
08058 }
08059 }
08060
08061
08062 nummsg = x - 1;
08063 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08064 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08065 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08066 DELETE(vms->curdir, x, vms->fn, vmu);
08067 }
08068 }
08069 ast_unlock_path(vms->curdir);
08070 #else
08071 ast_mutex_lock(&vms->lock);
08072 if (vms->deleted) {
08073
08074
08075 last_msg_idx = vms->dh_arraysize;
08076 for (x = last_msg_idx - 1; x >= 0; x--) {
08077 if (vms->deleted[x]) {
08078 ast_debug(3, "IMAP delete of %d\n", x);
08079 DELETE(vms->curdir, x, vms->fn, vmu);
08080 }
08081 }
08082 }
08083 #endif
08084
08085 done:
08086 if (vms->deleted) {
08087 ast_free(vms->deleted);
08088 vms->deleted = NULL;
08089 }
08090 if (vms->heard) {
08091 ast_free(vms->heard);
08092 vms->heard = NULL;
08093 }
08094 vms->dh_arraysize = 0;
08095 #ifdef IMAP_STORAGE
08096 ast_mutex_unlock(&vms->lock);
08097 #endif
08098
08099 return 0;
08100 }
08101
08102
08103
08104
08105
08106
08107
08108 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08109 {
08110 int cmd;
08111 char *buf;
08112
08113 buf = ast_alloca(strlen(box) + 2);
08114 strcpy(buf, box);
08115 strcat(buf, "s");
08116
08117 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08118 cmd = ast_play_and_wait(chan, buf);
08119 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08120 } else {
08121 cmd = ast_play_and_wait(chan, "vm-messages");
08122 return cmd ? cmd : ast_play_and_wait(chan, box);
08123 }
08124 }
08125
08126 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08127 {
08128 int cmd;
08129
08130 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08131 if (!strcasecmp(box, "vm-INBOX"))
08132 cmd = ast_play_and_wait(chan, "vm-new-e");
08133 else
08134 cmd = ast_play_and_wait(chan, "vm-old-e");
08135 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08136 } else {
08137 cmd = ast_play_and_wait(chan, "vm-messages");
08138 return cmd ? cmd : ast_play_and_wait(chan, box);
08139 }
08140 }
08141
08142 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08143 {
08144 int cmd;
08145
08146 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08147 cmd = ast_play_and_wait(chan, "vm-messages");
08148 return cmd ? cmd : ast_play_and_wait(chan, box);
08149 } else {
08150 cmd = ast_play_and_wait(chan, box);
08151 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08152 }
08153 }
08154
08155 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08156 {
08157 int cmd;
08158
08159 if ( !strncasecmp(chan->language, "it", 2) ||
08160 !strncasecmp(chan->language, "es", 2) ||
08161 !strncasecmp(chan->language, "pt", 2)) {
08162 cmd = ast_play_and_wait(chan, "vm-messages");
08163 return cmd ? cmd : ast_play_and_wait(chan, box);
08164 } else if (!strncasecmp(chan->language, "gr", 2)) {
08165 return vm_play_folder_name_gr(chan, box);
08166 } else if (!strncasecmp(chan->language, "he", 2)) {
08167 return ast_play_and_wait(chan, box);
08168 } else if (!strncasecmp(chan->language, "pl", 2)) {
08169 return vm_play_folder_name_pl(chan, box);
08170 } else if (!strncasecmp(chan->language, "ua", 2)) {
08171 return vm_play_folder_name_ua(chan, box);
08172 } else if (!strncasecmp(chan->language, "vi", 2)) {
08173 return ast_play_and_wait(chan, box);
08174 } else {
08175 cmd = ast_play_and_wait(chan, box);
08176 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08177 }
08178 }
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08193 {
08194 int res = 0;
08195
08196 if (vms->newmessages) {
08197 res = ast_play_and_wait(chan, "vm-youhave");
08198 if (!res)
08199 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08200 if (!res) {
08201 if ((vms->newmessages == 1)) {
08202 res = ast_play_and_wait(chan, "vm-INBOX");
08203 if (!res)
08204 res = ast_play_and_wait(chan, "vm-message");
08205 } else {
08206 res = ast_play_and_wait(chan, "vm-INBOXs");
08207 if (!res)
08208 res = ast_play_and_wait(chan, "vm-messages");
08209 }
08210 }
08211 } else if (vms->oldmessages){
08212 res = ast_play_and_wait(chan, "vm-youhave");
08213 if (!res)
08214 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08215 if ((vms->oldmessages == 1)){
08216 res = ast_play_and_wait(chan, "vm-Old");
08217 if (!res)
08218 res = ast_play_and_wait(chan, "vm-message");
08219 } else {
08220 res = ast_play_and_wait(chan, "vm-Olds");
08221 if (!res)
08222 res = ast_play_and_wait(chan, "vm-messages");
08223 }
08224 } else if (!vms->oldmessages && !vms->newmessages)
08225 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08226 return res;
08227 }
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285
08286 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08287 {
08288 int res;
08289 int lastnum = 0;
08290
08291 res = ast_play_and_wait(chan, "vm-youhave");
08292
08293 if (!res && vms->newmessages) {
08294 lastnum = vms->newmessages;
08295
08296 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08297 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08298 }
08299
08300 if (!res && vms->oldmessages) {
08301 res = ast_play_and_wait(chan, "vm-and");
08302 }
08303 }
08304
08305 if (!res && vms->oldmessages) {
08306 lastnum = vms->oldmessages;
08307
08308 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08309 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08310 }
08311 }
08312
08313 if (!res) {
08314 if (lastnum == 0) {
08315 res = ast_play_and_wait(chan, "vm-no");
08316 }
08317 if (!res) {
08318 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08319 }
08320 }
08321
08322 return res;
08323 }
08324
08325
08326 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08327 {
08328 int res = 0;
08329
08330
08331 if (!res) {
08332 if ((vms->newmessages) || (vms->oldmessages)) {
08333 res = ast_play_and_wait(chan, "vm-youhave");
08334 }
08335
08336
08337
08338
08339
08340 if (vms->newmessages) {
08341 if (!res) {
08342 if (vms->newmessages == 1) {
08343 res = ast_play_and_wait(chan, "vm-INBOX1");
08344 } else {
08345 if (vms->newmessages == 2) {
08346 res = ast_play_and_wait(chan, "vm-shtei");
08347 } else {
08348 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08349 }
08350 res = ast_play_and_wait(chan, "vm-INBOX");
08351 }
08352 }
08353 if (vms->oldmessages && !res) {
08354 res = ast_play_and_wait(chan, "vm-and");
08355 if (vms->oldmessages == 1) {
08356 res = ast_play_and_wait(chan, "vm-Old1");
08357 } else {
08358 if (vms->oldmessages == 2) {
08359 res = ast_play_and_wait(chan, "vm-shtei");
08360 } else {
08361 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08362 }
08363 res = ast_play_and_wait(chan, "vm-Old");
08364 }
08365 }
08366 }
08367 if (!res && vms->oldmessages && !vms->newmessages) {
08368 if (!res) {
08369 if (vms->oldmessages == 1) {
08370 res = ast_play_and_wait(chan, "vm-Old1");
08371 } else {
08372 if (vms->oldmessages == 2) {
08373 res = ast_play_and_wait(chan, "vm-shtei");
08374 } else {
08375 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08376 }
08377 res = ast_play_and_wait(chan, "vm-Old");
08378 }
08379 }
08380 }
08381 if (!res) {
08382 if (!vms->oldmessages && !vms->newmessages) {
08383 if (!res) {
08384 res = ast_play_and_wait(chan, "vm-nomessages");
08385 }
08386 }
08387 }
08388 }
08389 return res;
08390 }
08391
08392
08393 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08394 {
08395 int res;
08396
08397
08398 res = ast_play_and_wait(chan, "vm-youhave");
08399 if (!res) {
08400 if (vms->urgentmessages) {
08401 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08402 if (!res)
08403 res = ast_play_and_wait(chan, "vm-Urgent");
08404 if ((vms->oldmessages || vms->newmessages) && !res) {
08405 res = ast_play_and_wait(chan, "vm-and");
08406 } else if (!res) {
08407 if ((vms->urgentmessages == 1))
08408 res = ast_play_and_wait(chan, "vm-message");
08409 else
08410 res = ast_play_and_wait(chan, "vm-messages");
08411 }
08412 }
08413 if (vms->newmessages) {
08414 res = say_and_wait(chan, vms->newmessages, chan->language);
08415 if (!res)
08416 res = ast_play_and_wait(chan, "vm-INBOX");
08417 if (vms->oldmessages && !res)
08418 res = ast_play_and_wait(chan, "vm-and");
08419 else if (!res) {
08420 if ((vms->newmessages == 1))
08421 res = ast_play_and_wait(chan, "vm-message");
08422 else
08423 res = ast_play_and_wait(chan, "vm-messages");
08424 }
08425
08426 }
08427 if (!res && vms->oldmessages) {
08428 res = say_and_wait(chan, vms->oldmessages, chan->language);
08429 if (!res)
08430 res = ast_play_and_wait(chan, "vm-Old");
08431 if (!res) {
08432 if (vms->oldmessages == 1)
08433 res = ast_play_and_wait(chan, "vm-message");
08434 else
08435 res = ast_play_and_wait(chan, "vm-messages");
08436 }
08437 }
08438 if (!res) {
08439 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08440 res = ast_play_and_wait(chan, "vm-no");
08441 if (!res)
08442 res = ast_play_and_wait(chan, "vm-messages");
08443 }
08444 }
08445 }
08446 return res;
08447 }
08448
08449
08450 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08451 {
08452
08453 int res;
08454 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08455 res = ast_play_and_wait(chan, "vm-no") ||
08456 ast_play_and_wait(chan, "vm-message");
08457 else
08458 res = ast_play_and_wait(chan, "vm-youhave");
08459 if (!res && vms->newmessages) {
08460 res = (vms->newmessages == 1) ?
08461 ast_play_and_wait(chan, "digits/un") ||
08462 ast_play_and_wait(chan, "vm-nuovo") ||
08463 ast_play_and_wait(chan, "vm-message") :
08464
08465 say_and_wait(chan, vms->newmessages, chan->language) ||
08466 ast_play_and_wait(chan, "vm-nuovi") ||
08467 ast_play_and_wait(chan, "vm-messages");
08468 if (!res && vms->oldmessages)
08469 res = ast_play_and_wait(chan, "vm-and");
08470 }
08471 if (!res && vms->oldmessages) {
08472 res = (vms->oldmessages == 1) ?
08473 ast_play_and_wait(chan, "digits/un") ||
08474 ast_play_and_wait(chan, "vm-vecchio") ||
08475 ast_play_and_wait(chan, "vm-message") :
08476
08477 say_and_wait(chan, vms->oldmessages, chan->language) ||
08478 ast_play_and_wait(chan, "vm-vecchi") ||
08479 ast_play_and_wait(chan, "vm-messages");
08480 }
08481 return res;
08482 }
08483
08484
08485 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08486 {
08487
08488 int res;
08489 div_t num;
08490
08491 if (!vms->oldmessages && !vms->newmessages) {
08492 res = ast_play_and_wait(chan, "vm-no");
08493 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08494 return res;
08495 } else {
08496 res = ast_play_and_wait(chan, "vm-youhave");
08497 }
08498
08499 if (vms->newmessages) {
08500 num = div(vms->newmessages, 10);
08501 if (vms->newmessages == 1) {
08502 res = ast_play_and_wait(chan, "digits/1-a");
08503 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08504 res = res ? res : ast_play_and_wait(chan, "vm-message");
08505 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08506 if (num.rem == 2) {
08507 if (!num.quot) {
08508 res = ast_play_and_wait(chan, "digits/2-ie");
08509 } else {
08510 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08511 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08512 }
08513 } else {
08514 res = say_and_wait(chan, vms->newmessages, chan->language);
08515 }
08516 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08517 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08518 } else {
08519 res = say_and_wait(chan, vms->newmessages, chan->language);
08520 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08521 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08522 }
08523 if (!res && vms->oldmessages)
08524 res = ast_play_and_wait(chan, "vm-and");
08525 }
08526 if (!res && vms->oldmessages) {
08527 num = div(vms->oldmessages, 10);
08528 if (vms->oldmessages == 1) {
08529 res = ast_play_and_wait(chan, "digits/1-a");
08530 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08531 res = res ? res : ast_play_and_wait(chan, "vm-message");
08532 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08533 if (num.rem == 2) {
08534 if (!num.quot) {
08535 res = ast_play_and_wait(chan, "digits/2-ie");
08536 } else {
08537 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08538 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08539 }
08540 } else {
08541 res = say_and_wait(chan, vms->oldmessages, chan->language);
08542 }
08543 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08544 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08545 } else {
08546 res = say_and_wait(chan, vms->oldmessages, chan->language);
08547 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08548 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08549 }
08550 }
08551
08552 return res;
08553 }
08554
08555
08556 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08557 {
08558
08559 int res;
08560
08561 res = ast_play_and_wait(chan, "vm-youhave");
08562 if (res)
08563 return res;
08564
08565 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08566 res = ast_play_and_wait(chan, "vm-no");
08567 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08568 return res;
08569 }
08570
08571 if (vms->newmessages) {
08572 if ((vms->newmessages == 1)) {
08573 res = ast_play_and_wait(chan, "digits/ett");
08574 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08575 res = res ? res : ast_play_and_wait(chan, "vm-message");
08576 } else {
08577 res = say_and_wait(chan, vms->newmessages, chan->language);
08578 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08579 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08580 }
08581 if (!res && vms->oldmessages)
08582 res = ast_play_and_wait(chan, "vm-and");
08583 }
08584 if (!res && vms->oldmessages) {
08585 if (vms->oldmessages == 1) {
08586 res = ast_play_and_wait(chan, "digits/ett");
08587 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08588 res = res ? res : ast_play_and_wait(chan, "vm-message");
08589 } else {
08590 res = say_and_wait(chan, vms->oldmessages, chan->language);
08591 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08592 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08593 }
08594 }
08595
08596 return res;
08597 }
08598
08599
08600 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08601 {
08602
08603 int res;
08604
08605 res = ast_play_and_wait(chan, "vm-youhave");
08606 if (res)
08607 return res;
08608
08609 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08610 res = ast_play_and_wait(chan, "vm-no");
08611 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08612 return res;
08613 }
08614
08615 if (vms->newmessages) {
08616 if ((vms->newmessages == 1)) {
08617 res = ast_play_and_wait(chan, "digits/1");
08618 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08619 res = res ? res : ast_play_and_wait(chan, "vm-message");
08620 } else {
08621 res = say_and_wait(chan, vms->newmessages, chan->language);
08622 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08623 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08624 }
08625 if (!res && vms->oldmessages)
08626 res = ast_play_and_wait(chan, "vm-and");
08627 }
08628 if (!res && vms->oldmessages) {
08629 if (vms->oldmessages == 1) {
08630 res = ast_play_and_wait(chan, "digits/1");
08631 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08632 res = res ? res : ast_play_and_wait(chan, "vm-message");
08633 } else {
08634 res = say_and_wait(chan, vms->oldmessages, chan->language);
08635 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08636 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08637 }
08638 }
08639
08640 return res;
08641 }
08642
08643
08644 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08645 {
08646
08647 int res;
08648 res = ast_play_and_wait(chan, "vm-youhave");
08649 if (!res) {
08650 if (vms->newmessages) {
08651 if ((vms->newmessages == 1))
08652 res = ast_play_and_wait(chan, "digits/1F");
08653 else
08654 res = say_and_wait(chan, vms->newmessages, chan->language);
08655 if (!res)
08656 res = ast_play_and_wait(chan, "vm-INBOX");
08657 if (vms->oldmessages && !res)
08658 res = ast_play_and_wait(chan, "vm-and");
08659 else if (!res) {
08660 if ((vms->newmessages == 1))
08661 res = ast_play_and_wait(chan, "vm-message");
08662 else
08663 res = ast_play_and_wait(chan, "vm-messages");
08664 }
08665
08666 }
08667 if (!res && vms->oldmessages) {
08668 if (vms->oldmessages == 1)
08669 res = ast_play_and_wait(chan, "digits/1F");
08670 else
08671 res = say_and_wait(chan, vms->oldmessages, chan->language);
08672 if (!res)
08673 res = ast_play_and_wait(chan, "vm-Old");
08674 if (!res) {
08675 if (vms->oldmessages == 1)
08676 res = ast_play_and_wait(chan, "vm-message");
08677 else
08678 res = ast_play_and_wait(chan, "vm-messages");
08679 }
08680 }
08681 if (!res) {
08682 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08683 res = ast_play_and_wait(chan, "vm-no");
08684 if (!res)
08685 res = ast_play_and_wait(chan, "vm-messages");
08686 }
08687 }
08688 }
08689 return res;
08690 }
08691
08692
08693 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08694 {
08695
08696 int res;
08697 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08698 res = ast_play_and_wait(chan, "vm-youhaveno");
08699 if (!res)
08700 res = ast_play_and_wait(chan, "vm-messages");
08701 } else {
08702 res = ast_play_and_wait(chan, "vm-youhave");
08703 }
08704 if (!res) {
08705 if (vms->newmessages) {
08706 if (!res) {
08707 if ((vms->newmessages == 1)) {
08708 res = ast_play_and_wait(chan, "digits/1M");
08709 if (!res)
08710 res = ast_play_and_wait(chan, "vm-message");
08711 if (!res)
08712 res = ast_play_and_wait(chan, "vm-INBOXs");
08713 } else {
08714 res = say_and_wait(chan, vms->newmessages, chan->language);
08715 if (!res)
08716 res = ast_play_and_wait(chan, "vm-messages");
08717 if (!res)
08718 res = ast_play_and_wait(chan, "vm-INBOX");
08719 }
08720 }
08721 if (vms->oldmessages && !res)
08722 res = ast_play_and_wait(chan, "vm-and");
08723 }
08724 if (vms->oldmessages) {
08725 if (!res) {
08726 if (vms->oldmessages == 1) {
08727 res = ast_play_and_wait(chan, "digits/1M");
08728 if (!res)
08729 res = ast_play_and_wait(chan, "vm-message");
08730 if (!res)
08731 res = ast_play_and_wait(chan, "vm-Olds");
08732 } else {
08733 res = say_and_wait(chan, vms->oldmessages, chan->language);
08734 if (!res)
08735 res = ast_play_and_wait(chan, "vm-messages");
08736 if (!res)
08737 res = ast_play_and_wait(chan, "vm-Old");
08738 }
08739 }
08740 }
08741 }
08742 return res;
08743 }
08744
08745
08746 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08747
08748 int res;
08749 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08750 res = ast_play_and_wait(chan, "vm-nomessages");
08751 return res;
08752 } else {
08753 res = ast_play_and_wait(chan, "vm-youhave");
08754 }
08755 if (vms->newmessages) {
08756 if (!res)
08757 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08758 if ((vms->newmessages == 1)) {
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-message");
08761 if (!res)
08762 res = ast_play_and_wait(chan, "vm-INBOXs");
08763 } else {
08764 if (!res)
08765 res = ast_play_and_wait(chan, "vm-messages");
08766 if (!res)
08767 res = ast_play_and_wait(chan, "vm-INBOX");
08768 }
08769 if (vms->oldmessages && !res)
08770 res = ast_play_and_wait(chan, "vm-and");
08771 }
08772 if (vms->oldmessages) {
08773 if (!res)
08774 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08775 if (vms->oldmessages == 1) {
08776 if (!res)
08777 res = ast_play_and_wait(chan, "vm-message");
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-Olds");
08780 } else {
08781 if (!res)
08782 res = ast_play_and_wait(chan, "vm-messages");
08783 if (!res)
08784 res = ast_play_and_wait(chan, "vm-Old");
08785 }
08786 }
08787 return res;
08788 }
08789
08790
08791 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08792 {
08793
08794 int res;
08795 res = ast_play_and_wait(chan, "vm-youhave");
08796 if (!res) {
08797 if (vms->newmessages) {
08798 res = say_and_wait(chan, vms->newmessages, chan->language);
08799 if (!res)
08800 res = ast_play_and_wait(chan, "vm-INBOX");
08801 if (vms->oldmessages && !res)
08802 res = ast_play_and_wait(chan, "vm-and");
08803 else if (!res) {
08804 if ((vms->newmessages == 1))
08805 res = ast_play_and_wait(chan, "vm-message");
08806 else
08807 res = ast_play_and_wait(chan, "vm-messages");
08808 }
08809
08810 }
08811 if (!res && vms->oldmessages) {
08812 res = say_and_wait(chan, vms->oldmessages, chan->language);
08813 if (!res)
08814 res = ast_play_and_wait(chan, "vm-Old");
08815 if (!res) {
08816 if (vms->oldmessages == 1)
08817 res = ast_play_and_wait(chan, "vm-message");
08818 else
08819 res = ast_play_and_wait(chan, "vm-messages");
08820 }
08821 }
08822 if (!res) {
08823 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08824 res = ast_play_and_wait(chan, "vm-no");
08825 if (!res)
08826 res = ast_play_and_wait(chan, "vm-messages");
08827 }
08828 }
08829 }
08830 return res;
08831 }
08832
08833
08834 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08835 {
08836
08837 int res;
08838 res = ast_play_and_wait(chan, "vm-youhave");
08839 if (!res) {
08840 if (vms->newmessages) {
08841 res = say_and_wait(chan, vms->newmessages, chan->language);
08842 if (!res) {
08843 if (vms->newmessages == 1)
08844 res = ast_play_and_wait(chan, "vm-INBOXs");
08845 else
08846 res = ast_play_and_wait(chan, "vm-INBOX");
08847 }
08848 if (vms->oldmessages && !res)
08849 res = ast_play_and_wait(chan, "vm-and");
08850 else if (!res) {
08851 if ((vms->newmessages == 1))
08852 res = ast_play_and_wait(chan, "vm-message");
08853 else
08854 res = ast_play_and_wait(chan, "vm-messages");
08855 }
08856
08857 }
08858 if (!res && vms->oldmessages) {
08859 res = say_and_wait(chan, vms->oldmessages, chan->language);
08860 if (!res) {
08861 if (vms->oldmessages == 1)
08862 res = ast_play_and_wait(chan, "vm-Olds");
08863 else
08864 res = ast_play_and_wait(chan, "vm-Old");
08865 }
08866 if (!res) {
08867 if (vms->oldmessages == 1)
08868 res = ast_play_and_wait(chan, "vm-message");
08869 else
08870 res = ast_play_and_wait(chan, "vm-messages");
08871 }
08872 }
08873 if (!res) {
08874 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08875 res = ast_play_and_wait(chan, "vm-no");
08876 if (!res)
08877 res = ast_play_and_wait(chan, "vm-messages");
08878 }
08879 }
08880 }
08881 return res;
08882 }
08883
08884
08885 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08886 {
08887
08888 int res;
08889 res = ast_play_and_wait(chan, "vm-youhave");
08890 if (!res) {
08891 if (vms->newmessages) {
08892 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08893 if (!res) {
08894 if ((vms->newmessages == 1)) {
08895 res = ast_play_and_wait(chan, "vm-message");
08896 if (!res)
08897 res = ast_play_and_wait(chan, "vm-INBOXs");
08898 } else {
08899 res = ast_play_and_wait(chan, "vm-messages");
08900 if (!res)
08901 res = ast_play_and_wait(chan, "vm-INBOX");
08902 }
08903 }
08904 if (vms->oldmessages && !res)
08905 res = ast_play_and_wait(chan, "vm-and");
08906 }
08907 if (!res && vms->oldmessages) {
08908 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08909 if (!res) {
08910 if (vms->oldmessages == 1) {
08911 res = ast_play_and_wait(chan, "vm-message");
08912 if (!res)
08913 res = ast_play_and_wait(chan, "vm-Olds");
08914 } else {
08915 res = ast_play_and_wait(chan, "vm-messages");
08916 if (!res)
08917 res = ast_play_and_wait(chan, "vm-Old");
08918 }
08919 }
08920 }
08921 if (!res) {
08922 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08923 res = ast_play_and_wait(chan, "vm-no");
08924 if (!res)
08925 res = ast_play_and_wait(chan, "vm-messages");
08926 }
08927 }
08928 }
08929 return res;
08930 }
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941
08942
08943
08944
08945
08946
08947
08948 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08949 {
08950 int res;
08951 res = ast_play_and_wait(chan, "vm-youhave");
08952 if (!res) {
08953 if (vms->newmessages) {
08954 if (vms->newmessages == 1) {
08955 res = ast_play_and_wait(chan, "digits/jednu");
08956 } else {
08957 res = say_and_wait(chan, vms->newmessages, chan->language);
08958 }
08959 if (!res) {
08960 if ((vms->newmessages == 1))
08961 res = ast_play_and_wait(chan, "vm-novou");
08962 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08963 res = ast_play_and_wait(chan, "vm-nove");
08964 if (vms->newmessages > 4)
08965 res = ast_play_and_wait(chan, "vm-novych");
08966 }
08967 if (vms->oldmessages && !res)
08968 res = ast_play_and_wait(chan, "vm-and");
08969 else if (!res) {
08970 if ((vms->newmessages == 1))
08971 res = ast_play_and_wait(chan, "vm-zpravu");
08972 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08973 res = ast_play_and_wait(chan, "vm-zpravy");
08974 if (vms->newmessages > 4)
08975 res = ast_play_and_wait(chan, "vm-zprav");
08976 }
08977 }
08978 if (!res && vms->oldmessages) {
08979 res = say_and_wait(chan, vms->oldmessages, chan->language);
08980 if (!res) {
08981 if ((vms->oldmessages == 1))
08982 res = ast_play_and_wait(chan, "vm-starou");
08983 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08984 res = ast_play_and_wait(chan, "vm-stare");
08985 if (vms->oldmessages > 4)
08986 res = ast_play_and_wait(chan, "vm-starych");
08987 }
08988 if (!res) {
08989 if ((vms->oldmessages == 1))
08990 res = ast_play_and_wait(chan, "vm-zpravu");
08991 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08992 res = ast_play_and_wait(chan, "vm-zpravy");
08993 if (vms->oldmessages > 4)
08994 res = ast_play_and_wait(chan, "vm-zprav");
08995 }
08996 }
08997 if (!res) {
08998 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08999 res = ast_play_and_wait(chan, "vm-no");
09000 if (!res)
09001 res = ast_play_and_wait(chan, "vm-zpravy");
09002 }
09003 }
09004 }
09005 return res;
09006 }
09007
09008
09009 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09010 {
09011 int res;
09012
09013 res = ast_play_and_wait(chan, "vm-you");
09014
09015 if (!res && vms->newmessages) {
09016 res = ast_play_and_wait(chan, "vm-have");
09017 if (!res)
09018 res = say_and_wait(chan, vms->newmessages, chan->language);
09019 if (!res)
09020 res = ast_play_and_wait(chan, "vm-tong");
09021 if (!res)
09022 res = ast_play_and_wait(chan, "vm-INBOX");
09023 if (vms->oldmessages && !res)
09024 res = ast_play_and_wait(chan, "vm-and");
09025 else if (!res)
09026 res = ast_play_and_wait(chan, "vm-messages");
09027 }
09028 if (!res && vms->oldmessages) {
09029 res = ast_play_and_wait(chan, "vm-have");
09030 if (!res)
09031 res = say_and_wait(chan, vms->oldmessages, chan->language);
09032 if (!res)
09033 res = ast_play_and_wait(chan, "vm-tong");
09034 if (!res)
09035 res = ast_play_and_wait(chan, "vm-Old");
09036 if (!res)
09037 res = ast_play_and_wait(chan, "vm-messages");
09038 }
09039 if (!res && !vms->oldmessages && !vms->newmessages) {
09040 res = ast_play_and_wait(chan, "vm-haveno");
09041 if (!res)
09042 res = ast_play_and_wait(chan, "vm-messages");
09043 }
09044 return res;
09045 }
09046
09047
09048 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09049 {
09050 int res;
09051
09052
09053 res = ast_play_and_wait(chan, "vm-youhave");
09054 if (!res) {
09055 if (vms->newmessages) {
09056 res = say_and_wait(chan, vms->newmessages, chan->language);
09057 if (!res)
09058 res = ast_play_and_wait(chan, "vm-INBOX");
09059 if (vms->oldmessages && !res)
09060 res = ast_play_and_wait(chan, "vm-and");
09061 }
09062 if (!res && vms->oldmessages) {
09063 res = say_and_wait(chan, vms->oldmessages, chan->language);
09064 if (!res)
09065 res = ast_play_and_wait(chan, "vm-Old");
09066 }
09067 if (!res) {
09068 if (!vms->oldmessages && !vms->newmessages) {
09069 res = ast_play_and_wait(chan, "vm-no");
09070 if (!res)
09071 res = ast_play_and_wait(chan, "vm-message");
09072 }
09073 }
09074 }
09075 return res;
09076 }
09077
09078 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09079 {
09080 char prefile[256];
09081
09082
09083 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09084 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09085 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09086 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09087 ast_play_and_wait(chan, "vm-tempgreetactive");
09088 }
09089 DISPOSE(prefile, -1);
09090 }
09091
09092
09093 if (0) {
09094 return 0;
09095 } else if (!strncasecmp(chan->language, "cs", 2)) {
09096 return vm_intro_cs(chan, vms);
09097 } else if (!strncasecmp(chan->language, "cz", 2)) {
09098 static int deprecation_warning = 0;
09099 if (deprecation_warning++ % 10 == 0) {
09100 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09101 }
09102 return vm_intro_cs(chan, vms);
09103 } else if (!strncasecmp(chan->language, "de", 2)) {
09104 return vm_intro_de(chan, vms);
09105 } else if (!strncasecmp(chan->language, "es", 2)) {
09106 return vm_intro_es(chan, vms);
09107 } else if (!strncasecmp(chan->language, "fr", 2)) {
09108 return vm_intro_fr(chan, vms);
09109 } else if (!strncasecmp(chan->language, "gr", 2)) {
09110 return vm_intro_gr(chan, vms);
09111 } else if (!strncasecmp(chan->language, "he", 2)) {
09112 return vm_intro_he(chan, vms);
09113 } else if (!strncasecmp(chan->language, "it", 2)) {
09114 return vm_intro_it(chan, vms);
09115 } else if (!strncasecmp(chan->language, "nl", 2)) {
09116 return vm_intro_nl(chan, vms);
09117 } else if (!strncasecmp(chan->language, "no", 2)) {
09118 return vm_intro_no(chan, vms);
09119 } else if (!strncasecmp(chan->language, "pl", 2)) {
09120 return vm_intro_pl(chan, vms);
09121 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09122 return vm_intro_pt_BR(chan, vms);
09123 } else if (!strncasecmp(chan->language, "pt", 2)) {
09124 return vm_intro_pt(chan, vms);
09125 } else if (!strncasecmp(chan->language, "ru", 2)) {
09126 return vm_intro_multilang(chan, vms, "n");
09127 } else if (!strncasecmp(chan->language, "se", 2)) {
09128 return vm_intro_se(chan, vms);
09129 } else if (!strncasecmp(chan->language, "ua", 2)) {
09130 return vm_intro_multilang(chan, vms, "n");
09131 } else if (!strncasecmp(chan->language, "vi", 2)) {
09132 return vm_intro_vi(chan, vms);
09133 } else if (!strncasecmp(chan->language, "zh", 2)) {
09134 return vm_intro_zh(chan, vms);
09135 } else {
09136 return vm_intro_en(chan, vms);
09137 }
09138 }
09139
09140 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09141 {
09142 int res = 0;
09143
09144 while (!res) {
09145 if (vms->starting) {
09146 if (vms->lastmsg > -1) {
09147 if (skipadvanced)
09148 res = ast_play_and_wait(chan, "vm-onefor-full");
09149 else
09150 res = ast_play_and_wait(chan, "vm-onefor");
09151 if (!res)
09152 res = vm_play_folder_name(chan, vms->vmbox);
09153 }
09154 if (!res) {
09155 if (skipadvanced)
09156 res = ast_play_and_wait(chan, "vm-opts-full");
09157 else
09158 res = ast_play_and_wait(chan, "vm-opts");
09159 }
09160 } else {
09161
09162 if (skipadvanced) {
09163 res = ast_play_and_wait(chan, "vm-onefor-full");
09164 if (!res)
09165 res = vm_play_folder_name(chan, vms->vmbox);
09166 res = ast_play_and_wait(chan, "vm-opts-full");
09167 }
09168
09169
09170
09171
09172
09173
09174 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09175 res = ast_play_and_wait(chan, "vm-prev");
09176 }
09177 if (!res && !skipadvanced)
09178 res = ast_play_and_wait(chan, "vm-advopts");
09179 if (!res)
09180 res = ast_play_and_wait(chan, "vm-repeat");
09181
09182
09183
09184
09185
09186
09187 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09188 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09189 res = ast_play_and_wait(chan, "vm-next");
09190 }
09191 if (!res) {
09192 int curmsg_deleted;
09193 #ifdef IMAP_STORAGE
09194 ast_mutex_lock(&vms->lock);
09195 #endif
09196 curmsg_deleted = vms->deleted[vms->curmsg];
09197 #ifdef IMAP_STORAGE
09198 ast_mutex_unlock(&vms->lock);
09199 #endif
09200 if (!curmsg_deleted) {
09201 res = ast_play_and_wait(chan, "vm-delete");
09202 } else {
09203 res = ast_play_and_wait(chan, "vm-undelete");
09204 }
09205 if (!res) {
09206 res = ast_play_and_wait(chan, "vm-toforward");
09207 }
09208 if (!res) {
09209 res = ast_play_and_wait(chan, "vm-savemessage");
09210 }
09211 }
09212 }
09213 if (!res) {
09214 res = ast_play_and_wait(chan, "vm-helpexit");
09215 }
09216 if (!res)
09217 res = ast_waitfordigit(chan, 6000);
09218 if (!res) {
09219 vms->repeats++;
09220 if (vms->repeats > 2) {
09221 res = 't';
09222 }
09223 }
09224 }
09225 return res;
09226 }
09227
09228 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09229 {
09230 int res = 0;
09231
09232 while (!res) {
09233 if (vms->lastmsg > -1) {
09234 res = ast_play_and_wait(chan, "vm-listen");
09235 if (!res)
09236 res = vm_play_folder_name(chan, vms->vmbox);
09237 if (!res)
09238 res = ast_play_and_wait(chan, "press");
09239 if (!res)
09240 res = ast_play_and_wait(chan, "digits/1");
09241 }
09242 if (!res)
09243 res = ast_play_and_wait(chan, "vm-opts");
09244 if (!res) {
09245 vms->starting = 0;
09246 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09247 }
09248 }
09249 return res;
09250 }
09251
09252 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09253 {
09254 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09255 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09256 } else {
09257 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09258 }
09259 }
09260
09261
09262 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09263 {
09264 int cmd = 0;
09265 int duration = 0;
09266 int tries = 0;
09267 char newpassword[80] = "";
09268 char newpassword2[80] = "";
09269 char prefile[PATH_MAX] = "";
09270 unsigned char buf[256];
09271 int bytes = 0;
09272
09273 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09274 if (ast_adsi_available(chan)) {
09275 bytes += adsi_logo(buf + bytes);
09276 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09277 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09278 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09279 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09280 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09281 }
09282
09283
09284 if (ast_test_flag(vmu, VM_FORCENAME)) {
09285 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09286 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09287 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09288 if (cmd < 0 || cmd == 't' || cmd == '#')
09289 return cmd;
09290 }
09291 }
09292
09293
09294 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09295 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09296 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09297 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09298 if (cmd < 0 || cmd == 't' || cmd == '#')
09299 return cmd;
09300 }
09301
09302 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09303 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09304 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09305 if (cmd < 0 || cmd == 't' || cmd == '#')
09306 return cmd;
09307 }
09308 }
09309
09310
09311
09312
09313
09314 for (;;) {
09315 newpassword[1] = '\0';
09316 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09317 if (cmd == '#')
09318 newpassword[0] = '\0';
09319 if (cmd < 0 || cmd == 't' || cmd == '#')
09320 return cmd;
09321 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09322 if (cmd < 0 || cmd == 't' || cmd == '#')
09323 return cmd;
09324 cmd = check_password(vmu, newpassword);
09325 if (cmd != 0) {
09326 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09327 cmd = ast_play_and_wait(chan, vm_invalid_password);
09328 } else {
09329 newpassword2[1] = '\0';
09330 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09331 if (cmd == '#')
09332 newpassword2[0] = '\0';
09333 if (cmd < 0 || cmd == 't' || cmd == '#')
09334 return cmd;
09335 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09336 if (cmd < 0 || cmd == 't' || cmd == '#')
09337 return cmd;
09338 if (!strcmp(newpassword, newpassword2))
09339 break;
09340 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09341 cmd = ast_play_and_wait(chan, vm_mismatch);
09342 }
09343 if (++tries == 3)
09344 return -1;
09345 if (cmd != 0) {
09346 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09347 }
09348 }
09349 if (pwdchange & PWDCHANGE_INTERNAL)
09350 vm_change_password(vmu, newpassword);
09351 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09352 vm_change_password_shell(vmu, newpassword);
09353
09354 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09355 cmd = ast_play_and_wait(chan, vm_passchanged);
09356
09357 return cmd;
09358 }
09359
09360 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09361 {
09362 int cmd = 0;
09363 int retries = 0;
09364 int duration = 0;
09365 char newpassword[80] = "";
09366 char newpassword2[80] = "";
09367 char prefile[PATH_MAX] = "";
09368 unsigned char buf[256];
09369 int bytes = 0;
09370
09371 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09372 if (ast_adsi_available(chan)) {
09373 bytes += adsi_logo(buf + bytes);
09374 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09375 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09376 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09377 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09378 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09379 }
09380 while ((cmd >= 0) && (cmd != 't')) {
09381 if (cmd)
09382 retries = 0;
09383 switch (cmd) {
09384 case '1':
09385 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09386 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09387 break;
09388 case '2':
09389 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09390 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09391 break;
09392 case '3':
09393 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09394 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09395 break;
09396 case '4':
09397 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09398 break;
09399 case '5':
09400 if (vmu->password[0] == '-') {
09401 cmd = ast_play_and_wait(chan, "vm-no");
09402 break;
09403 }
09404 newpassword[1] = '\0';
09405 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09406 if (cmd == '#')
09407 newpassword[0] = '\0';
09408 else {
09409 if (cmd < 0)
09410 break;
09411 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09412 break;
09413 }
09414 }
09415 cmd = check_password(vmu, newpassword);
09416 if (cmd != 0) {
09417 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09418 cmd = ast_play_and_wait(chan, vm_invalid_password);
09419 if (!cmd) {
09420 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09421 }
09422 break;
09423 }
09424 newpassword2[1] = '\0';
09425 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09426 if (cmd == '#')
09427 newpassword2[0] = '\0';
09428 else {
09429 if (cmd < 0)
09430 break;
09431
09432 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09433 break;
09434 }
09435 }
09436 if (strcmp(newpassword, newpassword2)) {
09437 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09438 cmd = ast_play_and_wait(chan, vm_mismatch);
09439 if (!cmd) {
09440 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09441 }
09442 break;
09443 }
09444
09445 if (pwdchange & PWDCHANGE_INTERNAL) {
09446 vm_change_password(vmu, newpassword);
09447 }
09448 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09449 vm_change_password_shell(vmu, newpassword);
09450 }
09451
09452 ast_debug(1, "User %s set password to %s of length %d\n",
09453 vms->username, newpassword, (int) strlen(newpassword));
09454 cmd = ast_play_and_wait(chan, vm_passchanged);
09455 break;
09456 case '*':
09457 cmd = 't';
09458 break;
09459 default:
09460 cmd = 0;
09461 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09462 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09463 if (ast_fileexists(prefile, NULL, NULL)) {
09464 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09465 }
09466 DISPOSE(prefile, -1);
09467 if (!cmd) {
09468 cmd = ast_play_and_wait(chan, "vm-options");
09469 }
09470 if (!cmd) {
09471 cmd = ast_waitfordigit(chan, 6000);
09472 }
09473 if (!cmd) {
09474 retries++;
09475 }
09476 if (retries > 3) {
09477 cmd = 't';
09478 }
09479 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09480 }
09481 }
09482 if (cmd == 't')
09483 cmd = 0;
09484 return cmd;
09485 }
09486
09487
09488
09489
09490
09491
09492
09493
09494
09495
09496
09497
09498
09499
09500
09501
09502
09503 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09504 {
09505 int cmd = 0;
09506 int retries = 0;
09507 int duration = 0;
09508 char prefile[PATH_MAX] = "";
09509 unsigned char buf[256];
09510 int bytes = 0;
09511
09512 if (ast_adsi_available(chan)) {
09513 bytes += adsi_logo(buf + bytes);
09514 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09515 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09516 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09517 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09518 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09519 }
09520
09521 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09522 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09523 while ((cmd >= 0) && (cmd != 't')) {
09524 if (cmd)
09525 retries = 0;
09526 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09527 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09528 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09529 if (cmd == -1) {
09530 break;
09531 }
09532 cmd = 't';
09533 } else {
09534 switch (cmd) {
09535 case '1':
09536 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09537 break;
09538 case '2':
09539 DELETE(prefile, -1, prefile, vmu);
09540 ast_play_and_wait(chan, "vm-tempremoved");
09541 cmd = 't';
09542 break;
09543 case '*':
09544 cmd = 't';
09545 break;
09546 default:
09547 cmd = ast_play_and_wait(chan,
09548 ast_fileexists(prefile, NULL, NULL) > 0 ?
09549 "vm-tempgreeting2" : "vm-tempgreeting");
09550 if (!cmd) {
09551 cmd = ast_waitfordigit(chan, 6000);
09552 }
09553 if (!cmd) {
09554 retries++;
09555 }
09556 if (retries > 3) {
09557 cmd = 't';
09558 }
09559 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09560 }
09561 }
09562 DISPOSE(prefile, -1);
09563 }
09564 if (cmd == 't')
09565 cmd = 0;
09566 return cmd;
09567 }
09568
09569
09570
09571
09572
09573
09574
09575
09576
09577 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09578 {
09579 int cmd = 0;
09580
09581 if (vms->lastmsg > -1) {
09582 cmd = play_message(chan, vmu, vms);
09583 } else {
09584 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09585 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09586 if (!cmd) {
09587 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09588 cmd = ast_play_and_wait(chan, vms->fn);
09589 }
09590 if (!cmd)
09591 cmd = ast_play_and_wait(chan, "vm-messages");
09592 } else {
09593 if (!cmd)
09594 cmd = ast_play_and_wait(chan, "vm-messages");
09595 if (!cmd) {
09596 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09597 cmd = ast_play_and_wait(chan, vms->fn);
09598 }
09599 }
09600 }
09601 return cmd;
09602 }
09603
09604
09605 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09606 {
09607 int cmd = 0;
09608
09609 if (vms->lastmsg > -1) {
09610 cmd = play_message(chan, vmu, vms);
09611 } else {
09612 if (!strcasecmp(vms->fn, "INBOX")) {
09613 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09614 } else {
09615 cmd = ast_play_and_wait(chan, "vm-nomessages");
09616 }
09617 }
09618 return cmd;
09619 }
09620
09621
09622
09623
09624
09625
09626
09627
09628
09629 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09630 {
09631 int cmd = 0;
09632
09633 if (vms->lastmsg > -1) {
09634 cmd = play_message(chan, vmu, vms);
09635 } else {
09636 cmd = ast_play_and_wait(chan, "vm-youhave");
09637 if (!cmd)
09638 cmd = ast_play_and_wait(chan, "vm-no");
09639 if (!cmd) {
09640 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09641 cmd = ast_play_and_wait(chan, vms->fn);
09642 }
09643 if (!cmd)
09644 cmd = ast_play_and_wait(chan, "vm-messages");
09645 }
09646 return cmd;
09647 }
09648
09649
09650
09651
09652
09653
09654
09655
09656
09657 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09658 {
09659 int cmd;
09660
09661 if (vms->lastmsg > -1) {
09662 cmd = play_message(chan, vmu, vms);
09663 } else {
09664 cmd = ast_play_and_wait(chan, "vm-no");
09665 if (!cmd)
09666 cmd = ast_play_and_wait(chan, "vm-message");
09667 if (!cmd) {
09668 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09669 cmd = ast_play_and_wait(chan, vms->fn);
09670 }
09671 }
09672 return cmd;
09673 }
09674
09675
09676
09677
09678
09679
09680
09681
09682
09683 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09684 {
09685 int cmd;
09686
09687 if (vms->lastmsg > -1) {
09688 cmd = play_message(chan, vmu, vms);
09689 } else {
09690 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09691 if (!cmd)
09692 cmd = ast_play_and_wait(chan, "vm-messages");
09693 if (!cmd) {
09694 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09695 cmd = ast_play_and_wait(chan, vms->fn);
09696 }
09697 }
09698 return cmd;
09699 }
09700
09701
09702
09703
09704
09705
09706
09707
09708
09709 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09710 {
09711 int cmd;
09712
09713 if (vms->lastmsg > -1) {
09714 cmd = play_message(chan, vmu, vms);
09715 } else {
09716 cmd = ast_play_and_wait(chan, "vm-no");
09717 if (!cmd) {
09718 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09719 cmd = ast_play_and_wait(chan, vms->fn);
09720 }
09721 if (!cmd)
09722 cmd = ast_play_and_wait(chan, "vm-messages");
09723 }
09724 return cmd;
09725 }
09726
09727
09728
09729
09730
09731
09732
09733
09734
09735 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09736 {
09737 int cmd;
09738
09739 if (vms->lastmsg > -1) {
09740 cmd = play_message(chan, vmu, vms);
09741 } else {
09742 cmd = ast_play_and_wait(chan, "vm-you");
09743 if (!cmd)
09744 cmd = ast_play_and_wait(chan, "vm-haveno");
09745 if (!cmd)
09746 cmd = ast_play_and_wait(chan, "vm-messages");
09747 if (!cmd) {
09748 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09749 cmd = ast_play_and_wait(chan, vms->fn);
09750 }
09751 }
09752 return cmd;
09753 }
09754
09755
09756
09757
09758
09759
09760
09761
09762
09763 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09764 {
09765 int cmd = 0;
09766
09767 if (vms->lastmsg > -1) {
09768 cmd = play_message(chan, vmu, vms);
09769 } else {
09770 cmd = ast_play_and_wait(chan, "vm-no");
09771 if (!cmd) {
09772 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09773 cmd = ast_play_and_wait(chan, vms->fn);
09774 }
09775 }
09776 return cmd;
09777 }
09778
09779
09780
09781
09782
09783
09784
09785
09786
09787
09788
09789
09790 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09791 {
09792 if (!strncasecmp(chan->language, "es", 2)) {
09793 return vm_browse_messages_es(chan, vms, vmu);
09794 } else if (!strncasecmp(chan->language, "gr", 2)) {
09795 return vm_browse_messages_gr(chan, vms, vmu);
09796 } else if (!strncasecmp(chan->language, "he", 2)) {
09797 return vm_browse_messages_he(chan, vms, vmu);
09798 } else if (!strncasecmp(chan->language, "it", 2)) {
09799 return vm_browse_messages_it(chan, vms, vmu);
09800 } else if (!strncasecmp(chan->language, "pt", 2)) {
09801 return vm_browse_messages_pt(chan, vms, vmu);
09802 } else if (!strncasecmp(chan->language, "vi", 2)) {
09803 return vm_browse_messages_vi(chan, vms, vmu);
09804 } else if (!strncasecmp(chan->language, "zh", 2)) {
09805 return vm_browse_messages_zh(chan, vms, vmu);
09806 } else {
09807 return vm_browse_messages_en(chan, vms, vmu);
09808 }
09809 }
09810
09811 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09812 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09813 int skipuser, int max_logins, int silent)
09814 {
09815 int useadsi = 0, valid = 0, logretries = 0;
09816 char password[AST_MAX_EXTENSION]="", *passptr;
09817 struct ast_vm_user vmus, *vmu = NULL;
09818
09819
09820 adsi_begin(chan, &useadsi);
09821 if (!skipuser && useadsi)
09822 adsi_login(chan);
09823 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09824 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09825 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09826 return -1;
09827 }
09828
09829
09830
09831 while (!valid && (logretries < max_logins)) {
09832
09833 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09834 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09835 return -1;
09836 }
09837 if (ast_strlen_zero(mailbox)) {
09838 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09839 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09840 } else {
09841 ast_verb(3, "Username not entered\n");
09842 return -1;
09843 }
09844 } else if (mailbox[0] == '*') {
09845
09846 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09847 if (ast_exists_extension(chan, chan->context, "a", 1,
09848 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09849 return -1;
09850 }
09851 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09852 mailbox[0] = '\0';
09853 }
09854
09855 if (useadsi)
09856 adsi_password(chan);
09857
09858 if (!ast_strlen_zero(prefix)) {
09859 char fullusername[80] = "";
09860 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09861 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09862 ast_copy_string(mailbox, fullusername, mailbox_size);
09863 }
09864
09865 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09866 vmu = find_user(&vmus, context, mailbox);
09867 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09868
09869 password[0] = '\0';
09870 } else {
09871 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09872 if (ast_streamfile(chan, vm_password, chan->language)) {
09873 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09874 return -1;
09875 }
09876 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09877 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09878 return -1;
09879 } else if (password[0] == '*') {
09880
09881 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09882 if (ast_exists_extension(chan, chan->context, "a", 1,
09883 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09884 mailbox[0] = '*';
09885 return -1;
09886 }
09887 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09888 mailbox[0] = '\0';
09889
09890 vmu = NULL;
09891 }
09892 }
09893
09894 if (vmu) {
09895 passptr = vmu->password;
09896 if (passptr[0] == '-') passptr++;
09897 }
09898 if (vmu && !strcmp(passptr, password))
09899 valid++;
09900 else {
09901 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09902 if (!ast_strlen_zero(prefix))
09903 mailbox[0] = '\0';
09904 }
09905 logretries++;
09906 if (!valid) {
09907 if (skipuser || logretries >= max_logins) {
09908 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09909 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09910 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09911 return -1;
09912 }
09913 } else {
09914 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09915 if (useadsi)
09916 adsi_login(chan);
09917 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09918 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09919 return -1;
09920 }
09921 }
09922 if (ast_waitstream(chan, ""))
09923 return -1;
09924 }
09925 }
09926 if (!valid && (logretries >= max_logins)) {
09927 ast_stopstream(chan);
09928 ast_play_and_wait(chan, "vm-goodbye");
09929 return -1;
09930 }
09931 if (vmu && !skipuser) {
09932 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09933 }
09934 return 0;
09935 }
09936
09937 static int vm_execmain(struct ast_channel *chan, const char *data)
09938 {
09939
09940
09941
09942 int res = -1;
09943 int cmd = 0;
09944 int valid = 0;
09945 char prefixstr[80] ="";
09946 char ext_context[256]="";
09947 int box;
09948 int useadsi = 0;
09949 int skipuser = 0;
09950 struct vm_state vms;
09951 struct ast_vm_user *vmu = NULL, vmus;
09952 char *context = NULL;
09953 int silentexit = 0;
09954 struct ast_flags flags = { 0 };
09955 signed char record_gain = 0;
09956 int play_auto = 0;
09957 int play_folder = 0;
09958 int in_urgent = 0;
09959 #ifdef IMAP_STORAGE
09960 int deleted = 0;
09961 #endif
09962
09963
09964 memset(&vms, 0, sizeof(vms));
09965
09966 vms.lastmsg = -1;
09967
09968 memset(&vmus, 0, sizeof(vmus));
09969
09970 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09971 if (chan->_state != AST_STATE_UP) {
09972 ast_debug(1, "Before ast_answer\n");
09973 ast_answer(chan);
09974 }
09975
09976 if (!ast_strlen_zero(data)) {
09977 char *opts[OPT_ARG_ARRAY_SIZE];
09978 char *parse;
09979 AST_DECLARE_APP_ARGS(args,
09980 AST_APP_ARG(argv0);
09981 AST_APP_ARG(argv1);
09982 );
09983
09984 parse = ast_strdupa(data);
09985
09986 AST_STANDARD_APP_ARGS(args, parse);
09987
09988 if (args.argc == 2) {
09989 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09990 return -1;
09991 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09992 int gain;
09993 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09994 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09995 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09996 return -1;
09997 } else {
09998 record_gain = (signed char) gain;
09999 }
10000 } else {
10001 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
10002 }
10003 }
10004 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10005 play_auto = 1;
10006 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10007
10008 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10009 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10010 play_folder = -1;
10011 }
10012 } else {
10013 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10014 }
10015 } else {
10016 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10017 }
10018 if (play_folder > 9 || play_folder < 0) {
10019 ast_log(AST_LOG_WARNING,
10020 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10021 opts[OPT_ARG_PLAYFOLDER]);
10022 play_folder = 0;
10023 }
10024 }
10025 } else {
10026
10027 while (*(args.argv0)) {
10028 if (*(args.argv0) == 's')
10029 ast_set_flag(&flags, OPT_SILENT);
10030 else if (*(args.argv0) == 'p')
10031 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10032 else
10033 break;
10034 (args.argv0)++;
10035 }
10036
10037 }
10038
10039 valid = ast_test_flag(&flags, OPT_SILENT);
10040
10041 if ((context = strchr(args.argv0, '@')))
10042 *context++ = '\0';
10043
10044 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10045 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10046 else
10047 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10048
10049 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10050 skipuser++;
10051 else
10052 valid = 0;
10053 }
10054
10055 if (!valid)
10056 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10057
10058 ast_debug(1, "After vm_authenticate\n");
10059
10060 if (vms.username[0] == '*') {
10061 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10062
10063
10064 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10065 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10066 res = 0;
10067 goto out;
10068 }
10069 }
10070
10071 if (!res) {
10072 valid = 1;
10073 if (!skipuser)
10074 vmu = &vmus;
10075 } else {
10076 res = 0;
10077 }
10078
10079
10080 adsi_begin(chan, &useadsi);
10081
10082 ast_test_suite_assert(valid);
10083 if (!valid) {
10084 goto out;
10085 }
10086 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10087
10088 #ifdef IMAP_STORAGE
10089 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10090 pthread_setspecific(ts_vmstate.key, &vms);
10091
10092 vms.interactive = 1;
10093 vms.updated = 1;
10094 if (vmu)
10095 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10096 vmstate_insert(&vms);
10097 init_vm_state(&vms);
10098 #endif
10099
10100
10101 if (!ast_strlen_zero(vmu->language))
10102 ast_string_field_set(chan, language, vmu->language);
10103
10104
10105 ast_debug(1, "Before open_mailbox\n");
10106 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10107 if (res < 0)
10108 goto out;
10109 vms.oldmessages = vms.lastmsg + 1;
10110 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10111
10112 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10113 if (res < 0)
10114 goto out;
10115 vms.newmessages = vms.lastmsg + 1;
10116 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10117
10118 in_urgent = 1;
10119 res = open_mailbox(&vms, vmu, 11);
10120 if (res < 0)
10121 goto out;
10122 vms.urgentmessages = vms.lastmsg + 1;
10123 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10124
10125
10126 if (play_auto) {
10127 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10128 if (vms.urgentmessages) {
10129 in_urgent = 1;
10130 res = open_mailbox(&vms, vmu, 11);
10131 } else {
10132 in_urgent = 0;
10133 res = open_mailbox(&vms, vmu, play_folder);
10134 }
10135 if (res < 0)
10136 goto out;
10137
10138
10139 if (vms.lastmsg == -1) {
10140 in_urgent = 0;
10141 cmd = vm_browse_messages(chan, &vms, vmu);
10142 res = 0;
10143 goto out;
10144 }
10145 } else {
10146 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10147
10148 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10149 in_urgent = 0;
10150 play_folder = 1;
10151 if (res < 0)
10152 goto out;
10153 } else if (!vms.urgentmessages && vms.newmessages) {
10154
10155 in_urgent = 0;
10156 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10157 if (res < 0)
10158 goto out;
10159 }
10160 }
10161
10162 if (useadsi)
10163 adsi_status(chan, &vms);
10164 res = 0;
10165
10166
10167 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10168 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10169 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10170 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10171 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10172 if ((cmd == 't') || (cmd == '#')) {
10173
10174 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10175 res = 0;
10176 goto out;
10177 } else if (cmd < 0) {
10178
10179 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10180 res = -1;
10181 goto out;
10182 }
10183 }
10184 #ifdef IMAP_STORAGE
10185 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10186 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10187 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10188 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10189 }
10190 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10191 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10192 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10193 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10194 }
10195 #endif
10196
10197 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10198 if (play_auto) {
10199 cmd = '1';
10200 } else {
10201 cmd = vm_intro(chan, vmu, &vms);
10202 }
10203 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10204
10205 vms.repeats = 0;
10206 vms.starting = 1;
10207 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10208
10209 switch (cmd) {
10210 case '1':
10211 vms.curmsg = 0;
10212
10213 case '5':
10214 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10215 cmd = vm_browse_messages(chan, &vms, vmu);
10216 break;
10217 case '2':
10218 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10219 if (useadsi)
10220 adsi_folders(chan, 0, "Change to folder...");
10221
10222 cmd = get_folder2(chan, "vm-changeto", 0);
10223 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10224 if (cmd == '#') {
10225 cmd = 0;
10226 } else if (cmd > 0) {
10227 cmd = cmd - '0';
10228 res = close_mailbox(&vms, vmu);
10229 if (res == ERROR_LOCK_PATH)
10230 goto out;
10231
10232 if (cmd != 11) in_urgent = 0;
10233 res = open_mailbox(&vms, vmu, cmd);
10234 if (res < 0)
10235 goto out;
10236 play_folder = cmd;
10237 cmd = 0;
10238 }
10239 if (useadsi)
10240 adsi_status2(chan, &vms);
10241
10242 if (!cmd) {
10243 cmd = vm_play_folder_name(chan, vms.vmbox);
10244 }
10245
10246 vms.starting = 1;
10247 vms.curmsg = 0;
10248 break;
10249 case '3':
10250 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10251 cmd = 0;
10252 vms.repeats = 0;
10253 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10254 switch (cmd) {
10255 case '1':
10256 if (vms.lastmsg > -1 && !vms.starting) {
10257 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10258 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10259 res = cmd;
10260 goto out;
10261 }
10262 } else {
10263 cmd = ast_play_and_wait(chan, "vm-sorry");
10264 }
10265 cmd = 't';
10266 break;
10267 case '2':
10268 if (!vms.starting)
10269 ast_verb(3, "Callback Requested\n");
10270 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10271 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10272 if (cmd == 9) {
10273 silentexit = 1;
10274 goto out;
10275 } else if (cmd == ERROR_LOCK_PATH) {
10276 res = cmd;
10277 goto out;
10278 }
10279 } else {
10280 cmd = ast_play_and_wait(chan, "vm-sorry");
10281 }
10282 cmd = 't';
10283 break;
10284 case '3':
10285 if (vms.lastmsg > -1 && !vms.starting) {
10286 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10287 if (cmd == ERROR_LOCK_PATH) {
10288 res = cmd;
10289 goto out;
10290 }
10291 } else {
10292 cmd = ast_play_and_wait(chan, "vm-sorry");
10293 }
10294 cmd = 't';
10295 break;
10296 case '4':
10297 if (!ast_strlen_zero(vmu->dialout)) {
10298 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10299 if (cmd == 9) {
10300 silentexit = 1;
10301 goto out;
10302 }
10303 } else {
10304 cmd = ast_play_and_wait(chan, "vm-sorry");
10305 }
10306 cmd = 't';
10307 break;
10308
10309 case '5':
10310 if (ast_test_flag(vmu, VM_SVMAIL)) {
10311 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10312 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10313 res = cmd;
10314 goto out;
10315 }
10316 } else {
10317 cmd = ast_play_and_wait(chan, "vm-sorry");
10318 }
10319 cmd = 't';
10320 break;
10321
10322 case '*':
10323 cmd = 't';
10324 break;
10325
10326 default:
10327 cmd = 0;
10328 if (!vms.starting) {
10329 cmd = ast_play_and_wait(chan, "vm-toreply");
10330 }
10331 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10332 cmd = ast_play_and_wait(chan, "vm-tocallback");
10333 }
10334 if (!cmd && !vms.starting) {
10335 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10336 }
10337 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10338 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10339 }
10340 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10341 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10342 }
10343 if (!cmd) {
10344 cmd = ast_play_and_wait(chan, "vm-starmain");
10345 }
10346 if (!cmd) {
10347 cmd = ast_waitfordigit(chan, 6000);
10348 }
10349 if (!cmd) {
10350 vms.repeats++;
10351 }
10352 if (vms.repeats > 3) {
10353 cmd = 't';
10354 }
10355 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10356 }
10357 }
10358 if (cmd == 't') {
10359 cmd = 0;
10360 vms.repeats = 0;
10361 }
10362 break;
10363 case '4':
10364 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10365 if (vms.curmsg > 0) {
10366 vms.curmsg--;
10367 cmd = play_message(chan, vmu, &vms);
10368 } else {
10369
10370
10371
10372
10373 if (in_urgent == 0 && vms.urgentmessages > 0) {
10374
10375 in_urgent = 1;
10376 res = close_mailbox(&vms, vmu);
10377 if (res == ERROR_LOCK_PATH)
10378 goto out;
10379 res = open_mailbox(&vms, vmu, 11);
10380 if (res < 0)
10381 goto out;
10382 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10383 vms.curmsg = vms.lastmsg;
10384 if (vms.lastmsg < 0) {
10385 cmd = ast_play_and_wait(chan, "vm-nomore");
10386 }
10387 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10388 vms.curmsg = vms.lastmsg;
10389 cmd = play_message(chan, vmu, &vms);
10390 } else {
10391 cmd = ast_play_and_wait(chan, "vm-nomore");
10392 }
10393 }
10394 break;
10395 case '6':
10396 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10397 if (vms.curmsg < vms.lastmsg) {
10398 vms.curmsg++;
10399 cmd = play_message(chan, vmu, &vms);
10400 } else {
10401 if (in_urgent && vms.newmessages > 0) {
10402
10403
10404
10405
10406 in_urgent = 0;
10407 res = close_mailbox(&vms, vmu);
10408 if (res == ERROR_LOCK_PATH)
10409 goto out;
10410 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10411 if (res < 0)
10412 goto out;
10413 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10414 vms.curmsg = -1;
10415 if (vms.lastmsg < 0) {
10416 cmd = ast_play_and_wait(chan, "vm-nomore");
10417 }
10418 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10419 vms.curmsg = 0;
10420 cmd = play_message(chan, vmu, &vms);
10421 } else {
10422 cmd = ast_play_and_wait(chan, "vm-nomore");
10423 }
10424 }
10425 break;
10426 case '7':
10427 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10428 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10429 if (useadsi)
10430 adsi_delete(chan, &vms);
10431 if (vms.deleted[vms.curmsg]) {
10432 if (play_folder == 0) {
10433 if (in_urgent) {
10434 vms.urgentmessages--;
10435 } else {
10436 vms.newmessages--;
10437 }
10438 }
10439 else if (play_folder == 1)
10440 vms.oldmessages--;
10441 cmd = ast_play_and_wait(chan, "vm-deleted");
10442 } else {
10443 if (play_folder == 0) {
10444 if (in_urgent) {
10445 vms.urgentmessages++;
10446 } else {
10447 vms.newmessages++;
10448 }
10449 }
10450 else if (play_folder == 1)
10451 vms.oldmessages++;
10452 cmd = ast_play_and_wait(chan, "vm-undeleted");
10453 }
10454 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10455 if (vms.curmsg < vms.lastmsg) {
10456 vms.curmsg++;
10457 cmd = play_message(chan, vmu, &vms);
10458 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10459 vms.curmsg = 0;
10460 cmd = play_message(chan, vmu, &vms);
10461 } else {
10462
10463
10464
10465
10466 if (in_urgent == 1) {
10467
10468 in_urgent = 0;
10469 res = close_mailbox(&vms, vmu);
10470 if (res == ERROR_LOCK_PATH)
10471 goto out;
10472 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10473 if (res < 0)
10474 goto out;
10475 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10476 vms.curmsg = -1;
10477 if (vms.lastmsg < 0) {
10478 cmd = ast_play_and_wait(chan, "vm-nomore");
10479 }
10480 } else {
10481 cmd = ast_play_and_wait(chan, "vm-nomore");
10482 }
10483 }
10484 }
10485 } else
10486 cmd = 0;
10487 #ifdef IMAP_STORAGE
10488 deleted = 1;
10489 #endif
10490 break;
10491
10492 case '8':
10493 if (vms.lastmsg > -1) {
10494 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10495 if (cmd == ERROR_LOCK_PATH) {
10496 res = cmd;
10497 goto out;
10498 }
10499 } else {
10500
10501
10502
10503
10504 if (in_urgent == 1 && vms.newmessages > 0) {
10505
10506 in_urgent = 0;
10507 res = close_mailbox(&vms, vmu);
10508 if (res == ERROR_LOCK_PATH)
10509 goto out;
10510 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10511 if (res < 0)
10512 goto out;
10513 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10514 vms.curmsg = -1;
10515 if (vms.lastmsg < 0) {
10516 cmd = ast_play_and_wait(chan, "vm-nomore");
10517 }
10518 } else {
10519 cmd = ast_play_and_wait(chan, "vm-nomore");
10520 }
10521 }
10522 break;
10523 case '9':
10524 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10525 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10526
10527 cmd = 0;
10528 break;
10529 }
10530 if (useadsi)
10531 adsi_folders(chan, 1, "Save to folder...");
10532 cmd = get_folder2(chan, "vm-savefolder", 1);
10533 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10534 box = 0;
10535 if (cmd == '#') {
10536 cmd = 0;
10537 break;
10538 } else if (cmd > 0) {
10539 box = cmd = cmd - '0';
10540 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10541 if (cmd == ERROR_LOCK_PATH) {
10542 res = cmd;
10543 goto out;
10544 #ifndef IMAP_STORAGE
10545 } else if (!cmd) {
10546 vms.deleted[vms.curmsg] = 1;
10547 #endif
10548 } else {
10549 vms.deleted[vms.curmsg] = 0;
10550 vms.heard[vms.curmsg] = 0;
10551 }
10552 }
10553 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10554 if (useadsi)
10555 adsi_message(chan, &vms);
10556 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10557 if (!cmd) {
10558 cmd = ast_play_and_wait(chan, "vm-message");
10559 if (!cmd)
10560 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10561 if (!cmd)
10562 cmd = ast_play_and_wait(chan, "vm-savedto");
10563 if (!cmd)
10564 cmd = vm_play_folder_name(chan, vms.fn);
10565 } else {
10566 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10567 }
10568 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10569 if (vms.curmsg < vms.lastmsg) {
10570 vms.curmsg++;
10571 cmd = play_message(chan, vmu, &vms);
10572 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10573 vms.curmsg = 0;
10574 cmd = play_message(chan, vmu, &vms);
10575 } else {
10576
10577
10578
10579
10580 if (in_urgent == 1 && vms.newmessages > 0) {
10581
10582 in_urgent = 0;
10583 res = close_mailbox(&vms, vmu);
10584 if (res == ERROR_LOCK_PATH)
10585 goto out;
10586 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10587 if (res < 0)
10588 goto out;
10589 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10590 vms.curmsg = -1;
10591 if (vms.lastmsg < 0) {
10592 cmd = ast_play_and_wait(chan, "vm-nomore");
10593 }
10594 } else {
10595 cmd = ast_play_and_wait(chan, "vm-nomore");
10596 }
10597 }
10598 }
10599 break;
10600 case '*':
10601 if (!vms.starting) {
10602 cmd = ast_play_and_wait(chan, "vm-onefor");
10603 if (!strncasecmp(chan->language, "he", 2)) {
10604 cmd = ast_play_and_wait(chan, "vm-for");
10605 }
10606 if (!cmd)
10607 cmd = vm_play_folder_name(chan, vms.vmbox);
10608 if (!cmd)
10609 cmd = ast_play_and_wait(chan, "vm-opts");
10610 if (!cmd)
10611 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10612 } else
10613 cmd = 0;
10614 break;
10615 case '0':
10616 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10617 if (useadsi)
10618 adsi_status(chan, &vms);
10619 break;
10620 default:
10621 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10622 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10623 break;
10624 }
10625 }
10626 if ((cmd == 't') || (cmd == '#')) {
10627
10628 res = 0;
10629 } else {
10630
10631 res = -1;
10632 }
10633
10634 out:
10635 if (res > -1) {
10636 ast_stopstream(chan);
10637 adsi_goodbye(chan);
10638 if (valid && res != OPERATOR_EXIT) {
10639 if (silentexit)
10640 res = ast_play_and_wait(chan, "vm-dialout");
10641 else
10642 res = ast_play_and_wait(chan, "vm-goodbye");
10643 }
10644 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10645 res = 0;
10646 }
10647 if (useadsi)
10648 ast_adsi_unload_session(chan);
10649 }
10650 if (vmu)
10651 close_mailbox(&vms, vmu);
10652 if (valid) {
10653 int new = 0, old = 0, urgent = 0;
10654 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10655 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10656
10657 run_externnotify(vmu->context, vmu->mailbox, NULL);
10658 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10659 queue_mwi_event(ext_context, urgent, new, old);
10660 }
10661 #ifdef IMAP_STORAGE
10662
10663 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10664 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10665 ast_mutex_lock(&vms.lock);
10666 #ifdef HAVE_IMAP_TK2006
10667 if (LEVELUIDPLUS (vms.mailstream)) {
10668 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10669 } else
10670 #endif
10671 mail_expunge(vms.mailstream);
10672 ast_mutex_unlock(&vms.lock);
10673 }
10674
10675
10676 if (vmu) {
10677 vmstate_delete(&vms);
10678 }
10679 #endif
10680 if (vmu)
10681 free_user(vmu);
10682
10683 #ifdef IMAP_STORAGE
10684 pthread_setspecific(ts_vmstate.key, NULL);
10685 #endif
10686 return res;
10687 }
10688
10689 static int vm_exec(struct ast_channel *chan, const char *data)
10690 {
10691 int res = 0;
10692 char *tmp;
10693 struct leave_vm_options leave_options;
10694 struct ast_flags flags = { 0 };
10695 char *opts[OPT_ARG_ARRAY_SIZE];
10696 AST_DECLARE_APP_ARGS(args,
10697 AST_APP_ARG(argv0);
10698 AST_APP_ARG(argv1);
10699 );
10700
10701 memset(&leave_options, 0, sizeof(leave_options));
10702
10703 if (chan->_state != AST_STATE_UP)
10704 ast_answer(chan);
10705
10706 if (!ast_strlen_zero(data)) {
10707 tmp = ast_strdupa(data);
10708 AST_STANDARD_APP_ARGS(args, tmp);
10709 if (args.argc == 2) {
10710 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10711 return -1;
10712 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10713 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10714 int gain;
10715
10716 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10717 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10718 return -1;
10719 } else {
10720 leave_options.record_gain = (signed char) gain;
10721 }
10722 }
10723 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10724 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10725 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10726 }
10727 }
10728 } else {
10729 char temp[256];
10730 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10731 if (res < 0)
10732 return res;
10733 if (ast_strlen_zero(temp))
10734 return 0;
10735 args.argv0 = ast_strdupa(temp);
10736 }
10737
10738 res = leave_voicemail(chan, args.argv0, &leave_options);
10739 if (res == 't') {
10740 ast_play_and_wait(chan, "vm-goodbye");
10741 res = 0;
10742 }
10743
10744 if (res == OPERATOR_EXIT) {
10745 res = 0;
10746 }
10747
10748 if (res == ERROR_LOCK_PATH) {
10749 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10750 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10751 res = 0;
10752 }
10753
10754 return res;
10755 }
10756
10757 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10758 {
10759 struct ast_vm_user *vmu;
10760
10761 if (!ast_strlen_zero(box) && box[0] == '*') {
10762 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10763 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10764 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10765 "\n\tand will be ignored.\n", box, context);
10766 return NULL;
10767 }
10768
10769 AST_LIST_TRAVERSE(&users, vmu, list) {
10770 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10771 if (strcasecmp(vmu->context, context)) {
10772 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10773 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10774 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10775 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10776 }
10777 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10778 return NULL;
10779 }
10780 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10781 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10782 return NULL;
10783 }
10784 }
10785
10786 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10787 return NULL;
10788
10789 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10790 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10791
10792 AST_LIST_INSERT_TAIL(&users, vmu, list);
10793
10794 return vmu;
10795 }
10796
10797 static int append_mailbox(const char *context, const char *box, const char *data)
10798 {
10799
10800 char *tmp;
10801 char *stringp;
10802 char *s;
10803 struct ast_vm_user *vmu;
10804 char *mailbox_full;
10805 int new = 0, old = 0, urgent = 0;
10806 char secretfn[PATH_MAX] = "";
10807
10808 tmp = ast_strdupa(data);
10809
10810 if (!(vmu = find_or_create(context, box)))
10811 return -1;
10812
10813 populate_defaults(vmu);
10814
10815 stringp = tmp;
10816 if ((s = strsep(&stringp, ","))) {
10817 if (!ast_strlen_zero(s) && s[0] == '*') {
10818 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10819 "\n\tmust be reset in voicemail.conf.\n", box);
10820 }
10821
10822 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10823 }
10824 if (stringp && (s = strsep(&stringp, ","))) {
10825 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10826 }
10827 if (stringp && (s = strsep(&stringp, ","))) {
10828 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10829 }
10830 if (stringp && (s = strsep(&stringp, ","))) {
10831 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10832 }
10833 if (stringp && (s = strsep(&stringp, ","))) {
10834 apply_options(vmu, s);
10835 }
10836
10837 switch (vmu->passwordlocation) {
10838 case OPT_PWLOC_SPOOLDIR:
10839 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10840 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10841 }
10842
10843 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10844 strcpy(mailbox_full, box);
10845 strcat(mailbox_full, "@");
10846 strcat(mailbox_full, context);
10847
10848 inboxcount2(mailbox_full, &urgent, &new, &old);
10849 queue_mwi_event(mailbox_full, urgent, new, old);
10850
10851 return 0;
10852 }
10853
10854 AST_TEST_DEFINE(test_voicemail_vmuser)
10855 {
10856 int res = 0;
10857 struct ast_vm_user *vmu;
10858
10859 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10860 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10861 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10862 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10863 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10864 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10865 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10866 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10867 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10868 #ifdef IMAP_STORAGE
10869 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10870 "imapfolder=INBOX|imapvmshareid=6000";
10871 #endif
10872
10873 switch (cmd) {
10874 case TEST_INIT:
10875 info->name = "vmuser";
10876 info->category = "/apps/app_voicemail/";
10877 info->summary = "Vmuser unit test";
10878 info->description =
10879 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10880 return AST_TEST_NOT_RUN;
10881 case TEST_EXECUTE:
10882 break;
10883 }
10884
10885 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10886 return AST_TEST_NOT_RUN;
10887 }
10888 populate_defaults(vmu);
10889 ast_set_flag(vmu, VM_ALLOCED);
10890
10891 apply_options(vmu, options_string);
10892
10893 if (!ast_test_flag(vmu, VM_ATTACH)) {
10894 ast_test_status_update(test, "Parse failure for attach option\n");
10895 res = 1;
10896 }
10897 if (strcasecmp(vmu->attachfmt, "wav49")) {
10898 ast_test_status_update(test, "Parse failure for attachftm option\n");
10899 res = 1;
10900 }
10901 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10902 ast_test_status_update(test, "Parse failure for serveremail option\n");
10903 res = 1;
10904 }
10905 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10906 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10907 res = 1;
10908 }
10909 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10910 ast_test_status_update(test, "Parse failure for emailbody option\n");
10911 res = 1;
10912 }
10913 if (strcasecmp(vmu->zonetag, "central")) {
10914 ast_test_status_update(test, "Parse failure for tz option\n");
10915 res = 1;
10916 }
10917 if (!ast_test_flag(vmu, VM_DELETE)) {
10918 ast_test_status_update(test, "Parse failure for delete option\n");
10919 res = 1;
10920 }
10921 if (!ast_test_flag(vmu, VM_SAYCID)) {
10922 ast_test_status_update(test, "Parse failure for saycid option\n");
10923 res = 1;
10924 }
10925 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10926 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10927 res = 1;
10928 }
10929 if (!ast_test_flag(vmu, VM_REVIEW)) {
10930 ast_test_status_update(test, "Parse failure for review option\n");
10931 res = 1;
10932 }
10933 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10934 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10935 res = 1;
10936 }
10937 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10938 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10939 res = 1;
10940 }
10941 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10942 ast_test_status_update(test, "Parse failure for operator option\n");
10943 res = 1;
10944 }
10945 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10946 ast_test_status_update(test, "Parse failure for envelope option\n");
10947 res = 1;
10948 }
10949 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10950 ast_test_status_update(test, "Parse failure for moveheard option\n");
10951 res = 1;
10952 }
10953 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10954 ast_test_status_update(test, "Parse failure for sayduration option\n");
10955 res = 1;
10956 }
10957 if (vmu->saydurationm != 5) {
10958 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10959 res = 1;
10960 }
10961 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10962 ast_test_status_update(test, "Parse failure for forcename option\n");
10963 res = 1;
10964 }
10965 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10966 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10967 res = 1;
10968 }
10969 if (strcasecmp(vmu->callback, "somecontext")) {
10970 ast_test_status_update(test, "Parse failure for callbacks option\n");
10971 res = 1;
10972 }
10973 if (strcasecmp(vmu->dialout, "somecontext2")) {
10974 ast_test_status_update(test, "Parse failure for dialout option\n");
10975 res = 1;
10976 }
10977 if (strcasecmp(vmu->exit, "somecontext3")) {
10978 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10979 res = 1;
10980 }
10981 if (vmu->minsecs != 10) {
10982 ast_test_status_update(test, "Parse failure for minsecs option\n");
10983 res = 1;
10984 }
10985 if (vmu->maxsecs != 100) {
10986 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10987 res = 1;
10988 }
10989 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10990 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10991 res = 1;
10992 }
10993 if (vmu->maxdeletedmsg != 50) {
10994 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10995 res = 1;
10996 }
10997 if (vmu->volgain != 1.3) {
10998 ast_test_status_update(test, "Parse failure for volgain option\n");
10999 res = 1;
11000 }
11001 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
11002 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
11003 res = 1;
11004 }
11005 #ifdef IMAP_STORAGE
11006 apply_options(vmu, option_string2);
11007
11008 if (strcasecmp(vmu->imapuser, "imapuser")) {
11009 ast_test_status_update(test, "Parse failure for imapuser option\n");
11010 res = 1;
11011 }
11012 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11013 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11014 res = 1;
11015 }
11016 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11017 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11018 res = 1;
11019 }
11020 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11021 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11022 res = 1;
11023 }
11024 #endif
11025
11026 free_user(vmu);
11027 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11028 }
11029
11030 static int vm_box_exists(struct ast_channel *chan, const char *data)
11031 {
11032 struct ast_vm_user svm;
11033 char *context, *box;
11034 AST_DECLARE_APP_ARGS(args,
11035 AST_APP_ARG(mbox);
11036 AST_APP_ARG(options);
11037 );
11038 static int dep_warning = 0;
11039
11040 if (ast_strlen_zero(data)) {
11041 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11042 return -1;
11043 }
11044
11045 if (!dep_warning) {
11046 dep_warning = 1;
11047 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11048 }
11049
11050 box = ast_strdupa(data);
11051
11052 AST_STANDARD_APP_ARGS(args, box);
11053
11054 if (args.options) {
11055 }
11056
11057 if ((context = strchr(args.mbox, '@'))) {
11058 *context = '\0';
11059 context++;
11060 }
11061
11062 if (find_user(&svm, context, args.mbox)) {
11063 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11064 } else
11065 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11066
11067 return 0;
11068 }
11069
11070 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11071 {
11072 struct ast_vm_user svm;
11073 AST_DECLARE_APP_ARGS(arg,
11074 AST_APP_ARG(mbox);
11075 AST_APP_ARG(context);
11076 );
11077
11078 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11079
11080 if (ast_strlen_zero(arg.mbox)) {
11081 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11082 return -1;
11083 }
11084
11085 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11086 return 0;
11087 }
11088
11089 static struct ast_custom_function mailbox_exists_acf = {
11090 .name = "MAILBOX_EXISTS",
11091 .read = acf_mailbox_exists,
11092 };
11093
11094 static int vmauthenticate(struct ast_channel *chan, const char *data)
11095 {
11096 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11097 struct ast_vm_user vmus;
11098 char *options = NULL;
11099 int silent = 0, skipuser = 0;
11100 int res = -1;
11101
11102 if (data) {
11103 s = ast_strdupa(data);
11104 user = strsep(&s, ",");
11105 options = strsep(&s, ",");
11106 if (user) {
11107 s = user;
11108 user = strsep(&s, "@");
11109 context = strsep(&s, "");
11110 if (!ast_strlen_zero(user))
11111 skipuser++;
11112 ast_copy_string(mailbox, user, sizeof(mailbox));
11113 }
11114 }
11115
11116 if (options) {
11117 silent = (strchr(options, 's')) != NULL;
11118 }
11119
11120 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11121 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11122 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11123 ast_play_and_wait(chan, "auth-thankyou");
11124 res = 0;
11125 } else if (mailbox[0] == '*') {
11126
11127 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11128 res = 0;
11129 }
11130 }
11131
11132 return res;
11133 }
11134
11135 static char *show_users_realtime(int fd, const char *context)
11136 {
11137 struct ast_config *cfg;
11138 const char *cat = NULL;
11139
11140 if (!(cfg = ast_load_realtime_multientry("voicemail",
11141 "context", context, SENTINEL))) {
11142 return CLI_FAILURE;
11143 }
11144
11145 ast_cli(fd,
11146 "\n"
11147 "=============================================================\n"
11148 "=== Configured Voicemail Users ==============================\n"
11149 "=============================================================\n"
11150 "===\n");
11151
11152 while ((cat = ast_category_browse(cfg, cat))) {
11153 struct ast_variable *var = NULL;
11154 ast_cli(fd,
11155 "=== Mailbox ...\n"
11156 "===\n");
11157 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11158 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11159 ast_cli(fd,
11160 "===\n"
11161 "=== ---------------------------------------------------------\n"
11162 "===\n");
11163 }
11164
11165 ast_cli(fd,
11166 "=============================================================\n"
11167 "\n");
11168
11169 ast_config_destroy(cfg);
11170
11171 return CLI_SUCCESS;
11172 }
11173
11174 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11175 {
11176 int which = 0;
11177 int wordlen;
11178 struct ast_vm_user *vmu;
11179 const char *context = "";
11180
11181
11182 if (pos > 4)
11183 return NULL;
11184 if (pos == 3)
11185 return (state == 0) ? ast_strdup("for") : NULL;
11186 wordlen = strlen(word);
11187 AST_LIST_TRAVERSE(&users, vmu, list) {
11188 if (!strncasecmp(word, vmu->context, wordlen)) {
11189 if (context && strcmp(context, vmu->context) && ++which > state)
11190 return ast_strdup(vmu->context);
11191
11192 context = vmu->context;
11193 }
11194 }
11195 return NULL;
11196 }
11197
11198
11199 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11200 {
11201 struct ast_vm_user *vmu;
11202 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11203 const char *context = NULL;
11204 int users_counter = 0;
11205
11206 switch (cmd) {
11207 case CLI_INIT:
11208 e->command = "voicemail show users";
11209 e->usage =
11210 "Usage: voicemail show users [for <context>]\n"
11211 " Lists all mailboxes currently set up\n";
11212 return NULL;
11213 case CLI_GENERATE:
11214 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11215 }
11216
11217 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11218 return CLI_SHOWUSAGE;
11219 if (a->argc == 5) {
11220 if (strcmp(a->argv[3],"for"))
11221 return CLI_SHOWUSAGE;
11222 context = a->argv[4];
11223 }
11224
11225 if (ast_check_realtime("voicemail")) {
11226 if (!context) {
11227 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11228 return CLI_SHOWUSAGE;
11229 }
11230 return show_users_realtime(a->fd, context);
11231 }
11232
11233 AST_LIST_LOCK(&users);
11234 if (AST_LIST_EMPTY(&users)) {
11235 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11236 AST_LIST_UNLOCK(&users);
11237 return CLI_FAILURE;
11238 }
11239 if (!context) {
11240 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11241 } else {
11242 int count = 0;
11243 AST_LIST_TRAVERSE(&users, vmu, list) {
11244 if (!strcmp(context, vmu->context)) {
11245 count++;
11246 break;
11247 }
11248 }
11249 if (count) {
11250 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11251 } else {
11252 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11253 AST_LIST_UNLOCK(&users);
11254 return CLI_FAILURE;
11255 }
11256 }
11257 AST_LIST_TRAVERSE(&users, vmu, list) {
11258 int newmsgs = 0, oldmsgs = 0;
11259 char count[12], tmp[256] = "";
11260
11261 if (!context || !strcmp(context, vmu->context)) {
11262 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11263 inboxcount(tmp, &newmsgs, &oldmsgs);
11264 snprintf(count, sizeof(count), "%d", newmsgs);
11265 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11266 users_counter++;
11267 }
11268 }
11269 AST_LIST_UNLOCK(&users);
11270 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11271 return CLI_SUCCESS;
11272 }
11273
11274
11275 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11276 {
11277 struct vm_zone *zone;
11278 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11279 char *res = CLI_SUCCESS;
11280
11281 switch (cmd) {
11282 case CLI_INIT:
11283 e->command = "voicemail show zones";
11284 e->usage =
11285 "Usage: voicemail show zones\n"
11286 " Lists zone message formats\n";
11287 return NULL;
11288 case CLI_GENERATE:
11289 return NULL;
11290 }
11291
11292 if (a->argc != 3)
11293 return CLI_SHOWUSAGE;
11294
11295 AST_LIST_LOCK(&zones);
11296 if (!AST_LIST_EMPTY(&zones)) {
11297 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11298 AST_LIST_TRAVERSE(&zones, zone, list) {
11299 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11300 }
11301 } else {
11302 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11303 res = CLI_FAILURE;
11304 }
11305 AST_LIST_UNLOCK(&zones);
11306
11307 return res;
11308 }
11309
11310
11311 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11312 {
11313 switch (cmd) {
11314 case CLI_INIT:
11315 e->command = "voicemail reload";
11316 e->usage =
11317 "Usage: voicemail reload\n"
11318 " Reload voicemail configuration\n";
11319 return NULL;
11320 case CLI_GENERATE:
11321 return NULL;
11322 }
11323
11324 if (a->argc != 2)
11325 return CLI_SHOWUSAGE;
11326
11327 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11328 load_config(1);
11329
11330 return CLI_SUCCESS;
11331 }
11332
11333 static struct ast_cli_entry cli_voicemail[] = {
11334 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11335 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11336 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11337 };
11338
11339 #ifdef IMAP_STORAGE
11340 #define DATA_EXPORT_VM_USERS(USER) \
11341 USER(ast_vm_user, context, AST_DATA_STRING) \
11342 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11343 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11344 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11345 USER(ast_vm_user, email, AST_DATA_STRING) \
11346 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11347 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11348 USER(ast_vm_user, pager, AST_DATA_STRING) \
11349 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11350 USER(ast_vm_user, language, AST_DATA_STRING) \
11351 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11352 USER(ast_vm_user, callback, AST_DATA_STRING) \
11353 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11354 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11355 USER(ast_vm_user, exit, AST_DATA_STRING) \
11356 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11357 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11358 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11359 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11360 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11361 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11362 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11363 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11364 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11365 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11366 #else
11367 #define DATA_EXPORT_VM_USERS(USER) \
11368 USER(ast_vm_user, context, AST_DATA_STRING) \
11369 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11370 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11371 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11372 USER(ast_vm_user, email, AST_DATA_STRING) \
11373 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11374 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11375 USER(ast_vm_user, pager, AST_DATA_STRING) \
11376 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11377 USER(ast_vm_user, language, AST_DATA_STRING) \
11378 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11379 USER(ast_vm_user, callback, AST_DATA_STRING) \
11380 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11381 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11382 USER(ast_vm_user, exit, AST_DATA_STRING) \
11383 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11384 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11385 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11386 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11387 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11388 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11389 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11390 #endif
11391
11392 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11393
11394 #define DATA_EXPORT_VM_ZONES(ZONE) \
11395 ZONE(vm_zone, name, AST_DATA_STRING) \
11396 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11397 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11398
11399 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11400
11401
11402
11403
11404
11405
11406
11407
11408 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11409 struct ast_data *data_root, struct ast_vm_user *user)
11410 {
11411 struct ast_data *data_user, *data_zone;
11412 struct ast_data *data_state;
11413 struct vm_zone *zone = NULL;
11414 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11415 char ext_context[256] = "";
11416
11417 data_user = ast_data_add_node(data_root, "user");
11418 if (!data_user) {
11419 return -1;
11420 }
11421
11422 ast_data_add_structure(ast_vm_user, data_user, user);
11423
11424 AST_LIST_LOCK(&zones);
11425 AST_LIST_TRAVERSE(&zones, zone, list) {
11426 if (!strcmp(zone->name, user->zonetag)) {
11427 break;
11428 }
11429 }
11430 AST_LIST_UNLOCK(&zones);
11431
11432
11433 data_state = ast_data_add_node(data_user, "state");
11434 if (!data_state) {
11435 return -1;
11436 }
11437 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11438 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11439 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11440 ast_data_add_int(data_state, "newmsg", newmsg);
11441 ast_data_add_int(data_state, "oldmsg", oldmsg);
11442
11443 if (zone) {
11444 data_zone = ast_data_add_node(data_user, "zone");
11445 ast_data_add_structure(vm_zone, data_zone, zone);
11446 }
11447
11448 if (!ast_data_search_match(search, data_user)) {
11449 ast_data_remove_node(data_root, data_user);
11450 }
11451
11452 return 0;
11453 }
11454
11455 static int vm_users_data_provider_get(const struct ast_data_search *search,
11456 struct ast_data *data_root)
11457 {
11458 struct ast_vm_user *user;
11459
11460 AST_LIST_LOCK(&users);
11461 AST_LIST_TRAVERSE(&users, user, list) {
11462 vm_users_data_provider_get_helper(search, data_root, user);
11463 }
11464 AST_LIST_UNLOCK(&users);
11465
11466 return 0;
11467 }
11468
11469 static const struct ast_data_handler vm_users_data_provider = {
11470 .version = AST_DATA_HANDLER_VERSION,
11471 .get = vm_users_data_provider_get
11472 };
11473
11474 static const struct ast_data_entry vm_data_providers[] = {
11475 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11476 };
11477
11478 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11479 {
11480 int new = 0, old = 0, urgent = 0;
11481
11482 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11483
11484 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11485 mwi_sub->old_urgent = urgent;
11486 mwi_sub->old_new = new;
11487 mwi_sub->old_old = old;
11488 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11489 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11490 }
11491 }
11492
11493 static void poll_subscribed_mailboxes(void)
11494 {
11495 struct mwi_sub *mwi_sub;
11496
11497 AST_RWLIST_RDLOCK(&mwi_subs);
11498 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11499 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11500 poll_subscribed_mailbox(mwi_sub);
11501 }
11502 }
11503 AST_RWLIST_UNLOCK(&mwi_subs);
11504 }
11505
11506 static void *mb_poll_thread(void *data)
11507 {
11508 while (poll_thread_run) {
11509 struct timespec ts = { 0, };
11510 struct timeval wait;
11511
11512 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11513 ts.tv_sec = wait.tv_sec;
11514 ts.tv_nsec = wait.tv_usec * 1000;
11515
11516 ast_mutex_lock(&poll_lock);
11517 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11518 ast_mutex_unlock(&poll_lock);
11519
11520 if (!poll_thread_run)
11521 break;
11522
11523 poll_subscribed_mailboxes();
11524 }
11525
11526 return NULL;
11527 }
11528
11529 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11530 {
11531 ast_free(mwi_sub);
11532 }
11533
11534 static int handle_unsubscribe(void *datap)
11535 {
11536 struct mwi_sub *mwi_sub;
11537 uint32_t *uniqueid = datap;
11538
11539 AST_RWLIST_WRLOCK(&mwi_subs);
11540 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11541 if (mwi_sub->uniqueid == *uniqueid) {
11542 AST_LIST_REMOVE_CURRENT(entry);
11543 break;
11544 }
11545 }
11546 AST_RWLIST_TRAVERSE_SAFE_END
11547 AST_RWLIST_UNLOCK(&mwi_subs);
11548
11549 if (mwi_sub)
11550 mwi_sub_destroy(mwi_sub);
11551
11552 ast_free(uniqueid);
11553 return 0;
11554 }
11555
11556 static int handle_subscribe(void *datap)
11557 {
11558 unsigned int len;
11559 struct mwi_sub *mwi_sub;
11560 struct mwi_sub_task *p = datap;
11561
11562 len = sizeof(*mwi_sub);
11563 if (!ast_strlen_zero(p->mailbox))
11564 len += strlen(p->mailbox);
11565
11566 if (!ast_strlen_zero(p->context))
11567 len += strlen(p->context) + 1;
11568
11569 if (!(mwi_sub = ast_calloc(1, len)))
11570 return -1;
11571
11572 mwi_sub->uniqueid = p->uniqueid;
11573 if (!ast_strlen_zero(p->mailbox))
11574 strcpy(mwi_sub->mailbox, p->mailbox);
11575
11576 if (!ast_strlen_zero(p->context)) {
11577 strcat(mwi_sub->mailbox, "@");
11578 strcat(mwi_sub->mailbox, p->context);
11579 }
11580
11581 AST_RWLIST_WRLOCK(&mwi_subs);
11582 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11583 AST_RWLIST_UNLOCK(&mwi_subs);
11584 ast_free((void *) p->mailbox);
11585 ast_free((void *) p->context);
11586 ast_free(p);
11587 poll_subscribed_mailbox(mwi_sub);
11588 return 0;
11589 }
11590
11591 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11592 {
11593 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11594
11595 if (!uniqueid) {
11596 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11597 return;
11598 }
11599
11600 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11601 ast_free(uniqueid);
11602 return;
11603 }
11604
11605 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11606 ast_free(uniqueid);
11607 return;
11608 }
11609
11610 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11611 *uniqueid = u;
11612 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11613 ast_free(uniqueid);
11614 }
11615 }
11616
11617 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11618 {
11619 struct mwi_sub_task *mwist;
11620
11621 if (ast_event_get_type(event) != AST_EVENT_SUB)
11622 return;
11623
11624 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11625 return;
11626
11627 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11628 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11629 return;
11630 }
11631 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11632 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11633 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11634
11635 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11636 ast_free(mwist);
11637 }
11638 }
11639
11640 static void start_poll_thread(void)
11641 {
11642 int errcode;
11643 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11644 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11645 AST_EVENT_IE_END);
11646
11647 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11648 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11649 AST_EVENT_IE_END);
11650
11651 if (mwi_sub_sub)
11652 ast_event_report_subs(mwi_sub_sub);
11653
11654 poll_thread_run = 1;
11655
11656 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11657 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11658 }
11659 }
11660
11661 static void stop_poll_thread(void)
11662 {
11663 poll_thread_run = 0;
11664
11665 if (mwi_sub_sub) {
11666 ast_event_unsubscribe(mwi_sub_sub);
11667 mwi_sub_sub = NULL;
11668 }
11669
11670 if (mwi_unsub_sub) {
11671 ast_event_unsubscribe(mwi_unsub_sub);
11672 mwi_unsub_sub = NULL;
11673 }
11674
11675 ast_mutex_lock(&poll_lock);
11676 ast_cond_signal(&poll_cond);
11677 ast_mutex_unlock(&poll_lock);
11678
11679 pthread_join(poll_thread, NULL);
11680
11681 poll_thread = AST_PTHREADT_NULL;
11682 }
11683
11684
11685 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11686 {
11687 struct ast_vm_user *vmu = NULL;
11688 const char *id = astman_get_header(m, "ActionID");
11689 char actionid[128] = "";
11690
11691 if (!ast_strlen_zero(id))
11692 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11693
11694 AST_LIST_LOCK(&users);
11695
11696 if (AST_LIST_EMPTY(&users)) {
11697 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11698 AST_LIST_UNLOCK(&users);
11699 return RESULT_SUCCESS;
11700 }
11701
11702 astman_send_ack(s, m, "Voicemail user list will follow");
11703
11704 AST_LIST_TRAVERSE(&users, vmu, list) {
11705 char dirname[256];
11706
11707 #ifdef IMAP_STORAGE
11708 int new, old;
11709 inboxcount(vmu->mailbox, &new, &old);
11710 #endif
11711
11712 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11713 astman_append(s,
11714 "%s"
11715 "Event: VoicemailUserEntry\r\n"
11716 "VMContext: %s\r\n"
11717 "VoiceMailbox: %s\r\n"
11718 "Fullname: %s\r\n"
11719 "Email: %s\r\n"
11720 "Pager: %s\r\n"
11721 "ServerEmail: %s\r\n"
11722 "MailCommand: %s\r\n"
11723 "Language: %s\r\n"
11724 "TimeZone: %s\r\n"
11725 "Callback: %s\r\n"
11726 "Dialout: %s\r\n"
11727 "UniqueID: %s\r\n"
11728 "ExitContext: %s\r\n"
11729 "SayDurationMinimum: %d\r\n"
11730 "SayEnvelope: %s\r\n"
11731 "SayCID: %s\r\n"
11732 "AttachMessage: %s\r\n"
11733 "AttachmentFormat: %s\r\n"
11734 "DeleteMessage: %s\r\n"
11735 "VolumeGain: %.2f\r\n"
11736 "CanReview: %s\r\n"
11737 "CallOperator: %s\r\n"
11738 "MaxMessageCount: %d\r\n"
11739 "MaxMessageLength: %d\r\n"
11740 "NewMessageCount: %d\r\n"
11741 #ifdef IMAP_STORAGE
11742 "OldMessageCount: %d\r\n"
11743 "IMAPUser: %s\r\n"
11744 #endif
11745 "\r\n",
11746 actionid,
11747 vmu->context,
11748 vmu->mailbox,
11749 vmu->fullname,
11750 vmu->email,
11751 vmu->pager,
11752 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11753 mailcmd,
11754 vmu->language,
11755 vmu->zonetag,
11756 vmu->callback,
11757 vmu->dialout,
11758 vmu->uniqueid,
11759 vmu->exit,
11760 vmu->saydurationm,
11761 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11762 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11763 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11764 vmu->attachfmt,
11765 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11766 vmu->volgain,
11767 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11768 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11769 vmu->maxmsg,
11770 vmu->maxsecs,
11771 #ifdef IMAP_STORAGE
11772 new, old, vmu->imapuser
11773 #else
11774 count_messages(vmu, dirname)
11775 #endif
11776 );
11777 }
11778 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11779
11780 AST_LIST_UNLOCK(&users);
11781
11782 return RESULT_SUCCESS;
11783 }
11784
11785
11786 static void free_vm_users(void)
11787 {
11788 struct ast_vm_user *current;
11789 AST_LIST_LOCK(&users);
11790 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11791 ast_set_flag(current, VM_ALLOCED);
11792 free_user(current);
11793 }
11794 AST_LIST_UNLOCK(&users);
11795 }
11796
11797
11798 static void free_vm_zones(void)
11799 {
11800 struct vm_zone *zcur;
11801 AST_LIST_LOCK(&zones);
11802 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11803 free_zone(zcur);
11804 AST_LIST_UNLOCK(&zones);
11805 }
11806
11807 static const char *substitute_escapes(const char *value)
11808 {
11809 char *current;
11810
11811
11812 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11813
11814 ast_str_reset(str);
11815
11816
11817 for (current = (char *) value; *current; current++) {
11818 if (*current == '\\') {
11819 current++;
11820 if (!*current) {
11821 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11822 break;
11823 }
11824 switch (*current) {
11825 case '\\':
11826 ast_str_append(&str, 0, "\\");
11827 break;
11828 case 'r':
11829 ast_str_append(&str, 0, "\r");
11830 break;
11831 case 'n':
11832 #ifdef IMAP_STORAGE
11833 if (!str->used || str->str[str->used - 1] != '\r') {
11834 ast_str_append(&str, 0, "\r");
11835 }
11836 #endif
11837 ast_str_append(&str, 0, "\n");
11838 break;
11839 case 't':
11840 ast_str_append(&str, 0, "\t");
11841 break;
11842 default:
11843 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11844 break;
11845 }
11846 } else {
11847 ast_str_append(&str, 0, "%c", *current);
11848 }
11849 }
11850
11851 return ast_str_buffer(str);
11852 }
11853
11854 static int load_config(int reload)
11855 {
11856 struct ast_config *cfg, *ucfg;
11857 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11858 int res;
11859
11860 ast_unload_realtime("voicemail");
11861 ast_unload_realtime("voicemail_data");
11862
11863 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11864 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11865 return 0;
11866 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11867 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11868 ucfg = NULL;
11869 }
11870 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11871 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11872 ast_config_destroy(ucfg);
11873 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11874 return 0;
11875 }
11876 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11877 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11878 return 0;
11879 } else {
11880 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11881 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11882 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11883 ucfg = NULL;
11884 }
11885 }
11886
11887 res = actual_load_config(reload, cfg, ucfg);
11888
11889 ast_config_destroy(cfg);
11890 ast_config_destroy(ucfg);
11891
11892 return res;
11893 }
11894
11895 #ifdef TEST_FRAMEWORK
11896 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11897 {
11898 ast_unload_realtime("voicemail");
11899 ast_unload_realtime("voicemail_data");
11900 return actual_load_config(reload, cfg, ucfg);
11901 }
11902 #endif
11903
11904 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11905 {
11906 struct ast_vm_user *current;
11907 char *cat;
11908 struct ast_variable *var;
11909 const char *val;
11910 char *q, *stringp, *tmp;
11911 int x;
11912 int tmpadsi[4];
11913 char secretfn[PATH_MAX] = "";
11914
11915 #ifdef IMAP_STORAGE
11916 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11917 #endif
11918
11919 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11920 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11921 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11922 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11923 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11924
11925
11926 free_vm_users();
11927
11928
11929 free_vm_zones();
11930
11931 AST_LIST_LOCK(&users);
11932
11933 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11934 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11935
11936 if (cfg) {
11937
11938
11939 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11940 val = "default";
11941 ast_copy_string(userscontext, val, sizeof(userscontext));
11942
11943 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11944 val = "yes";
11945 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11946
11947 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11948 val = "no";
11949 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11950
11951 volgain = 0.0;
11952 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11953 sscanf(val, "%30lf", &volgain);
11954
11955 #ifdef ODBC_STORAGE
11956 strcpy(odbc_database, "asterisk");
11957 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11958 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11959 }
11960 strcpy(odbc_table, "voicemessages");
11961 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11962 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11963 }
11964 #endif
11965
11966 strcpy(mailcmd, SENDMAIL);
11967 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11968 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11969
11970 maxsilence = 0;
11971 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11972 maxsilence = atoi(val);
11973 if (maxsilence > 0)
11974 maxsilence *= 1000;
11975 }
11976
11977 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11978 maxmsg = MAXMSG;
11979 } else {
11980 maxmsg = atoi(val);
11981 if (maxmsg < 0) {
11982 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11983 maxmsg = MAXMSG;
11984 } else if (maxmsg > MAXMSGLIMIT) {
11985 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11986 maxmsg = MAXMSGLIMIT;
11987 }
11988 }
11989
11990 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11991 maxdeletedmsg = 0;
11992 } else {
11993 if (sscanf(val, "%30d", &x) == 1)
11994 maxdeletedmsg = x;
11995 else if (ast_true(val))
11996 maxdeletedmsg = MAXMSG;
11997 else
11998 maxdeletedmsg = 0;
11999
12000 if (maxdeletedmsg < 0) {
12001 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
12002 maxdeletedmsg = MAXMSG;
12003 } else if (maxdeletedmsg > MAXMSGLIMIT) {
12004 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12005 maxdeletedmsg = MAXMSGLIMIT;
12006 }
12007 }
12008
12009
12010 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12011 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12012 }
12013
12014
12015 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12016 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12017 }
12018
12019
12020 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12021 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12022 pwdchange = PWDCHANGE_EXTERNAL;
12023 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12024 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12025 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12026 }
12027
12028
12029 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12030 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12031 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12032 }
12033
12034 #ifdef IMAP_STORAGE
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12037 ast_copy_string(imapserver, val, sizeof(imapserver));
12038 } else {
12039 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12040 }
12041
12042 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12043 ast_copy_string(imapport, val, sizeof(imapport));
12044 } else {
12045 ast_copy_string(imapport, "143", sizeof(imapport));
12046 }
12047
12048 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12049 ast_copy_string(imapflags, val, sizeof(imapflags));
12050 }
12051
12052 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12053 ast_copy_string(authuser, val, sizeof(authuser));
12054 }
12055
12056 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12057 ast_copy_string(authpassword, val, sizeof(authpassword));
12058 }
12059
12060 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12061 if (ast_false(val))
12062 expungeonhangup = 0;
12063 else
12064 expungeonhangup = 1;
12065 } else {
12066 expungeonhangup = 1;
12067 }
12068
12069 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12070 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12071 } else {
12072 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12073 }
12074 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12075 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12076 }
12077 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12078 imapgreetings = ast_true(val);
12079 } else {
12080 imapgreetings = 0;
12081 }
12082 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12083 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12084 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12085
12086 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12087 } else {
12088 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12089 }
12090
12091
12092
12093
12094
12095 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12096 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12097 } else {
12098 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12099 }
12100
12101 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12102 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12103 } else {
12104 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12105 }
12106
12107 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12108 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12109 } else {
12110 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12111 }
12112
12113 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12114 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12115 } else {
12116 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12117 }
12118
12119
12120 imapversion++;
12121 #endif
12122
12123 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12124 ast_copy_string(externnotify, val, sizeof(externnotify));
12125 ast_debug(1, "found externnotify: %s\n", externnotify);
12126 } else {
12127 externnotify[0] = '\0';
12128 }
12129
12130
12131 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12132 ast_debug(1, "Enabled SMDI voicemail notification\n");
12133 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12134 smdi_iface = ast_smdi_interface_find(val);
12135 } else {
12136 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12137 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12138 }
12139 if (!smdi_iface) {
12140 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12141 }
12142 }
12143
12144
12145 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12146 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12147 silencethreshold = atoi(val);
12148
12149 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12150 val = ASTERISK_USERNAME;
12151 ast_copy_string(serveremail, val, sizeof(serveremail));
12152
12153 vmmaxsecs = 0;
12154 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12155 if (sscanf(val, "%30d", &x) == 1) {
12156 vmmaxsecs = x;
12157 } else {
12158 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12159 }
12160 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12161 static int maxmessage_deprecate = 0;
12162 if (maxmessage_deprecate == 0) {
12163 maxmessage_deprecate = 1;
12164 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12165 }
12166 if (sscanf(val, "%30d", &x) == 1) {
12167 vmmaxsecs = x;
12168 } else {
12169 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12170 }
12171 }
12172
12173 vmminsecs = 0;
12174 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12175 if (sscanf(val, "%30d", &x) == 1) {
12176 vmminsecs = x;
12177 if (maxsilence / 1000 >= vmminsecs) {
12178 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12179 }
12180 } else {
12181 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12182 }
12183 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12184 static int maxmessage_deprecate = 0;
12185 if (maxmessage_deprecate == 0) {
12186 maxmessage_deprecate = 1;
12187 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12188 }
12189 if (sscanf(val, "%30d", &x) == 1) {
12190 vmminsecs = x;
12191 if (maxsilence / 1000 >= vmminsecs) {
12192 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12193 }
12194 } else {
12195 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12196 }
12197 }
12198
12199 val = ast_variable_retrieve(cfg, "general", "format");
12200 if (!val) {
12201 val = "wav";
12202 } else {
12203 tmp = ast_strdupa(val);
12204 val = ast_format_str_reduce(tmp);
12205 if (!val) {
12206 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12207 val = "wav";
12208 }
12209 }
12210 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12211
12212 skipms = 3000;
12213 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12214 if (sscanf(val, "%30d", &x) == 1) {
12215 maxgreet = x;
12216 } else {
12217 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12218 }
12219 }
12220
12221 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12222 if (sscanf(val, "%30d", &x) == 1) {
12223 skipms = x;
12224 } else {
12225 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12226 }
12227 }
12228
12229 maxlogins = 3;
12230 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12231 if (sscanf(val, "%30d", &x) == 1) {
12232 maxlogins = x;
12233 } else {
12234 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12235 }
12236 }
12237
12238 minpassword = MINPASSWORD;
12239 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12240 if (sscanf(val, "%30d", &x) == 1) {
12241 minpassword = x;
12242 } else {
12243 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12244 }
12245 }
12246
12247
12248 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12249 val = "no";
12250 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12251
12252
12253 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12254 val = "no";
12255 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12256
12257 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12258 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12259 stringp = ast_strdupa(val);
12260 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12261 if (!ast_strlen_zero(stringp)) {
12262 q = strsep(&stringp, ",");
12263 while ((*q == ' ')||(*q == '\t'))
12264 q++;
12265 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12266 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12267 } else {
12268 cidinternalcontexts[x][0] = '\0';
12269 }
12270 }
12271 }
12272 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12273 ast_debug(1, "VM Review Option disabled globally\n");
12274 val = "no";
12275 }
12276 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12277
12278
12279 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12280 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12281 val = "no";
12282 } else {
12283 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12284 }
12285 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12286 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12287 ast_debug(1, "VM next message wrap disabled globally\n");
12288 val = "no";
12289 }
12290 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12291
12292 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12293 ast_debug(1, "VM Operator break disabled globally\n");
12294 val = "no";
12295 }
12296 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12297
12298 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12299 ast_debug(1, "VM CID Info before msg disabled globally\n");
12300 val = "no";
12301 }
12302 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12303
12304 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12305 ast_debug(1, "Send Voicemail msg disabled globally\n");
12306 val = "no";
12307 }
12308 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12309
12310 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12311 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12312 val = "yes";
12313 }
12314 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12315
12316 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12317 ast_debug(1, "Move Heard enabled globally\n");
12318 val = "yes";
12319 }
12320 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12321
12322 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12323 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12324 val = "no";
12325 }
12326 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12327
12328 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12329 ast_debug(1, "Duration info before msg enabled globally\n");
12330 val = "yes";
12331 }
12332 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12333
12334 saydurationminfo = 2;
12335 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12336 if (sscanf(val, "%30d", &x) == 1) {
12337 saydurationminfo = x;
12338 } else {
12339 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12340 }
12341 }
12342
12343 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12344 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12345 val = "no";
12346 }
12347 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12348
12349 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12350 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12351 ast_debug(1, "found dialout context: %s\n", dialcontext);
12352 } else {
12353 dialcontext[0] = '\0';
12354 }
12355
12356 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12357 ast_copy_string(callcontext, val, sizeof(callcontext));
12358 ast_debug(1, "found callback context: %s\n", callcontext);
12359 } else {
12360 callcontext[0] = '\0';
12361 }
12362
12363 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12364 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12365 ast_debug(1, "found operator context: %s\n", exitcontext);
12366 } else {
12367 exitcontext[0] = '\0';
12368 }
12369
12370
12371 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12372 ast_copy_string(vm_password, val, sizeof(vm_password));
12373 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12374 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12375 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12376 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12377 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12378 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12379 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12380 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12381 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12382 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12383 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12384 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12385 }
12386 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12387 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12388 }
12389
12390 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12391 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12392 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12393 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12394 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12395 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12396 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12397 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12398 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12399 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12400
12401 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12402 val = "no";
12403 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12404
12405 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12406 val = "voicemail.conf";
12407 }
12408 if (!(strcmp(val, "spooldir"))) {
12409 passwordlocation = OPT_PWLOC_SPOOLDIR;
12410 } else {
12411 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12412 }
12413
12414 poll_freq = DEFAULT_POLL_FREQ;
12415 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12416 if (sscanf(val, "%30u", &poll_freq) != 1) {
12417 poll_freq = DEFAULT_POLL_FREQ;
12418 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12419 }
12420 }
12421
12422 poll_mailboxes = 0;
12423 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12424 poll_mailboxes = ast_true(val);
12425
12426 memset(fromstring, 0, sizeof(fromstring));
12427 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12428 strcpy(charset, "ISO-8859-1");
12429 if (emailbody) {
12430 ast_free(emailbody);
12431 emailbody = NULL;
12432 }
12433 if (emailsubject) {
12434 ast_free(emailsubject);
12435 emailsubject = NULL;
12436 }
12437 if (pagerbody) {
12438 ast_free(pagerbody);
12439 pagerbody = NULL;
12440 }
12441 if (pagersubject) {
12442 ast_free(pagersubject);
12443 pagersubject = NULL;
12444 }
12445 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12446 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12447 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12448 ast_copy_string(fromstring, val, sizeof(fromstring));
12449 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12450 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12451 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12452 ast_copy_string(charset, val, sizeof(charset));
12453 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12454 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12455 for (x = 0; x < 4; x++) {
12456 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12457 }
12458 }
12459 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12460 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12461 for (x = 0; x < 4; x++) {
12462 memcpy(&adsisec[x], &tmpadsi[x], 1);
12463 }
12464 }
12465 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12466 if (atoi(val)) {
12467 adsiver = atoi(val);
12468 }
12469 }
12470 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12471 ast_copy_string(zonetag, val, sizeof(zonetag));
12472 }
12473 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12474 ast_copy_string(locale, val, sizeof(locale));
12475 }
12476 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12477 emailsubject = ast_strdup(substitute_escapes(val));
12478 }
12479 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12480 emailbody = ast_strdup(substitute_escapes(val));
12481 }
12482 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12483 pagersubject = ast_strdup(substitute_escapes(val));
12484 }
12485 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12486 pagerbody = ast_strdup(substitute_escapes(val));
12487 }
12488
12489
12490 if (ucfg) {
12491 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12492 if (!strcasecmp(cat, "general")) {
12493 continue;
12494 }
12495 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12496 continue;
12497 if ((current = find_or_create(userscontext, cat))) {
12498 populate_defaults(current);
12499 apply_options_full(current, ast_variable_browse(ucfg, cat));
12500 ast_copy_string(current->context, userscontext, sizeof(current->context));
12501 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12502 current->passwordlocation = OPT_PWLOC_USERSCONF;
12503 }
12504
12505 switch (current->passwordlocation) {
12506 case OPT_PWLOC_SPOOLDIR:
12507 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12508 read_password_from_file(secretfn, current->password, sizeof(current->password));
12509 }
12510 }
12511 }
12512 }
12513
12514
12515 cat = ast_category_browse(cfg, NULL);
12516 while (cat) {
12517 if (strcasecmp(cat, "general")) {
12518 var = ast_variable_browse(cfg, cat);
12519 if (strcasecmp(cat, "zonemessages")) {
12520
12521 while (var) {
12522 append_mailbox(cat, var->name, var->value);
12523 var = var->next;
12524 }
12525 } else {
12526
12527 while (var) {
12528 struct vm_zone *z;
12529 if ((z = ast_malloc(sizeof(*z)))) {
12530 char *msg_format, *tzone;
12531 msg_format = ast_strdupa(var->value);
12532 tzone = strsep(&msg_format, "|,");
12533 if (msg_format) {
12534 ast_copy_string(z->name, var->name, sizeof(z->name));
12535 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12536 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12537 AST_LIST_LOCK(&zones);
12538 AST_LIST_INSERT_HEAD(&zones, z, list);
12539 AST_LIST_UNLOCK(&zones);
12540 } else {
12541 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12542 ast_free(z);
12543 }
12544 } else {
12545 AST_LIST_UNLOCK(&users);
12546 return -1;
12547 }
12548 var = var->next;
12549 }
12550 }
12551 }
12552 cat = ast_category_browse(cfg, cat);
12553 }
12554
12555 AST_LIST_UNLOCK(&users);
12556
12557 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12558 start_poll_thread();
12559 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12560 stop_poll_thread();;
12561
12562 return 0;
12563 } else {
12564 AST_LIST_UNLOCK(&users);
12565 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12566 return 0;
12567 }
12568 }
12569
12570 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12571 {
12572 int res = -1;
12573 char dir[PATH_MAX];
12574 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12575 ast_debug(2, "About to try retrieving name file %s\n", dir);
12576 RETRIEVE(dir, -1, mailbox, context);
12577 if (ast_fileexists(dir, NULL, NULL)) {
12578 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12579 }
12580 DISPOSE(dir, -1);
12581 return res;
12582 }
12583
12584 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12585 struct ast_config *pwconf;
12586 struct ast_flags config_flags = { 0 };
12587
12588 pwconf = ast_config_load(secretfn, config_flags);
12589 if (valid_config(pwconf)) {
12590 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12591 if (val) {
12592 ast_copy_string(password, val, passwordlen);
12593 ast_config_destroy(pwconf);
12594 return;
12595 }
12596 ast_config_destroy(pwconf);
12597 }
12598 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12599 }
12600
12601 static int write_password_to_file(const char *secretfn, const char *password) {
12602 struct ast_config *conf;
12603 struct ast_category *cat;
12604 struct ast_variable *var;
12605 int res = -1;
12606
12607 if (!(conf = ast_config_new())) {
12608 ast_log(LOG_ERROR, "Error creating new config structure\n");
12609 return res;
12610 }
12611 if (!(cat = ast_category_new("general", "", 1))) {
12612 ast_log(LOG_ERROR, "Error creating new category structure\n");
12613 ast_config_destroy(conf);
12614 return res;
12615 }
12616 if (!(var = ast_variable_new("password", password, ""))) {
12617 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12618 ast_config_destroy(conf);
12619 ast_category_destroy(cat);
12620 return res;
12621 }
12622 ast_category_append(conf, cat);
12623 ast_variable_append(cat, var);
12624 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12625 res = 0;
12626 } else {
12627 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12628 }
12629
12630 ast_config_destroy(conf);
12631 return res;
12632 }
12633
12634 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12635 {
12636 char *context;
12637 char *args_copy;
12638 int res;
12639
12640 if (ast_strlen_zero(data)) {
12641 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12642 return -1;
12643 }
12644
12645 args_copy = ast_strdupa(data);
12646 if ((context = strchr(args_copy, '@'))) {
12647 *context++ = '\0';
12648 } else {
12649 context = "default";
12650 }
12651
12652 if ((res = sayname(chan, args_copy, context) < 0)) {
12653 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12654 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12655 if (!res) {
12656 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12657 }
12658 }
12659
12660 return res;
12661 }
12662
12663 #ifdef TEST_FRAMEWORK
12664 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12665 {
12666 return 0;
12667 }
12668
12669 static struct ast_frame *fake_read(struct ast_channel *ast)
12670 {
12671 return &ast_null_frame;
12672 }
12673
12674 AST_TEST_DEFINE(test_voicemail_vmsayname)
12675 {
12676 char dir[PATH_MAX];
12677 char dir2[PATH_MAX];
12678 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12679 static const char TEST_EXTENSION[] = "1234";
12680
12681 struct ast_channel *test_channel1 = NULL;
12682 int res = -1;
12683
12684 static const struct ast_channel_tech fake_tech = {
12685 .write = fake_write,
12686 .read = fake_read,
12687 };
12688
12689 switch (cmd) {
12690 case TEST_INIT:
12691 info->name = "vmsayname_exec";
12692 info->category = "/apps/app_voicemail/";
12693 info->summary = "Vmsayname unit test";
12694 info->description =
12695 "This tests passing various parameters to vmsayname";
12696 return AST_TEST_NOT_RUN;
12697 case TEST_EXECUTE:
12698 break;
12699 }
12700
12701 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12702 NULL, NULL, 0, 0, "TestChannel1"))) {
12703 goto exit_vmsayname_test;
12704 }
12705
12706
12707 test_channel1->nativeformats = AST_FORMAT_GSM;
12708 test_channel1->writeformat = AST_FORMAT_GSM;
12709 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12710 test_channel1->readformat = AST_FORMAT_GSM;
12711 test_channel1->rawreadformat = AST_FORMAT_GSM;
12712 test_channel1->tech = &fake_tech;
12713
12714 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12715 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12716 if (!(res = vmsayname_exec(test_channel1, dir))) {
12717 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12718 if (ast_fileexists(dir, NULL, NULL)) {
12719 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12720 res = -1;
12721 goto exit_vmsayname_test;
12722 } else {
12723
12724 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12725 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12726 goto exit_vmsayname_test;
12727 }
12728 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12729 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12730
12731 if ((res = symlink(dir, dir2))) {
12732 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12733 goto exit_vmsayname_test;
12734 }
12735 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12736 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12737 res = vmsayname_exec(test_channel1, dir);
12738
12739
12740 unlink(dir2);
12741 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12742 rmdir(dir2);
12743 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12744 rmdir(dir2);
12745 }
12746 }
12747
12748 exit_vmsayname_test:
12749
12750 if (test_channel1) {
12751 ast_hangup(test_channel1);
12752 }
12753
12754 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12755 }
12756
12757 AST_TEST_DEFINE(test_voicemail_msgcount)
12758 {
12759 int i, j, res = AST_TEST_PASS, syserr;
12760 struct ast_vm_user *vmu;
12761 struct ast_vm_user svm;
12762 struct vm_state vms;
12763 #ifdef IMAP_STORAGE
12764 struct ast_channel *chan = NULL;
12765 #endif
12766 struct {
12767 char dir[256];
12768 char file[256];
12769 char txtfile[256];
12770 } tmp[3];
12771 char syscmd[256];
12772 const char origweasels[] = "tt-weasels";
12773 const char testcontext[] = "test";
12774 const char testmailbox[] = "00000000";
12775 const char testspec[] = "00000000@test";
12776 FILE *txt;
12777 int new, old, urgent;
12778 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12779 const int folder2mbox[3] = { 1, 11, 0 };
12780 const int expected_results[3][12] = {
12781
12782 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12783 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12784 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12785 };
12786
12787 switch (cmd) {
12788 case TEST_INIT:
12789 info->name = "test_voicemail_msgcount";
12790 info->category = "/apps/app_voicemail/";
12791 info->summary = "Test Voicemail status checks";
12792 info->description =
12793 "Verify that message counts are correct when retrieved through the public API";
12794 return AST_TEST_NOT_RUN;
12795 case TEST_EXECUTE:
12796 break;
12797 }
12798
12799
12800 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12801 if ((syserr = ast_safe_system(syscmd))) {
12802 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12803 syserr > 0 ? strerror(syserr) : "unable to fork()");
12804 return AST_TEST_FAIL;
12805 }
12806
12807 #ifdef IMAP_STORAGE
12808 if (!(chan = ast_dummy_channel_alloc())) {
12809 ast_test_status_update(test, "Unable to create dummy channel\n");
12810 return AST_TEST_FAIL;
12811 }
12812 #endif
12813
12814 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12815 !(vmu = find_or_create(testcontext, testmailbox))) {
12816 ast_test_status_update(test, "Cannot create vmu structure\n");
12817 ast_unreplace_sigchld();
12818 #ifdef IMAP_STORAGE
12819 chan = ast_channel_unref(chan);
12820 #endif
12821 return AST_TEST_FAIL;
12822 }
12823
12824 populate_defaults(vmu);
12825 memset(&vms, 0, sizeof(vms));
12826
12827
12828 for (i = 0; i < 3; i++) {
12829 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12830 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12831 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12832
12833 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12834 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12835 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12836 if ((syserr = ast_safe_system(syscmd))) {
12837 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12838 syserr > 0 ? strerror(syserr) : "unable to fork()");
12839 ast_unreplace_sigchld();
12840 #ifdef IMAP_STORAGE
12841 chan = ast_channel_unref(chan);
12842 #endif
12843 return AST_TEST_FAIL;
12844 }
12845 }
12846
12847 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12848 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12849 fclose(txt);
12850 } else {
12851 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12852 res = AST_TEST_FAIL;
12853 break;
12854 }
12855 open_mailbox(&vms, vmu, folder2mbox[i]);
12856 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12857
12858
12859 for (j = 0; j < 3; j++) {
12860
12861 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12862 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12863 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12864 res = AST_TEST_FAIL;
12865 }
12866 }
12867
12868 new = old = urgent = 0;
12869 if (ast_app_inboxcount(testspec, &new, &old)) {
12870 ast_test_status_update(test, "inboxcount returned failure\n");
12871 res = AST_TEST_FAIL;
12872 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12873 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12874 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12875 res = AST_TEST_FAIL;
12876 }
12877
12878 new = old = urgent = 0;
12879 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12880 ast_test_status_update(test, "inboxcount2 returned failure\n");
12881 res = AST_TEST_FAIL;
12882 } else if (old != expected_results[i][6 + 0] ||
12883 urgent != expected_results[i][6 + 1] ||
12884 new != expected_results[i][6 + 2] ) {
12885 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12886 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12887 res = AST_TEST_FAIL;
12888 }
12889
12890 new = old = urgent = 0;
12891 for (j = 0; j < 3; j++) {
12892 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12893 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12894 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12895 res = AST_TEST_FAIL;
12896 }
12897 }
12898 }
12899
12900 for (i = 0; i < 3; i++) {
12901
12902
12903
12904 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12905 DISPOSE(tmp[i].dir, 0);
12906 }
12907
12908 if (vms.deleted) {
12909 ast_free(vms.deleted);
12910 }
12911 if (vms.heard) {
12912 ast_free(vms.heard);
12913 }
12914
12915 #ifdef IMAP_STORAGE
12916 chan = ast_channel_unref(chan);
12917 #endif
12918
12919
12920 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12921 if ((syserr = ast_safe_system(syscmd))) {
12922 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12923 syserr > 0 ? strerror(syserr) : "unable to fork()");
12924 }
12925
12926 return res;
12927 }
12928
12929 AST_TEST_DEFINE(test_voicemail_notify_endl)
12930 {
12931 int res = AST_TEST_PASS;
12932 char testcontext[] = "test";
12933 char testmailbox[] = "00000000";
12934 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12935 char attach[256], attach2[256];
12936 char buf[256] = "";
12937 struct ast_channel *chan = NULL;
12938 struct ast_vm_user *vmu, vmus = {
12939 .flags = 0,
12940 };
12941 FILE *file;
12942 struct {
12943 char *name;
12944 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12945 void *location;
12946 union {
12947 int intval;
12948 char *strval;
12949 } u;
12950 } test_items[] = {
12951 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12952 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12953 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12954 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12955 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12956 { "attach2", STRPTR, attach2, .u.strval = "" },
12957 { "attach", STRPTR, attach, .u.strval = "" },
12958 };
12959 int which;
12960
12961 switch (cmd) {
12962 case TEST_INIT:
12963 info->name = "test_voicemail_notify_endl";
12964 info->category = "/apps/app_voicemail/";
12965 info->summary = "Test Voicemail notification end-of-line";
12966 info->description =
12967 "Verify that notification emails use a consistent end-of-line character";
12968 return AST_TEST_NOT_RUN;
12969 case TEST_EXECUTE:
12970 break;
12971 }
12972
12973 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12974 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12975
12976 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12977 !(vmu = find_or_create(testcontext, testmailbox))) {
12978 ast_test_status_update(test, "Cannot create vmu structure\n");
12979 return AST_TEST_NOT_RUN;
12980 }
12981
12982 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12983 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12984 return AST_TEST_NOT_RUN;
12985 }
12986
12987 populate_defaults(vmu);
12988 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12989 #ifdef IMAP_STORAGE
12990
12991 #endif
12992
12993 file = tmpfile();
12994 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12995
12996 rewind(file);
12997 if (ftruncate(fileno(file), 0)) {
12998 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12999 res = AST_TEST_FAIL;
13000 break;
13001 }
13002
13003
13004 if (test_items[which].type == INT) {
13005 *((int *) test_items[which].location) = test_items[which].u.intval;
13006 } else if (test_items[which].type == FLAGVAL) {
13007 if (ast_test_flag(vmu, test_items[which].u.intval)) {
13008 ast_clear_flag(vmu, test_items[which].u.intval);
13009 } else {
13010 ast_set_flag(vmu, test_items[which].u.intval);
13011 }
13012 } else if (test_items[which].type == STATIC) {
13013 strcpy(test_items[which].location, test_items[which].u.strval);
13014 } else if (test_items[which].type == STRPTR) {
13015 test_items[which].location = test_items[which].u.strval;
13016 }
13017
13018 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13019 rewind(file);
13020 while (fgets(buf, sizeof(buf), file)) {
13021 if (
13022 #ifdef IMAP_STORAGE
13023 buf[strlen(buf) - 2] != '\r'
13024 #else
13025 buf[strlen(buf) - 2] == '\r'
13026 #endif
13027 || buf[strlen(buf) - 1] != '\n') {
13028 res = AST_TEST_FAIL;
13029 }
13030 }
13031 }
13032 fclose(file);
13033 return res;
13034 }
13035
13036 AST_TEST_DEFINE(test_voicemail_load_config)
13037 {
13038 int res = AST_TEST_PASS;
13039 struct ast_vm_user *vmu;
13040 struct ast_config *cfg;
13041 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13042 int fd;
13043 FILE *file;
13044 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13045
13046 switch (cmd) {
13047 case TEST_INIT:
13048 info->name = "test_voicemail_load_config";
13049 info->category = "/apps/app_voicemail/";
13050 info->summary = "Test loading Voicemail config";
13051 info->description =
13052 "Verify that configuration is loaded consistently. "
13053 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13054 "some options were loaded after the mailboxes were instantiated, causing "
13055 "those options not to be set correctly.";
13056 return AST_TEST_NOT_RUN;
13057 case TEST_EXECUTE:
13058 break;
13059 }
13060
13061
13062 if ((fd = mkstemp(config_filename)) < 0) {
13063 return AST_TEST_FAIL;
13064 }
13065 if (!(file = fdopen(fd, "w"))) {
13066 close(fd);
13067 unlink(config_filename);
13068 return AST_TEST_FAIL;
13069 }
13070 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13071 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13072 fputs("00000002 => 9999,Mrs. Test\n", file);
13073 fclose(file);
13074
13075 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13076 res = AST_TEST_FAIL;
13077 goto cleanup;
13078 }
13079
13080 load_config_from_memory(1, cfg, NULL);
13081 ast_config_destroy(cfg);
13082
13083 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13084 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13085 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13086
13087 AST_LIST_LOCK(&users);
13088 AST_LIST_TRAVERSE(&users, vmu, list) {
13089 if (!strcmp(vmu->mailbox, "00000001")) {
13090 if (0);
13091 CHECK(vmu, callback, "othercontext")
13092 CHECK(vmu, locale, "nl_NL.UTF-8")
13093 CHECK(vmu, zonetag, "central")
13094 } else if (!strcmp(vmu->mailbox, "00000002")) {
13095 if (0);
13096 CHECK(vmu, callback, "somecontext")
13097 CHECK(vmu, locale, "de_DE.UTF-8")
13098 CHECK(vmu, zonetag, "european")
13099 }
13100 }
13101 AST_LIST_UNLOCK(&users);
13102
13103 #undef CHECK
13104
13105
13106 load_config(1);
13107
13108 cleanup:
13109 unlink(config_filename);
13110 return res;
13111 }
13112
13113 #endif
13114
13115 static int reload(void)
13116 {
13117 return load_config(1);
13118 }
13119
13120 static int unload_module(void)
13121 {
13122 int res;
13123
13124 res = ast_unregister_application(app);
13125 res |= ast_unregister_application(app2);
13126 res |= ast_unregister_application(app3);
13127 res |= ast_unregister_application(app4);
13128 res |= ast_unregister_application(sayname_app);
13129 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13130 res |= ast_manager_unregister("VoicemailUsersList");
13131 res |= ast_data_unregister(NULL);
13132 #ifdef TEST_FRAMEWORK
13133 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13134 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13135 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13136 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13137 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13138 #endif
13139 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13140 ast_uninstall_vm_functions();
13141 ao2_ref(inprocess_container, -1);
13142
13143 if (poll_thread != AST_PTHREADT_NULL)
13144 stop_poll_thread();
13145
13146 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13147 ast_unload_realtime("voicemail");
13148 ast_unload_realtime("voicemail_data");
13149
13150 free_vm_users();
13151 free_vm_zones();
13152 return res;
13153 }
13154
13155 static int load_module(void)
13156 {
13157 int res;
13158 my_umask = umask(0);
13159 umask(my_umask);
13160
13161 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13162 return AST_MODULE_LOAD_DECLINE;
13163 }
13164
13165
13166 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13167
13168 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13169 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13170 }
13171
13172 if ((res = load_config(0)))
13173 return res;
13174
13175 res = ast_register_application_xml(app, vm_exec);
13176 res |= ast_register_application_xml(app2, vm_execmain);
13177 res |= ast_register_application_xml(app3, vm_box_exists);
13178 res |= ast_register_application_xml(app4, vmauthenticate);
13179 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13180 res |= ast_custom_function_register(&mailbox_exists_acf);
13181 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13182 #ifdef TEST_FRAMEWORK
13183 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13184 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13185 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13186 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13187 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13188 #endif
13189
13190 if (res)
13191 return res;
13192
13193 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13194 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13195
13196 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13197 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13198 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13199
13200 return res;
13201 }
13202
13203 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13204 {
13205 int cmd = 0;
13206 char destination[80] = "";
13207 int retries = 0;
13208
13209 if (!num) {
13210 ast_verb(3, "Destination number will be entered manually\n");
13211 while (retries < 3 && cmd != 't') {
13212 destination[1] = '\0';
13213 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13214 if (!cmd)
13215 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13216 if (!cmd)
13217 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13218 if (!cmd) {
13219 cmd = ast_waitfordigit(chan, 6000);
13220 if (cmd)
13221 destination[0] = cmd;
13222 }
13223 if (!cmd) {
13224 retries++;
13225 } else {
13226
13227 if (cmd < 0)
13228 return 0;
13229 if (cmd == '*') {
13230 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13231 return 0;
13232 }
13233 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13234 retries++;
13235 else
13236 cmd = 't';
13237 }
13238 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13239 }
13240 if (retries >= 3) {
13241 return 0;
13242 }
13243
13244 } else {
13245 if (option_verbose > 2)
13246 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13247 ast_copy_string(destination, num, sizeof(destination));
13248 }
13249
13250 if (!ast_strlen_zero(destination)) {
13251 if (destination[strlen(destination) -1 ] == '*')
13252 return 0;
13253 if (option_verbose > 2)
13254 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13255 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13256 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13257 chan->priority = 0;
13258 return 9;
13259 }
13260 return 0;
13261 }
13262
13263
13264
13265
13266
13267
13268
13269
13270
13271
13272
13273
13274
13275
13276 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)
13277 {
13278 int res = 0;
13279 char filename[PATH_MAX];
13280 struct ast_config *msg_cfg = NULL;
13281 const char *origtime, *context;
13282 char *name, *num;
13283 int retries = 0;
13284 char *cid;
13285 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13286
13287 vms->starting = 0;
13288
13289 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13290
13291
13292 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13293 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13294 msg_cfg = ast_config_load(filename, config_flags);
13295 DISPOSE(vms->curdir, vms->curmsg);
13296 if (!valid_config(msg_cfg)) {
13297 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13298 return 0;
13299 }
13300
13301 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13302 ast_config_destroy(msg_cfg);
13303 return 0;
13304 }
13305
13306 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13307
13308 context = ast_variable_retrieve(msg_cfg, "message", "context");
13309 if (!strncasecmp("macro", context, 5))
13310 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13311 switch (option) {
13312 case 3:
13313 if (!res)
13314 res = play_message_datetime(chan, vmu, origtime, filename);
13315 if (!res)
13316 res = play_message_callerid(chan, vms, cid, context, 0);
13317
13318 res = 't';
13319 break;
13320
13321 case 2:
13322
13323 if (ast_strlen_zero(cid))
13324 break;
13325
13326 ast_callerid_parse(cid, &name, &num);
13327 while ((res > -1) && (res != 't')) {
13328 switch (res) {
13329 case '1':
13330 if (num) {
13331
13332 res = dialout(chan, vmu, num, vmu->callback);
13333 if (res) {
13334 ast_config_destroy(msg_cfg);
13335 return 9;
13336 }
13337 } else {
13338 res = '2';
13339 }
13340 break;
13341
13342 case '2':
13343
13344 if (!ast_strlen_zero(vmu->dialout)) {
13345 res = dialout(chan, vmu, NULL, vmu->dialout);
13346 if (res) {
13347 ast_config_destroy(msg_cfg);
13348 return 9;
13349 }
13350 } else {
13351 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13352 res = ast_play_and_wait(chan, "vm-sorry");
13353 }
13354 ast_config_destroy(msg_cfg);
13355 return res;
13356 case '*':
13357 res = 't';
13358 break;
13359 case '3':
13360 case '4':
13361 case '5':
13362 case '6':
13363 case '7':
13364 case '8':
13365 case '9':
13366 case '0':
13367
13368 res = ast_play_and_wait(chan, "vm-sorry");
13369 retries++;
13370 break;
13371 default:
13372 if (num) {
13373 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13374 res = ast_play_and_wait(chan, "vm-num-i-have");
13375 if (!res)
13376 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13377 if (!res)
13378 res = ast_play_and_wait(chan, "vm-tocallnum");
13379
13380 if (!ast_strlen_zero(vmu->dialout)) {
13381 if (!res)
13382 res = ast_play_and_wait(chan, "vm-calldiffnum");
13383 }
13384 } else {
13385 res = ast_play_and_wait(chan, "vm-nonumber");
13386 if (!ast_strlen_zero(vmu->dialout)) {
13387 if (!res)
13388 res = ast_play_and_wait(chan, "vm-toenternumber");
13389 }
13390 }
13391 if (!res) {
13392 res = ast_play_and_wait(chan, "vm-star-cancel");
13393 }
13394 if (!res) {
13395 res = ast_waitfordigit(chan, 6000);
13396 }
13397 if (!res) {
13398 retries++;
13399 if (retries > 3) {
13400 res = 't';
13401 }
13402 }
13403 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13404 break;
13405
13406 }
13407 if (res == 't')
13408 res = 0;
13409 else if (res == '*')
13410 res = -1;
13411 }
13412 break;
13413
13414 case 1:
13415
13416 if (ast_strlen_zero(cid))
13417 break;
13418
13419 ast_callerid_parse(cid, &name, &num);
13420 if (!num) {
13421 ast_verb(3, "No CID number available, no reply sent\n");
13422 if (!res)
13423 res = ast_play_and_wait(chan, "vm-nonumber");
13424 ast_config_destroy(msg_cfg);
13425 return res;
13426 } else {
13427 struct ast_vm_user vmu2;
13428 if (find_user(&vmu2, vmu->context, num)) {
13429 struct leave_vm_options leave_options;
13430 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13431 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13432
13433 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13434
13435 memset(&leave_options, 0, sizeof(leave_options));
13436 leave_options.record_gain = record_gain;
13437 res = leave_voicemail(chan, mailbox, &leave_options);
13438 if (!res)
13439 res = 't';
13440 ast_config_destroy(msg_cfg);
13441 return res;
13442 } else {
13443
13444 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13445 ast_play_and_wait(chan, "vm-nobox");
13446 res = 't';
13447 ast_config_destroy(msg_cfg);
13448 return res;
13449 }
13450 }
13451 res = 0;
13452
13453 break;
13454 }
13455
13456 ast_config_destroy(msg_cfg);
13457
13458 #ifndef IMAP_STORAGE
13459 if (!res) {
13460 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13461 vms->heard[msg] = 1;
13462 res = wait_file(chan, vms, vms->fn);
13463 }
13464 #endif
13465 return res;
13466 }
13467
13468 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13469 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13470 signed char record_gain, struct vm_state *vms, char *flag)
13471 {
13472
13473 int res = 0;
13474 int cmd = 0;
13475 int max_attempts = 3;
13476 int attempts = 0;
13477 int recorded = 0;
13478 int msg_exists = 0;
13479 signed char zero_gain = 0;
13480 char tempfile[PATH_MAX];
13481 char *acceptdtmf = "#";
13482 char *canceldtmf = "";
13483 int canceleddtmf = 0;
13484
13485
13486
13487
13488 if (duration == NULL) {
13489 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13490 return -1;
13491 }
13492
13493 if (!outsidecaller)
13494 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13495 else
13496 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13497
13498 cmd = '3';
13499
13500 while ((cmd >= 0) && (cmd != 't')) {
13501 switch (cmd) {
13502 case '1':
13503 if (!msg_exists) {
13504
13505 cmd = '3';
13506 break;
13507 } else {
13508
13509 ast_verb(3, "Saving message as is\n");
13510 if (!outsidecaller)
13511 ast_filerename(tempfile, recordfile, NULL);
13512 ast_stream_and_wait(chan, "vm-msgsaved", "");
13513 if (!outsidecaller) {
13514
13515 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13516 DISPOSE(recordfile, -1);
13517 }
13518 cmd = 't';
13519 return res;
13520 }
13521 case '2':
13522
13523 ast_verb(3, "Reviewing the message\n");
13524 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13525 break;
13526 case '3':
13527 msg_exists = 0;
13528
13529 if (recorded == 1)
13530 ast_verb(3, "Re-recording the message\n");
13531 else
13532 ast_verb(3, "Recording the message\n");
13533
13534 if (recorded && outsidecaller) {
13535 cmd = ast_play_and_wait(chan, INTRO);
13536 cmd = ast_play_and_wait(chan, "beep");
13537 }
13538 recorded = 1;
13539
13540 if (record_gain)
13541 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13542 if (ast_test_flag(vmu, VM_OPERATOR))
13543 canceldtmf = "0";
13544 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13545 if (strchr(canceldtmf, cmd)) {
13546
13547 canceleddtmf = 1;
13548 }
13549 if (record_gain)
13550 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13551 if (cmd == -1) {
13552
13553 if (!outsidecaller) {
13554
13555 ast_filedelete(tempfile, NULL);
13556 }
13557 return cmd;
13558 }
13559 if (cmd == '0') {
13560 break;
13561 } else if (cmd == '*') {
13562 break;
13563 #if 0
13564 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13565
13566 ast_verb(3, "Message too short\n");
13567 cmd = ast_play_and_wait(chan, "vm-tooshort");
13568 cmd = ast_filedelete(tempfile, NULL);
13569 break;
13570 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13571
13572 ast_verb(3, "Nothing recorded\n");
13573 cmd = ast_filedelete(tempfile, NULL);
13574 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13575 if (!cmd)
13576 cmd = ast_play_and_wait(chan, "vm-speakup");
13577 break;
13578 #endif
13579 } else {
13580
13581 msg_exists = 1;
13582 cmd = 0;
13583 }
13584 break;
13585 case '4':
13586 if (outsidecaller) {
13587
13588 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13589 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13590 res = ast_play_and_wait(chan, "vm-marked-urgent");
13591 strcpy(flag, "Urgent");
13592 } else if (flag) {
13593 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13594 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13595 strcpy(flag, "");
13596 } else {
13597 ast_play_and_wait(chan, "vm-sorry");
13598 }
13599 cmd = 0;
13600 } else {
13601 cmd = ast_play_and_wait(chan, "vm-sorry");
13602 }
13603 break;
13604 case '5':
13605 case '6':
13606 case '7':
13607 case '8':
13608 case '9':
13609 case '*':
13610 case '#':
13611 cmd = ast_play_and_wait(chan, "vm-sorry");
13612 break;
13613 #if 0
13614
13615
13616 case '*':
13617
13618 cmd = ast_play_and_wait(chan, "vm-deleted");
13619 cmd = ast_filedelete(tempfile, NULL);
13620 if (outsidecaller) {
13621 res = vm_exec(chan, NULL);
13622 return res;
13623 }
13624 else
13625 return 1;
13626 #endif
13627 case '0':
13628 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13629 cmd = ast_play_and_wait(chan, "vm-sorry");
13630 break;
13631 }
13632 if (msg_exists || recorded) {
13633 cmd = ast_play_and_wait(chan, "vm-saveoper");
13634 if (!cmd)
13635 cmd = ast_waitfordigit(chan, 3000);
13636 if (cmd == '1') {
13637 ast_filerename(tempfile, recordfile, NULL);
13638 ast_play_and_wait(chan, "vm-msgsaved");
13639 cmd = '0';
13640 } else if (cmd == '4') {
13641 if (flag) {
13642 ast_play_and_wait(chan, "vm-marked-urgent");
13643 strcpy(flag, "Urgent");
13644 }
13645 ast_play_and_wait(chan, "vm-msgsaved");
13646 cmd = '0';
13647 } else {
13648 ast_play_and_wait(chan, "vm-deleted");
13649 DELETE(tempfile, -1, tempfile, vmu);
13650 cmd = '0';
13651 }
13652 }
13653 return cmd;
13654 default:
13655
13656
13657
13658 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13659 return cmd;
13660 if (msg_exists) {
13661 cmd = ast_play_and_wait(chan, "vm-review");
13662 if (!cmd && outsidecaller) {
13663 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13664 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13665 } else if (flag) {
13666 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13667 }
13668 }
13669 } else {
13670 cmd = ast_play_and_wait(chan, "vm-torerecord");
13671 if (!cmd)
13672 cmd = ast_waitfordigit(chan, 600);
13673 }
13674
13675 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13676 cmd = ast_play_and_wait(chan, "vm-reachoper");
13677 if (!cmd)
13678 cmd = ast_waitfordigit(chan, 600);
13679 }
13680 #if 0
13681 if (!cmd)
13682 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13683 #endif
13684 if (!cmd)
13685 cmd = ast_waitfordigit(chan, 6000);
13686 if (!cmd) {
13687 attempts++;
13688 }
13689 if (attempts > max_attempts) {
13690 cmd = 't';
13691 }
13692 }
13693 }
13694 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13695
13696 ast_filedelete(tempfile, NULL);
13697 }
13698
13699 if (cmd != 't' && outsidecaller)
13700 ast_play_and_wait(chan, "vm-goodbye");
13701
13702 return cmd;
13703 }
13704
13705
13706
13707
13708
13709 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13710 .load = load_module,
13711 .unload = unload_module,
13712 .reload = reload,
13713 .nonoptreq = "res_adsi,res_smdi",
13714 );