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 #include "asterisk.h"
00054
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 165767 $")
00056
00057 #include <stdlib.h>
00058 #include <errno.h>
00059 #include <unistd.h>
00060 #include <string.h>
00061 #include <stdlib.h>
00062 #include <stdio.h>
00063 #include <sys/time.h>
00064 #include <sys/stat.h>
00065 #include <sys/types.h>
00066 #include <sys/mman.h>
00067 #include <time.h>
00068 #include <dirent.h>
00069 #ifdef IMAP_STORAGE
00070 #include <ctype.h>
00071 #include <signal.h>
00072 #include <pwd.h>
00073 #ifdef USE_SYSTEM_IMAP
00074 #include <imap/c-client.h>
00075 #include <imap/imap4r1.h>
00076 #include <imap/linkage.h>
00077 #elif defined (USE_SYSTEM_CCLIENT)
00078 #include <c-client/c-client.h>
00079 #include <c-client/imap4r1.h>
00080 #include <c-client/linkage.h>
00081 #else
00082 #include "c-client.h"
00083 #include "imap4r1.h"
00084 #include "linkage.h"
00085 #endif
00086 #endif
00087 #include "asterisk/lock.h"
00088 #include "asterisk/file.h"
00089 #include "asterisk/logger.h"
00090 #include "asterisk/channel.h"
00091 #include "asterisk/pbx.h"
00092 #include "asterisk/options.h"
00093 #include "asterisk/config.h"
00094 #include "asterisk/say.h"
00095 #include "asterisk/module.h"
00096 #include "asterisk/adsi.h"
00097 #include "asterisk/app.h"
00098 #include "asterisk/manager.h"
00099 #include "asterisk/dsp.h"
00100 #include "asterisk/localtime.h"
00101 #include "asterisk/cli.h"
00102 #include "asterisk/utils.h"
00103 #include "asterisk/stringfields.h"
00104 #include "asterisk/smdi.h"
00105 #ifdef ODBC_STORAGE
00106 #include "asterisk/res_odbc.h"
00107 #endif
00108
00109 #ifdef IMAP_STORAGE
00110 AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
00111 static char imaptemp[1024];
00112 static char imapserver[48];
00113 static char imapport[8];
00114 static char imapflags[128];
00115 static char imapfolder[64];
00116 static char authuser[32];
00117 static char authpassword[42];
00118
00119 static int expungeonhangup = 1;
00120 static char delimiter = '\0';
00121 static const long DEFAULT_IMAP_TCP_TIMEOUT = 60L;
00122
00123 struct vm_state;
00124 struct ast_vm_user;
00125
00126 static int init_mailstream (struct vm_state *vms, int box);
00127 static void write_file (char *filename, char *buffer, unsigned long len);
00128
00129 static char *get_header_by_tag(char *header, char *tag);
00130 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu);
00131 static char *get_user_by_mailbox(char *mailbox);
00132 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
00133 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00134 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00135 static void vmstate_insert(struct vm_state *vms);
00136 static void vmstate_delete(struct vm_state *vms);
00137 static void set_update(MAILSTREAM * stream);
00138 static void init_vm_state(struct vm_state *vms);
00139 static void copy_msgArray(struct vm_state *dst, struct vm_state *src);
00140 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00141 static void get_mailbox_delimiter(MAILSTREAM *stream);
00142 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00143 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00144 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
00145 static void check_quota(struct vm_state *vms, char *mailbox);
00146 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
00147 struct vmstate {
00148 struct vm_state *vms;
00149 struct vmstate *next;
00150 };
00151 AST_MUTEX_DEFINE_STATIC(vmstate_lock);
00152 static struct vmstate *vmstates = NULL;
00153 #endif
00154
00155 #define SMDI_MWI_WAIT_TIMEOUT 1000
00156
00157 #define COMMAND_TIMEOUT 5000
00158
00159 #define VOICEMAIL_DIR_MODE 0777
00160 #define VOICEMAIL_FILE_MODE 0666
00161 #define CHUNKSIZE 65536
00162
00163 #define VOICEMAIL_CONFIG "voicemail.conf"
00164 #define ASTERISK_USERNAME "asterisk"
00165
00166
00167
00168 #define SENDMAIL "/usr/sbin/sendmail -t"
00169
00170 #define INTRO "vm-intro"
00171
00172 #define MAXMSG 100
00173 #ifndef IMAP_STORAGE
00174 #define MAXMSGLIMIT 9999
00175 #else
00176 #define MAXMSGLIMIT 255
00177 #endif
00178
00179 #define BASEMAXINLINE 256
00180 #define BASELINELEN 72
00181 #define BASEMAXINLINE 256
00182 #define eol "\r\n"
00183
00184 #define MAX_DATETIME_FORMAT 512
00185 #define MAX_NUM_CID_CONTEXTS 10
00186
00187 #define VM_REVIEW (1 << 0)
00188 #define VM_OPERATOR (1 << 1)
00189 #define VM_SAYCID (1 << 2)
00190 #define VM_SVMAIL (1 << 3)
00191 #define VM_ENVELOPE (1 << 4)
00192 #define VM_SAYDURATION (1 << 5)
00193 #define VM_SKIPAFTERCMD (1 << 6)
00194 #define VM_FORCENAME (1 << 7)
00195 #define VM_FORCEGREET (1 << 8)
00196 #define VM_PBXSKIP (1 << 9)
00197 #define VM_DIRECFORWARD (1 << 10)
00198 #define VM_ATTACH (1 << 11)
00199 #define VM_DELETE (1 << 12)
00200 #define VM_ALLOCED (1 << 13)
00201 #define VM_SEARCH (1 << 14)
00202 #define VM_TEMPGREETWARN (1 << 15)
00203 #define ERROR_LOCK_PATH -100
00204 #define ERROR_MAILBOX_FULL -200
00205
00206
00207 enum {
00208 OPT_SILENT = (1 << 0),
00209 OPT_BUSY_GREETING = (1 << 1),
00210 OPT_UNAVAIL_GREETING = (1 << 2),
00211 OPT_RECORDGAIN = (1 << 3),
00212 OPT_PREPEND_MAILBOX = (1 << 4),
00213 OPT_PRIORITY_JUMP = (1 << 5),
00214 OPT_AUTOPLAY = (1 << 6),
00215 } vm_option_flags;
00216
00217 enum {
00218 OPT_ARG_RECORDGAIN = 0,
00219 OPT_ARG_PLAYFOLDER = 1,
00220
00221 OPT_ARG_ARRAY_SIZE = 2,
00222 } vm_option_args;
00223
00224 AST_APP_OPTIONS(vm_app_options, {
00225 AST_APP_OPTION('s', OPT_SILENT),
00226 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00227 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00228 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00229 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00230 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00231 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00232 });
00233
00234 static int load_config(void);
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 struct baseio {
00323 int iocp;
00324 int iolen;
00325 int linelength;
00326 int ateof;
00327 unsigned char iobuf[BASEMAXINLINE];
00328 };
00329
00330
00331 struct ast_vm_user {
00332 char context[AST_MAX_CONTEXT];
00333 char mailbox[AST_MAX_EXTENSION];
00334 char password[80];
00335 char fullname[80];
00336 char email[80];
00337 char pager[80];
00338 char serveremail[80];
00339 char mailcmd[160];
00340 char language[MAX_LANGUAGE];
00341 char zonetag[80];
00342 char callback[80];
00343 char dialout[80];
00344 char uniqueid[80];
00345 char exit[80];
00346 char attachfmt[20];
00347 unsigned int flags;
00348 int saydurationm;
00349 int maxmsg;
00350 #ifdef IMAP_STORAGE
00351 char imapuser[80];
00352 char imappassword[80];
00353 #endif
00354 double volgain;
00355 AST_LIST_ENTRY(ast_vm_user) list;
00356 };
00357
00358 struct vm_zone {
00359 AST_LIST_ENTRY(vm_zone) list;
00360 char name[80];
00361 char timezone[80];
00362 char msg_format[512];
00363 };
00364
00365 struct vm_state {
00366 char curbox[80];
00367 char username[80];
00368 char context[80];
00369 char curdir[PATH_MAX];
00370 char vmbox[PATH_MAX];
00371 char fn[PATH_MAX];
00372 char fn2[PATH_MAX];
00373 int *deleted;
00374 int *heard;
00375 int curmsg;
00376 int lastmsg;
00377 int newmessages;
00378 int oldmessages;
00379 int starting;
00380 int repeats;
00381 #ifdef IMAP_STORAGE
00382 ast_mutex_t lock;
00383 int updated;
00384 long msgArray[256];
00385 MAILSTREAM *mailstream;
00386 int vmArrayIndex;
00387 char imapuser[80];
00388 int interactive;
00389 unsigned int quota_limit;
00390 unsigned int quota_usage;
00391 struct vm_state *persist_vms;
00392 #endif
00393 };
00394 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);
00395 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00396 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00397 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00398 signed char record_gain, struct vm_state *vms);
00399 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00400 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00401 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
00402 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00403 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00404 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00405 #endif
00406 static void apply_options(struct ast_vm_user *vmu, const char *options);
00407
00408 #ifdef ODBC_STORAGE
00409 static char odbc_database[80];
00410 static char odbc_table[80];
00411 #define RETRIEVE(a,b,c) retrieve_file(a,b)
00412 #define DISPOSE(a,b) remove_file(a,b)
00413 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00414 #define EXISTS(a,b,c,d) (message_exists(a,b))
00415 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00416 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00417 #define DELETE(a,b,c,d) (delete_file(a,b))
00418 #else
00419 #ifdef IMAP_STORAGE
00420 #define RETRIEVE(a,b,c) imap_retrieve_file(a,b,c)
00421 #define DISPOSE(a,b) remove_file(a,b)
00422 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00423 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00424 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00425 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00426 #define DELETE(a,b,c,d) (vm_imap_delete(b,d))
00427 #else
00428 #define RETRIEVE(a,b,c)
00429 #define DISPOSE(a,b)
00430 #define STORE(a,b,c,d,e,f,g,h,i)
00431 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00432 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00433 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00434 #define DELETE(a,b,c,d) (vm_delete(c))
00435 #endif
00436 #endif
00437
00438 static char VM_SPOOL_DIR[PATH_MAX];
00439
00440 static char ext_pass_cmd[128];
00441
00442 int my_umask;
00443
00444 #if ODBC_STORAGE
00445 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00446 #elif IMAP_STORAGE
00447 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00448 #else
00449 #define tdesc "Comedian Mail (Voicemail System)"
00450 #endif
00451
00452 static char userscontext[AST_MAX_EXTENSION] = "default";
00453
00454 static char *addesc = "Comedian Mail";
00455
00456 static char *synopsis_vm =
00457 "Leave a Voicemail message";
00458
00459 static char *descrip_vm =
00460 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
00461 "application allows the calling party to leave a message for the specified\n"
00462 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00463 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00464 "specified mailbox does not exist.\n"
00465 " The Voicemail application will exit if any of the following DTMF digits are\n"
00466 "received:\n"
00467 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00468 " * - Jump to the 'a' extension in the current dialplan context.\n"
00469 " This application will set the following channel variable upon completion:\n"
00470 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00471 " application. The possible values are:\n"
00472 " SUCCESS | USEREXIT | FAILED\n\n"
00473 " Options:\n"
00474 " b - Play the 'busy' greeting to the calling party.\n"
00475 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00476 " message. The units are whole-number decibels (dB).\n"
00477 " Only works on supported technologies, which is Zap only.\n"
00478 " s - Skip the playback of instructions for leaving a message to the\n"
00479 " calling party.\n"
00480 " u - Play the 'unavailable' greeting.\n"
00481 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
00482 " error occurs.\n";
00483
00484 static char *synopsis_vmain =
00485 "Check Voicemail messages";
00486
00487 static char *descrip_vmain =
00488 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
00489 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00490 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00491 "calling party will be prompted to enter one. If a context is not specified,\n"
00492 "the 'default' context will be used.\n\n"
00493 " Options:\n"
00494 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00495 " is entered by the caller.\n"
00496 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00497 " message. The units are whole-number decibels (dB).\n"
00498 " s - Skip checking the passcode for the mailbox.\n"
00499 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00500 " Defaults to INBOX\n";
00501
00502 static char *synopsis_vm_box_exists =
00503 "Check to see if Voicemail mailbox exists";
00504
00505 static char *descrip_vm_box_exists =
00506 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
00507 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00508 "will be used.\n"
00509 " This application will set the following channel variable upon completion:\n"
00510 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00511 " MailboxExists application. Possible values include:\n"
00512 " SUCCESS | FAILED\n\n"
00513 " Options:\n"
00514 " j - Jump to priority n+101 if the mailbox is found.\n";
00515
00516 static char *synopsis_vmauthenticate =
00517 "Authenticate with Voicemail passwords";
00518
00519 static char *descrip_vmauthenticate =
00520 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
00521 "same way as the Authenticate application, but the passwords are taken from\n"
00522 "voicemail.conf.\n"
00523 " If the mailbox is specified, only that mailbox's password will be considered\n"
00524 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00525 "be set with the authenticated mailbox.\n\n"
00526 " Options:\n"
00527 " s - Skip playing the initial prompts.\n";
00528
00529
00530 static char *app = "VoiceMail";
00531
00532
00533 static char *app2 = "VoiceMailMain";
00534
00535 static char *app3 = "MailboxExists";
00536 static char *app4 = "VMAuthenticate";
00537
00538 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00539 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00540 static char zonetag[80];
00541 static int maxsilence;
00542 static int maxmsg;
00543 static int silencethreshold = 128;
00544 static char serveremail[80];
00545 static char mailcmd[160];
00546 static char externnotify[160];
00547 static struct ast_smdi_interface *smdi_iface = NULL;
00548 static char vmfmts[80];
00549 static double volgain;
00550 static int vmminmessage;
00551 static int vmmaxmessage;
00552 static int maxgreet;
00553 static int skipms;
00554 static int maxlogins;
00555
00556 static struct ast_flags globalflags = {0};
00557
00558 static int saydurationminfo;
00559
00560 static char dialcontext[AST_MAX_CONTEXT];
00561 static char callcontext[AST_MAX_CONTEXT];
00562 static char exitcontext[AST_MAX_CONTEXT];
00563
00564 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00565
00566
00567 static char *emailbody = NULL;
00568 static char *emailsubject = NULL;
00569 static char *pagerbody = NULL;
00570 static char *pagersubject = NULL;
00571 static char fromstring[100];
00572 static char pagerfromstring[100];
00573 static char emailtitle[100];
00574 static char charset[32] = "ISO-8859-1";
00575
00576 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00577 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00578 static int adsiver = 1;
00579 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00580
00581
00582 static char *strip_control(const char *input, char *buf, size_t buflen)
00583 {
00584 char *bufptr = buf;
00585 for (; *input; input++) {
00586 if (*input < 32) {
00587 continue;
00588 }
00589 *bufptr++ = *input;
00590 if (bufptr == buf + buflen - 1) {
00591 break;
00592 }
00593 }
00594 *bufptr = '\0';
00595 return buf;
00596 }
00597
00598 static void populate_defaults(struct ast_vm_user *vmu)
00599 {
00600 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00601 if (saydurationminfo)
00602 vmu->saydurationm = saydurationminfo;
00603 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00604 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00605 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00606 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00607 if (maxmsg)
00608 vmu->maxmsg = maxmsg;
00609 vmu->volgain = volgain;
00610 }
00611
00612 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00613 {
00614 int x;
00615 if (!strcasecmp(var, "attach")) {
00616 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00617 } else if (!strcasecmp(var, "attachfmt")) {
00618 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00619 } else if (!strcasecmp(var, "serveremail")) {
00620 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00621 } else if (!strcasecmp(var, "language")) {
00622 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00623 } else if (!strcasecmp(var, "tz")) {
00624 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00625 #ifdef IMAP_STORAGE
00626 } else if (!strcasecmp(var, "imapuser")) {
00627 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00628 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00629 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00630 #endif
00631 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00632 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00633 } else if (!strcasecmp(var, "saycid")){
00634 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00635 } else if (!strcasecmp(var,"sendvoicemail")){
00636 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00637 } else if (!strcasecmp(var, "review")){
00638 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00639 } else if (!strcasecmp(var, "tempgreetwarn")){
00640 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00641 } else if (!strcasecmp(var, "operator")){
00642 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00643 } else if (!strcasecmp(var, "envelope")){
00644 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00645 } else if (!strcasecmp(var, "sayduration")){
00646 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00647 } else if (!strcasecmp(var, "saydurationm")){
00648 if (sscanf(value, "%d", &x) == 1) {
00649 vmu->saydurationm = x;
00650 } else {
00651 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00652 }
00653 } else if (!strcasecmp(var, "forcename")){
00654 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00655 } else if (!strcasecmp(var, "forcegreetings")){
00656 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00657 } else if (!strcasecmp(var, "callback")) {
00658 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00659 } else if (!strcasecmp(var, "dialout")) {
00660 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00661 } else if (!strcasecmp(var, "exitcontext")) {
00662 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00663 } else if (!strcasecmp(var, "maxmsg")) {
00664 vmu->maxmsg = atoi(value);
00665 if (vmu->maxmsg <= 0) {
00666 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
00667 vmu->maxmsg = MAXMSG;
00668 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00669 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00670 vmu->maxmsg = MAXMSGLIMIT;
00671 }
00672 } else if (!strcasecmp(var, "volgain")) {
00673 sscanf(value, "%lf", &vmu->volgain);
00674 } else if (!strcasecmp(var, "options")) {
00675 apply_options(vmu, value);
00676 }
00677 }
00678
00679 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00680 {
00681 int res;
00682 if (!ast_strlen_zero(vmu->uniqueid)) {
00683 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
00684 if (res > 0) {
00685 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00686 res = 0;
00687 } else if (!res) {
00688 res = -1;
00689 }
00690 return res;
00691 }
00692 return -1;
00693 }
00694
00695 static void apply_options(struct ast_vm_user *vmu, const char *options)
00696 {
00697 char *stringp;
00698 char *s;
00699 char *var, *value;
00700 stringp = ast_strdupa(options);
00701 while ((s = strsep(&stringp, "|"))) {
00702 value = s;
00703 if ((var = strsep(&value, "=")) && value) {
00704 apply_option(vmu, var, value);
00705 }
00706 }
00707 }
00708
00709 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00710 {
00711 struct ast_variable *tmp;
00712 tmp = var;
00713 while (tmp) {
00714 if (!strcasecmp(tmp->name, "vmsecret")) {
00715 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00716 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00717 if (ast_strlen_zero(retval->password))
00718 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00719 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00720 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00721 } else if (!strcasecmp(tmp->name, "pager")) {
00722 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00723 } else if (!strcasecmp(tmp->name, "email")) {
00724 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00725 } else if (!strcasecmp(tmp->name, "fullname")) {
00726 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00727 } else if (!strcasecmp(tmp->name, "context")) {
00728 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00729 #ifdef IMAP_STORAGE
00730 } else if (!strcasecmp(tmp->name, "imapuser")) {
00731 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00732 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
00733 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00734 #endif
00735 } else
00736 apply_option(retval, tmp->name, tmp->value);
00737 tmp = tmp->next;
00738 }
00739 }
00740
00741 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00742 {
00743 struct ast_variable *var;
00744 struct ast_vm_user *retval;
00745
00746 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00747 if (!ivm)
00748 ast_set_flag(retval, VM_ALLOCED);
00749 else
00750 memset(retval, 0, sizeof(*retval));
00751 if (mailbox)
00752 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00753 populate_defaults(retval);
00754 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00755 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00756 else
00757 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00758 if (var) {
00759 apply_options_full(retval, var);
00760 ast_variables_destroy(var);
00761 } else {
00762 if (!ivm)
00763 free(retval);
00764 retval = NULL;
00765 }
00766 }
00767 return retval;
00768 }
00769
00770 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00771 {
00772
00773 struct ast_vm_user *vmu=NULL, *cur;
00774 AST_LIST_LOCK(&users);
00775
00776 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00777 context = "default";
00778
00779 AST_LIST_TRAVERSE(&users, cur, list) {
00780 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00781 break;
00782 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00783 break;
00784 }
00785 if (cur) {
00786
00787 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00788 memcpy(vmu, cur, sizeof(*vmu));
00789 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00790 AST_LIST_NEXT(vmu, list) = NULL;
00791 }
00792 } else
00793 vmu = find_user_realtime(ivm, context, mailbox);
00794 AST_LIST_UNLOCK(&users);
00795 return vmu;
00796 }
00797
00798 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00799 {
00800
00801 struct ast_vm_user *cur;
00802 int res = -1;
00803 AST_LIST_LOCK(&users);
00804 AST_LIST_TRAVERSE(&users, cur, list) {
00805 if ((!context || !strcasecmp(context, cur->context)) &&
00806 (!strcasecmp(mailbox, cur->mailbox)))
00807 break;
00808 }
00809 if (cur) {
00810 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00811 res = 0;
00812 }
00813 AST_LIST_UNLOCK(&users);
00814 return res;
00815 }
00816
00817 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00818 {
00819 struct ast_config *cfg=NULL;
00820 struct ast_variable *var=NULL;
00821 struct ast_category *cat=NULL;
00822 char *category=NULL, *value=NULL, *new=NULL;
00823 const char *tmp=NULL;
00824
00825 if (!change_password_realtime(vmu, newpassword))
00826 return;
00827
00828
00829 if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
00830 while ((category = ast_category_browse(cfg, category))) {
00831 if (!strcasecmp(category, vmu->context)) {
00832 tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
00833 if (!tmp) {
00834 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00835 break;
00836 }
00837 value = strstr(tmp,",");
00838 if (!value) {
00839 ast_log(LOG_WARNING, "variable has bad format.\n");
00840 break;
00841 }
00842 new = alloca((strlen(value)+strlen(newpassword)+1));
00843 sprintf(new,"%s%s", newpassword, value);
00844 if (!(cat = ast_category_get(cfg, category))) {
00845 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00846 break;
00847 }
00848 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00849 }
00850 }
00851
00852 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00853 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00854 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
00855 }
00856 category = NULL;
00857 var = NULL;
00858
00859
00860 if ((cfg = ast_config_load_with_comments("users.conf"))) {
00861 if (option_debug > 3)
00862 ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
00863 while ((category = ast_category_browse(cfg, category))) {
00864 if (option_debug > 3)
00865 ast_log(LOG_DEBUG, "users.conf: %s\n", category);
00866 if (!strcasecmp(category, vmu->mailbox)) {
00867 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
00868 if (option_debug > 3)
00869 ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
00870 var = ast_variable_new("vmsecret", newpassword);
00871 }
00872 new = alloca(strlen(newpassword)+1);
00873 sprintf(new, "%s", newpassword);
00874 if (!(cat = ast_category_get(cfg, category))) {
00875 if (option_debug > 3)
00876 ast_log(LOG_DEBUG, "failed to get category!\n");
00877 break;
00878 }
00879 if (!var)
00880 ast_variable_update(cat, "vmsecret", new, NULL, 0);
00881 else
00882 ast_variable_append(cat, var);
00883 }
00884 }
00885
00886 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00887 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00888 config_text_file_save("users.conf", cfg, "AppVoicemail");
00889 }
00890 }
00891
00892 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
00893 {
00894 char buf[255];
00895 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
00896 if (!ast_safe_system(buf)) {
00897 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00898
00899 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00900 }
00901 }
00902
00903 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
00904 {
00905 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
00906 }
00907
00908 static int make_file(char *dest, const int len, const char *dir, const int num)
00909 {
00910 return snprintf(dest, len, "%s/msg%04d", dir, num);
00911 }
00912
00913
00914 static FILE *vm_mkftemp(char *template)
00915 {
00916 FILE *p = NULL;
00917 int pfd = mkstemp(template);
00918 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
00919 if (pfd > -1) {
00920 p = fdopen(pfd, "w+");
00921 if (!p) {
00922 close(pfd);
00923 pfd = -1;
00924 }
00925 }
00926 return p;
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
00938 {
00939 mode_t mode = VOICEMAIL_DIR_MODE;
00940
00941 if (!ast_strlen_zero(context)) {
00942 make_dir(dest, len, context, "", "");
00943 if (mkdir(dest, mode) && errno != EEXIST) {
00944 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00945 return -1;
00946 }
00947 }
00948 if (!ast_strlen_zero(ext)) {
00949 make_dir(dest, len, context, ext, "");
00950 if (mkdir(dest, mode) && errno != EEXIST) {
00951 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00952 return -1;
00953 }
00954 }
00955 if (!ast_strlen_zero(folder)) {
00956 make_dir(dest, len, context, ext, folder);
00957 if (mkdir(dest, mode) && errno != EEXIST) {
00958 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00959 return -1;
00960 }
00961 }
00962 return 0;
00963 }
00964
00965 static char *mbox(int id)
00966 {
00967 static char *msgs[] = {
00968 "INBOX",
00969 "Old",
00970 "Work",
00971 "Family",
00972 "Friends",
00973 "Cust1",
00974 "Cust2",
00975 "Cust3",
00976 "Cust4",
00977 "Cust5",
00978 };
00979 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp";
00980 }
00981
00982 static void free_user(struct ast_vm_user *vmu)
00983 {
00984 if (ast_test_flag(vmu, VM_ALLOCED))
00985 free(vmu);
00986 }
00987
00988
00989
00990 #ifdef IMAP_STORAGE
00991 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu)
00992 {
00993 char arg[10];
00994 struct vm_state *vms;
00995 unsigned long messageNum;
00996
00997
00998 if (msgnum < 0) {
00999 return;
01000 }
01001
01002 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01003 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);
01004 return;
01005 }
01006
01007
01008
01009 messageNum = vms->msgArray[msgnum];
01010 if (messageNum == 0) {
01011 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01012 return;
01013 }
01014 if (option_debug > 2)
01015 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01016
01017 snprintf (arg, sizeof(arg), "%lu",messageNum);
01018 ast_mutex_lock(&vms->lock);
01019 mail_setflag (vms->mailstream,arg,"\\DELETED");
01020 ast_mutex_unlock(&vms->lock);
01021 }
01022
01023 static int imap_retrieve_file(const char *dir, const int msgnum, const struct ast_vm_user *vmu)
01024 {
01025 BODY *body;
01026 char *header_content;
01027 char *attachedfilefmt;
01028 const char *cid_num;
01029 const char *cid_name;
01030 const char *duration;
01031 const char *context;
01032 const char *category;
01033 const char *origtime;
01034 struct vm_state *vms;
01035 char text_file[PATH_MAX];
01036 FILE *text_file_ptr;
01037
01038
01039
01040
01041 if (msgnum < 0) {
01042 return 0;
01043 }
01044
01045
01046
01047
01048 if(!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01049
01050
01051
01052
01053
01054
01055
01056 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01057 }
01058
01059 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01060
01061
01062 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01063 return 0;
01064 }
01065
01066 if (option_debug > 2)
01067 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01068 if (vms->msgArray[msgnum] == 0) {
01069 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01070 return -1;
01071 }
01072
01073
01074 ast_mutex_lock(&vms->lock);
01075 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01076 ast_mutex_unlock(&vms->lock);
01077
01078 if (ast_strlen_zero(header_content)) {
01079 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01080 return -1;
01081 }
01082
01083 ast_mutex_lock(&vms->lock);
01084 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01085 ast_mutex_unlock(&vms->lock);
01086
01087
01088 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01089 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01090 } else {
01091 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01092 return -1;
01093 }
01094
01095
01096
01097 strsep(&attachedfilefmt, ".");
01098 if (!attachedfilefmt) {
01099 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01100 return -1;
01101 }
01102
01103 save_body(body, vms, "2", attachedfilefmt);
01104
01105
01106 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01107
01108 if (!(text_file_ptr = fopen(text_file, "w"))) {
01109 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01110 }
01111
01112 fprintf(text_file_ptr, "%s\n", "[message]");
01113
01114 cid_num = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
01115 cid_name = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:");
01116 fprintf(text_file_ptr, "callerid=\"%s\" <%s>\n", S_OR(cid_name, ""), S_OR(cid_num, ""));
01117 context = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
01118 fprintf(text_file_ptr, "context=%s\n", S_OR(context, ""));
01119 origtime = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
01120 fprintf(text_file_ptr, "origtime=%s\n", S_OR(origtime, ""));
01121 duration = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
01122 fprintf(text_file_ptr, "duration=%s\n", S_OR(origtime, ""));
01123 category = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
01124 fprintf(text_file_ptr, "category=%s\n", S_OR(category, ""));
01125
01126 fclose(text_file_ptr);
01127 return 0;
01128 }
01129
01130 static int folder_int(const char *folder)
01131 {
01132
01133 if (!folder)
01134 return 0;
01135 if (!strcasecmp(folder, "INBOX"))
01136 return 0;
01137 else if (!strcasecmp(folder, "Old"))
01138 return 1;
01139 else if (!strcasecmp(folder, "Work"))
01140 return 2;
01141 else if (!strcasecmp(folder, "Family"))
01142 return 3;
01143 else if (!strcasecmp(folder, "Friends"))
01144 return 4;
01145 else if (!strcasecmp(folder, "Cust1"))
01146 return 5;
01147 else if (!strcasecmp(folder, "Cust2"))
01148 return 6;
01149 else if (!strcasecmp(folder, "Cust3"))
01150 return 7;
01151 else if (!strcasecmp(folder, "Cust4"))
01152 return 8;
01153 else if (!strcasecmp(folder, "Cust5"))
01154 return 9;
01155 else
01156 return 0;
01157 }
01158
01159 static int messagecount(const char *context, const char *mailbox, const char *folder)
01160 {
01161 SEARCHPGM *pgm;
01162 SEARCHHEADER *hdr;
01163
01164 struct ast_vm_user *vmu, vmus;
01165 struct vm_state *vms_p;
01166 int ret = 0;
01167 int fold = folder_int(folder);
01168
01169 if (ast_strlen_zero(mailbox))
01170 return 0;
01171
01172
01173
01174 vmu = find_user(&vmus, context, mailbox);
01175 if (!vmu) {
01176 ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
01177 return -1;
01178 } else {
01179
01180 if (vmu->imapuser[0] == '\0') {
01181 ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
01182 return -1;
01183 }
01184 }
01185
01186
01187 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01188 if (!vms_p) {
01189 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01190 }
01191 if (vms_p) {
01192 if (option_debug > 2)
01193 ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
01194 if (fold == 0) {
01195 return vms_p->newmessages;
01196 }
01197 if (fold == 1) {
01198 return vms_p->oldmessages;
01199 }
01200 }
01201
01202
01203 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01204 if (!vms_p) {
01205 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01206 }
01207
01208 if (!vms_p) {
01209 if (!(vms_p = create_vm_state_from_user(vmu))) {
01210 ast_log(LOG_WARNING, "Unable to allocate space for new vm_state!\n");
01211 return -1;
01212 }
01213 }
01214 ret = init_mailstream(vms_p, fold);
01215 if (!vms_p->mailstream) {
01216 ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
01217 return -1;
01218 }
01219 if (ret == 0) {
01220 ast_mutex_lock(&vms_p->lock);
01221 pgm = mail_newsearchpgm ();
01222 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox);
01223 pgm->header = hdr;
01224 if (fold != 1) {
01225 pgm->unseen = 1;
01226 pgm->seen = 0;
01227 }
01228
01229
01230
01231 else {
01232 pgm->unseen = 0;
01233 pgm->seen = 1;
01234 }
01235 pgm->undeleted = 1;
01236 pgm->deleted = 0;
01237
01238 vms_p->vmArrayIndex = 0;
01239 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01240 if (fold == 0)
01241 vms_p->newmessages = vms_p->vmArrayIndex;
01242 if (fold == 1)
01243 vms_p->oldmessages = vms_p->vmArrayIndex;
01244
01245 mail_free_searchpgm(&pgm);
01246 ast_mutex_unlock(&vms_p->lock);
01247 vms_p->updated = 0;
01248 return vms_p->vmArrayIndex;
01249 } else {
01250 ast_mutex_lock(&vms_p->lock);
01251 mail_ping(vms_p->mailstream);
01252 ast_mutex_unlock(&vms_p->lock);
01253 }
01254 return 0;
01255 }
01256
01257 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms)
01258 {
01259 char *myserveremail = serveremail;
01260 char fn[PATH_MAX];
01261 char mailbox[256];
01262 char *stringp;
01263 FILE *p=NULL;
01264 char tmp[80] = "/tmp/astmail-XXXXXX";
01265 long len;
01266 void *buf;
01267 int tempcopy = 0;
01268 STRING str;
01269
01270
01271 if (msgnum < 0)
01272 return 0;
01273
01274
01275 fmt = ast_strdupa(fmt);
01276 stringp = fmt;
01277 strsep(&stringp, "|");
01278
01279 if (!ast_strlen_zero(vmu->serveremail))
01280 myserveremail = vmu->serveremail;
01281
01282 make_file(fn, sizeof(fn), dir, msgnum);
01283
01284 if (ast_strlen_zero(vmu->email)) {
01285
01286
01287
01288
01289 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01290 tempcopy = 1;
01291 }
01292
01293 if (!strcmp(fmt, "wav49"))
01294 fmt = "WAV";
01295 if (option_debug > 2)
01296 ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
01297
01298
01299 if ((p = vm_mkftemp(tmp)) == NULL) {
01300 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01301 if (tempcopy)
01302 *(vmu->email) = '\0';
01303 return -1;
01304 } else {
01305 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
01306
01307 len = ftell(p);
01308 rewind(p);
01309 if ((buf = ast_malloc(len+1)) == NIL) {
01310 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
01311 fclose(p);
01312 return -1;
01313 }
01314 if (fread(buf, len, 1, p) != 1) {
01315 ast_log(LOG_WARNING, "Short read: %s\n", strerror(errno));
01316 }
01317 ((char *)buf)[len] = '\0';
01318 INIT(&str, mail_string, buf, len);
01319 init_mailstream(vms, 0);
01320 imap_mailbox_name(mailbox, sizeof(mailbox), vms, 0, 1);
01321 ast_mutex_lock(&vms->lock);
01322 if (!mail_append(vms->mailstream, mailbox, &str))
01323 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01324 ast_mutex_unlock(&vms->lock);
01325 fclose(p);
01326 unlink(tmp);
01327 ast_free(buf);
01328 if (option_debug > 2)
01329 ast_log(LOG_DEBUG, "%s stored\n", fn);
01330
01331
01332
01333 messagecount(vmu->context, vmu->mailbox, "INBOX");
01334 }
01335 if (tempcopy)
01336 *(vmu->email) = '\0';
01337 return 0;
01338
01339 }
01340
01341 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01342 {
01343 char tmp[PATH_MAX] = "";
01344 char *mailboxnc;
01345 char *context;
01346 char *mb;
01347 char *cur;
01348 if (newmsgs)
01349 *newmsgs = 0;
01350 if (oldmsgs)
01351 *oldmsgs = 0;
01352
01353 if (option_debug > 2)
01354 ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context);
01355
01356 if (ast_strlen_zero(mailbox_context))
01357 return 0;
01358
01359 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01360 context = strchr(tmp, '@');
01361 if (strchr(mailbox_context, ',')) {
01362 int tmpnew, tmpold;
01363 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01364 mb = tmp;
01365 while ((cur = strsep(&mb, ", "))) {
01366 if (!ast_strlen_zero(cur)) {
01367 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01368 return -1;
01369 else {
01370 if (newmsgs)
01371 *newmsgs += tmpnew;
01372 if (oldmsgs)
01373 *oldmsgs += tmpold;
01374 }
01375 }
01376 }
01377 return 0;
01378 }
01379 if (context) {
01380 *context = '\0';
01381 mailboxnc = tmp;
01382 context++;
01383 } else {
01384 context = "default";
01385 mailboxnc = (char *)mailbox_context;
01386 }
01387 if (newmsgs) {
01388 if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0)
01389 return -1;
01390 }
01391 if (oldmsgs) {
01392 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01393 return -1;
01394 }
01395 return 0;
01396 }
01397
01398
01399 static int has_voicemail(const char *mailbox, const char *folder)
01400 {
01401 char tmp[256], *tmp2, *mbox, *context;
01402 ast_copy_string(tmp, mailbox, sizeof(tmp));
01403 tmp2 = tmp;
01404 if (strchr(tmp2, ',')) {
01405 while ((mbox = strsep(&tmp2, ","))) {
01406 if (!ast_strlen_zero(mbox)) {
01407 if (has_voicemail(mbox, folder))
01408 return 1;
01409 }
01410 }
01411 }
01412 if ((context= strchr(tmp, '@')))
01413 *context++ = '\0';
01414 else
01415 context = "default";
01416 return messagecount(context, tmp, folder) ? 1 : 0;
01417 }
01418
01419 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)
01420 {
01421 struct vm_state *sendvms = NULL, *destvms = NULL;
01422 char messagestring[10];
01423 if (msgnum >= recip->maxmsg) {
01424 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01425 return -1;
01426 }
01427 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01428 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01429 return -1;
01430 }
01431 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01432 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01433 return -1;
01434 }
01435 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01436 ast_mutex_lock(&sendvms->lock);
01437 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
01438 ast_mutex_unlock(&sendvms->lock);
01439 return 0;
01440 }
01441 ast_mutex_unlock(&sendvms->lock);
01442 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01443 return -1;
01444 }
01445
01446 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01447 {
01448 char tmp[256], *t = tmp;
01449 size_t left = sizeof(tmp);
01450
01451 if (box == 1) {
01452 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
01453 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1));
01454 } else {
01455 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01456 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
01457 }
01458
01459
01460 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
01461
01462
01463 if (!ast_strlen_zero(authuser))
01464 ast_build_string(&t, &left, "/authuser=%s", authuser);
01465
01466
01467 if (!ast_strlen_zero(imapflags))
01468 ast_build_string(&t, &left, "/%s", imapflags);
01469
01470
01471 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
01472
01473 if (box == 0 || box == 1)
01474 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
01475 else
01476 snprintf(spec, len, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
01477 }
01478
01479 static int init_mailstream(struct vm_state *vms, int box)
01480 {
01481 MAILSTREAM *stream = NIL;
01482 long debug;
01483 char tmp[256];
01484
01485 if (!vms) {
01486 ast_log (LOG_ERROR,"vm_state is NULL!\n");
01487 return -1;
01488 }
01489 if (option_debug > 2)
01490 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
01491 if (vms->mailstream == NIL || !vms->mailstream) {
01492 if (option_debug)
01493 ast_log (LOG_DEBUG,"mailstream not set.\n");
01494 } else {
01495 stream = vms->mailstream;
01496 }
01497
01498 debug = NIL;
01499
01500 if (delimiter == '\0') {
01501 char *cp;
01502 #ifdef USE_SYSTEM_IMAP
01503 #include <imap/linkage.c>
01504 #elif defined(USE_SYSTEM_CCLIENT)
01505 #include <c-client/linkage.c>
01506 #else
01507 #include "linkage.c"
01508 #endif
01509
01510 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
01511 ast_mutex_lock(&vms->lock);
01512 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01513 ast_mutex_unlock(&vms->lock);
01514 if (stream == NIL) {
01515 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
01516 return -1;
01517 }
01518 get_mailbox_delimiter(stream);
01519
01520 for (cp = imapfolder; *cp; cp++)
01521 if (*cp == '/')
01522 *cp = delimiter;
01523 }
01524
01525 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
01526 if (option_debug > 2)
01527 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
01528 ast_mutex_lock(&vms->lock);
01529 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01530 ast_mutex_unlock(&vms->lock);
01531 if (vms->mailstream == NIL) {
01532 return -1;
01533 } else {
01534 return 0;
01535 }
01536 }
01537
01538 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
01539 {
01540 SEARCHPGM *pgm;
01541 SEARCHHEADER *hdr;
01542 int ret;
01543
01544 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
01545 if (option_debug > 2)
01546 ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
01547 ret = init_mailstream(vms, box);
01548 if (ret != 0 || !vms->mailstream) {
01549 ast_log (LOG_ERROR,"Could not initialize mailstream\n");
01550 return -1;
01551 }
01552
01553 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
01554
01555
01556 if (box == 0) {
01557 if (option_debug > 2)
01558 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
01559 check_quota(vms,(char *)mbox(box));
01560 }
01561
01562 ast_mutex_lock(&vms->lock);
01563 pgm = mail_newsearchpgm();
01564
01565
01566 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
01567 pgm->header = hdr;
01568 pgm->deleted = 0;
01569 pgm->undeleted = 1;
01570
01571
01572 if (box == 0) {
01573 pgm->unseen = 1;
01574 pgm->seen = 0;
01575 } else if (box == 1) {
01576 pgm->seen = 1;
01577 pgm->unseen = 0;
01578 }
01579
01580 vms->vmArrayIndex = 0;
01581 if (option_debug > 2)
01582 ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
01583 mail_search_full (vms->mailstream, NULL, pgm, NIL);
01584
01585 vms->lastmsg = vms->vmArrayIndex - 1;
01586
01587 mail_free_searchpgm(&pgm);
01588 ast_mutex_unlock(&vms->lock);
01589 return 0;
01590 }
01591
01592 static void write_file(char *filename, char *buffer, unsigned long len)
01593 {
01594 FILE *output;
01595
01596 output = fopen (filename, "w");
01597 if (fwrite (buffer, len, 1, output) != 1) {
01598 ast_log(LOG_WARNING, "Short write: %s\n", strerror(errno));
01599 }
01600 fclose (output);
01601 }
01602
01603 void mm_searched(MAILSTREAM *stream, unsigned long number)
01604 {
01605 struct vm_state *vms;
01606 char *mailbox;
01607 char *user;
01608 mailbox = stream->mailbox;
01609 user = get_user_by_mailbox(mailbox);
01610 vms = get_vm_state_by_imapuser(user,2);
01611 if (vms) {
01612 if (option_debug > 2)
01613 ast_log (LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number,vms->vmArrayIndex,vms->interactive);
01614 vms->msgArray[vms->vmArrayIndex++] = number;
01615 } else {
01616 ast_log (LOG_ERROR, "No state found.\n");
01617 }
01618 }
01619
01620 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
01621 {
01622 struct ast_variable *var;
01623 struct ast_vm_user *vmu;
01624
01625 vmu = ast_calloc(1, sizeof *vmu);
01626 if (!vmu)
01627 return NULL;
01628 ast_set_flag(vmu, VM_ALLOCED);
01629 populate_defaults(vmu);
01630
01631 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
01632 if (var) {
01633 apply_options_full(vmu, var);
01634 ast_variables_destroy(var);
01635 return vmu;
01636 } else {
01637 free(vmu);
01638 return NULL;
01639 }
01640 }
01641
01642
01643
01644 void mm_exists(MAILSTREAM * stream, unsigned long number)
01645 {
01646
01647 if (option_debug > 3)
01648 ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
01649 if (number == 0) return;
01650 set_update(stream);
01651 }
01652
01653
01654 void mm_expunged(MAILSTREAM * stream, unsigned long number)
01655 {
01656
01657 if (option_debug > 3)
01658 ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
01659 if (number == 0) return;
01660 set_update(stream);
01661 }
01662
01663
01664 void mm_flags(MAILSTREAM * stream, unsigned long number)
01665 {
01666
01667 if (option_debug > 3)
01668 ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
01669 if (number == 0) return;
01670 set_update(stream);
01671 }
01672
01673
01674 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
01675 {
01676 mm_log (string, errflg);
01677 }
01678
01679
01680 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
01681 {
01682 if (delimiter == '\0') {
01683 delimiter = delim;
01684 }
01685 if (option_debug > 4) {
01686 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
01687 if (attributes & LATT_NOINFERIORS)
01688 ast_log(LOG_DEBUG, "no inferiors\n");
01689 if (attributes & LATT_NOSELECT)
01690 ast_log(LOG_DEBUG, "no select\n");
01691 if (attributes & LATT_MARKED)
01692 ast_log(LOG_DEBUG, "marked\n");
01693 if (attributes & LATT_UNMARKED)
01694 ast_log(LOG_DEBUG, "unmarked\n");
01695 }
01696 }
01697
01698
01699 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
01700 {
01701 if (option_debug > 4) {
01702 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
01703 if (attributes & LATT_NOINFERIORS)
01704 ast_log(LOG_DEBUG, "no inferiors\n");
01705 if (attributes & LATT_NOSELECT)
01706 ast_log(LOG_DEBUG, "no select\n");
01707 if (attributes & LATT_MARKED)
01708 ast_log(LOG_DEBUG, "marked\n");
01709 if (attributes & LATT_UNMARKED)
01710 ast_log(LOG_DEBUG, "unmarked\n");
01711 }
01712 }
01713
01714
01715 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
01716 {
01717 ast_log (LOG_NOTICE," Mailbox %s", mailbox);
01718 if (status->flags & SA_MESSAGES)
01719 ast_log (LOG_NOTICE,", %lu messages", status->messages);
01720 if (status->flags & SA_RECENT)
01721 ast_log (LOG_NOTICE,", %lu recent", status->recent);
01722 if (status->flags & SA_UNSEEN)
01723 ast_log (LOG_NOTICE,", %lu unseen", status->unseen);
01724 if (status->flags & SA_UIDVALIDITY)
01725 ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity);
01726 if (status->flags & SA_UIDNEXT)
01727 ast_log (LOG_NOTICE,", %lu next UID", status->uidnext);
01728 ast_log (LOG_NOTICE,"\n");
01729 }
01730
01731
01732 void mm_log(char *string, long errflg)
01733 {
01734 switch ((short) errflg) {
01735 case NIL:
01736 if (option_debug)
01737 ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
01738 break;
01739 case PARSE:
01740 case WARN:
01741 ast_log (LOG_WARNING,"IMAP Warning: %s\n", string);
01742 break;
01743 case ERROR:
01744 ast_log (LOG_ERROR,"IMAP Error: %s\n", string);
01745 break;
01746 }
01747 }
01748
01749
01750 void mm_dlog(char *string)
01751 {
01752 ast_log (LOG_NOTICE, "%s\n", string);
01753 }
01754
01755
01756 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
01757 {
01758 struct ast_vm_user *vmu;
01759
01760 if (option_debug > 3)
01761 ast_log(LOG_DEBUG, "Entering callback mm_login\n");
01762
01763 ast_copy_string(user, mb->user, MAILTMPLEN);
01764
01765
01766 if (!ast_strlen_zero(authpassword)) {
01767 ast_copy_string(pwd, authpassword, MAILTMPLEN);
01768 } else {
01769 AST_LIST_TRAVERSE(&users, vmu, list) {
01770 if (!strcasecmp(mb->user, vmu->imapuser)) {
01771 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01772 break;
01773 }
01774 }
01775 if (!vmu) {
01776 if ((vmu = find_user_realtime_imapuser(mb->user))) {
01777 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01778 free_user(vmu);
01779 }
01780 }
01781 }
01782 }
01783
01784
01785 void mm_critical(MAILSTREAM * stream)
01786 {
01787 }
01788
01789
01790 void mm_nocritical(MAILSTREAM * stream)
01791 {
01792 }
01793
01794
01795 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
01796 {
01797 kill (getpid (), SIGSTOP);
01798 return NIL;
01799 }
01800
01801
01802 void mm_fatal(char *string)
01803 {
01804 ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string);
01805 }
01806
01807
01808 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
01809 {
01810 struct vm_state *vms;
01811 char *mailbox;
01812 char *user;
01813 unsigned long usage = 0;
01814 unsigned long limit = 0;
01815
01816 while (pquota) {
01817 usage = pquota->usage;
01818 limit = pquota->limit;
01819 pquota = pquota->next;
01820 }
01821
01822 mailbox = stream->mailbox;
01823 user = get_user_by_mailbox(mailbox);
01824 vms = get_vm_state_by_imapuser(user,2);
01825 if (vms) {
01826 if (option_debug > 2)
01827 ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
01828 vms->quota_usage = usage;
01829 vms->quota_limit = limit;
01830 } else {
01831 ast_log (LOG_ERROR, "No state found.\n");
01832 }
01833 }
01834
01835 static char *get_header_by_tag(char *header, char *tag)
01836 {
01837 char *start;
01838 int taglen;
01839 char *eol_pnt;
01840
01841 if (!header || !tag)
01842 return NULL;
01843
01844 taglen = strlen(tag) + 1;
01845 if (taglen < 1)
01846 return NULL;
01847
01848 start = strstr(header, tag);
01849 if (!start)
01850 return NULL;
01851
01852 ast_mutex_lock(&imaptemp_lock);
01853 ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
01854 ast_mutex_unlock(&imaptemp_lock);
01855 if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n')))
01856 *eol_pnt = '\0';
01857 return imaptemp;
01858 }
01859
01860 static char *get_user_by_mailbox(char *mailbox)
01861 {
01862 char *start, *quote;
01863 char *eol_pnt;
01864
01865 if (!mailbox)
01866 return NULL;
01867
01868 start = strstr(mailbox,"/user=");
01869 if (!start)
01870 return NULL;
01871
01872 ast_mutex_lock(&imaptemp_lock);
01873 ast_copy_string(imaptemp, start+6, sizeof(imaptemp));
01874 ast_mutex_unlock(&imaptemp_lock);
01875
01876 quote = strchr(imaptemp,'\"');
01877 if (!quote) {
01878 eol_pnt = strchr(imaptemp,'/');
01879 if (!eol_pnt) {
01880 eol_pnt = strchr(imaptemp,'}');
01881 }
01882 *eol_pnt = '\0';
01883 return imaptemp;
01884 } else {
01885 eol_pnt = strchr(imaptemp+1,'\"');
01886 *eol_pnt = '\0';
01887 return imaptemp+1;
01888 }
01889 }
01890
01891 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
01892 {
01893 struct vm_state *vms_p;
01894
01895 if (option_debug > 4)
01896 ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
01897 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
01898 return NULL;
01899 ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
01900 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
01901 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
01902 vms_p->mailstream = NIL;
01903 if (option_debug > 4)
01904 ast_log(LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
01905 vms_p->updated = 1;
01906
01907 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
01908 init_vm_state(vms_p);
01909 vmstate_insert(vms_p);
01910 return vms_p;
01911 }
01912
01913 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
01914 {
01915 struct vmstate *vlist = NULL;
01916
01917 ast_mutex_lock(&vmstate_lock);
01918 vlist = vmstates;
01919 while (vlist) {
01920 if (vlist->vms) {
01921 if (vlist->vms->imapuser) {
01922 if (!strcmp(vlist->vms->imapuser,user)) {
01923 if (interactive == 2) {
01924 ast_mutex_unlock(&vmstate_lock);
01925 return vlist->vms;
01926 } else if (vlist->vms->interactive == interactive) {
01927 ast_mutex_unlock(&vmstate_lock);
01928 return vlist->vms;
01929 }
01930 }
01931 } else {
01932 if (option_debug > 2)
01933 ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user);
01934 }
01935 } else {
01936 if (option_debug > 2)
01937 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user);
01938 }
01939 vlist = vlist->next;
01940 }
01941 ast_mutex_unlock(&vmstate_lock);
01942 if (option_debug > 2)
01943 ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
01944 return NULL;
01945 }
01946
01947 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
01948 {
01949 struct vmstate *vlist = NULL;
01950 const char *local_context = S_OR(context, "default");
01951
01952 ast_mutex_lock(&vmstate_lock);
01953 vlist = vmstates;
01954 if (option_debug > 2)
01955 ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
01956 while (vlist) {
01957 if (vlist->vms) {
01958 if (vlist->vms->username && vlist->vms->context) {
01959 if (option_debug > 2)
01960 ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive);
01961 if (!strcmp(vlist->vms->username,mailbox) && !(strcmp(vlist->vms->context, local_context)) && vlist->vms->interactive == interactive) {
01962 if (option_debug > 2)
01963 ast_log(LOG_DEBUG, " Found it!\n");
01964 ast_mutex_unlock(&vmstate_lock);
01965 return vlist->vms;
01966 }
01967 } else {
01968 if (option_debug > 2)
01969 ast_log(LOG_DEBUG, " error: username or context is NULL for %s\n",mailbox);
01970 }
01971 } else {
01972 if (option_debug > 2)
01973 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox);
01974 }
01975 vlist = vlist->next;
01976 }
01977 ast_mutex_unlock(&vmstate_lock);
01978 if (option_debug > 2)
01979 ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
01980 return NULL;
01981 }
01982
01983 static void vmstate_insert(struct vm_state *vms)
01984 {
01985 struct vmstate *v;
01986 struct vm_state *altvms;
01987
01988
01989
01990
01991 if (vms->interactive == 1) {
01992 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
01993 if (altvms) {
01994 if (option_debug > 2)
01995 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
01996 vms->newmessages = altvms->newmessages;
01997 vms->oldmessages = altvms->oldmessages;
01998
01999 copy_msgArray(vms, altvms);
02000 vms->vmArrayIndex = altvms->vmArrayIndex;
02001 vms->lastmsg = altvms->lastmsg;
02002 vms->curmsg = altvms->curmsg;
02003
02004 vms->persist_vms = altvms;
02005
02006 vms->mailstream = altvms->mailstream;
02007
02008 }
02009 }
02010
02011 v = (struct vmstate *)malloc(sizeof(struct vmstate));
02012 if (!v) {
02013 ast_log(LOG_ERROR, "Out of memory\n");
02014 }
02015 if (option_debug > 2)
02016 ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02017 ast_mutex_lock(&vmstate_lock);
02018 v->vms = vms;
02019 v->next = vmstates;
02020 vmstates = v;
02021 ast_mutex_unlock(&vmstate_lock);
02022 }
02023
02024 static void vmstate_delete(struct vm_state *vms)
02025 {
02026 struct vmstate *vc, *vf = NULL, *vl = NULL;
02027 struct vm_state *altvms;
02028
02029
02030
02031 if (vms->interactive == 1) {
02032 altvms = vms->persist_vms;
02033 if (altvms) {
02034 if (option_debug > 2)
02035 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02036 altvms->newmessages = vms->newmessages;
02037 altvms->oldmessages = vms->oldmessages;
02038 altvms->updated = 1;
02039 }
02040 }
02041
02042 ast_mutex_lock(&vmstate_lock);
02043 vc = vmstates;
02044 if (option_debug > 2)
02045 ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02046 while (vc) {
02047 if (vc->vms == vms) {
02048 vf = vc;
02049 if (vl)
02050 vl->next = vc->next;
02051 else
02052 vmstates = vc->next;
02053 break;
02054 }
02055 vl = vc;
02056 vc = vc->next;
02057 }
02058 if (!vf) {
02059 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02060 } else {
02061 ast_mutex_destroy(&vf->vms->lock);
02062 free(vf);
02063 }
02064 ast_mutex_unlock(&vmstate_lock);
02065 }
02066
02067 static void set_update(MAILSTREAM * stream)
02068 {
02069 struct vm_state *vms;
02070 char *mailbox;
02071 char *user;
02072
02073 mailbox = stream->mailbox;
02074 user = get_user_by_mailbox(mailbox);
02075 vms = get_vm_state_by_imapuser(user, 0);
02076 if (vms) {
02077 if (option_debug > 2)
02078 ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user);
02079 vms->updated = 1;
02080 } else {
02081 if (option_debug > 2)
02082 ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user);
02083 }
02084 }
02085
02086 static void init_vm_state(struct vm_state *vms)
02087 {
02088 int x;
02089 vms->vmArrayIndex = 0;
02090 for (x = 0; x < 256; x++) {
02091 vms->msgArray[x] = 0;
02092 }
02093 ast_mutex_init(&vms->lock);
02094 }
02095
02096 static void copy_msgArray(struct vm_state *dst, struct vm_state *src)
02097 {
02098 int x;
02099 for (x = 0; x<256; x++) {
02100 dst->msgArray[x] = src->msgArray[x];
02101 }
02102 }
02103
02104 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
02105 {
02106 char *body_content;
02107 char *body_decoded;
02108 unsigned long len;
02109 unsigned long newlen;
02110 char filename[256];
02111
02112 if (!body || body == NIL)
02113 return -1;
02114 ast_mutex_lock(&vms->lock);
02115 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02116 ast_mutex_unlock(&vms->lock);
02117 if (body_content != NIL) {
02118 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
02119
02120 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
02121 write_file (filename, (char *) body_decoded, newlen);
02122 }
02123 return 0;
02124 }
02125
02126
02127
02128 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02129 char tmp[50];
02130 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02131 mail_list(stream, tmp, "*");
02132 }
02133
02134
02135 static void check_quota(struct vm_state *vms, char *mailbox) {
02136 ast_mutex_lock(&vms->lock);
02137 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02138 if (option_debug > 2)
02139 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02140 if (vms && vms->mailstream != NULL) {
02141 imap_getquotaroot(vms->mailstream, mailbox);
02142 } else {
02143 ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox);
02144 }
02145 ast_mutex_unlock(&vms->lock);
02146 }
02147 #endif
02148
02149
02150
02151
02152 static int vm_lock_path(const char *path)
02153 {
02154 switch (ast_lock_path(path)) {
02155 case AST_LOCK_TIMEOUT:
02156 return -1;
02157 default:
02158 return 0;
02159 }
02160 }
02161
02162
02163 #ifdef ODBC_STORAGE
02164 struct generic_prepare_struct {
02165 char *sql;
02166 int argc;
02167 char **argv;
02168 };
02169
02170 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02171 {
02172 struct generic_prepare_struct *gps = data;
02173 int res, i;
02174 SQLHSTMT stmt;
02175
02176 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02177 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02178 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02179 return NULL;
02180 }
02181 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02182 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02183 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02184 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02185 return NULL;
02186 }
02187 for (i = 0; i < gps->argc; i++)
02188 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02189
02190 return stmt;
02191 }
02192
02193 static int retrieve_file(char *dir, int msgnum)
02194 {
02195 int x = 0;
02196 int res;
02197 int fd=-1;
02198 size_t fdlen = 0;
02199 void *fdm = MAP_FAILED;
02200 SQLSMALLINT colcount=0;
02201 SQLHSTMT stmt;
02202 char sql[PATH_MAX];
02203 char fmt[80]="";
02204 char *c;
02205 char coltitle[256];
02206 SQLSMALLINT collen;
02207 SQLSMALLINT datatype;
02208 SQLSMALLINT decimaldigits;
02209 SQLSMALLINT nullable;
02210 SQLULEN colsize;
02211 SQLLEN colsize2;
02212 FILE *f=NULL;
02213 char rowdata[80];
02214 char fn[PATH_MAX];
02215 char full_fn[PATH_MAX];
02216 char msgnums[80];
02217 char *argv[] = { dir, msgnums };
02218 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02219
02220 struct odbc_obj *obj;
02221 obj = ast_odbc_request_obj(odbc_database, 0);
02222 if (obj) {
02223 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02224 c = strchr(fmt, '|');
02225 if (c)
02226 *c = '\0';
02227 if (!strcasecmp(fmt, "wav49"))
02228 strcpy(fmt, "WAV");
02229 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02230 if (msgnum > -1)
02231 make_file(fn, sizeof(fn), dir, msgnum);
02232 else
02233 ast_copy_string(fn, dir, sizeof(fn));
02234 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02235
02236 if (!(f = fopen(full_fn, "w+"))) {
02237 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02238 goto yuck;
02239 }
02240
02241 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02242 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02243 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02244 if (!stmt) {
02245 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02246 ast_odbc_release_obj(obj);
02247 goto yuck;
02248 }
02249 res = SQLFetch(stmt);
02250 if (res == SQL_NO_DATA) {
02251 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02252 ast_odbc_release_obj(obj);
02253 goto yuck;
02254 }
02255 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02256 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02257 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02258 ast_odbc_release_obj(obj);
02259 goto yuck;
02260 }
02261 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
02262 if (fd < 0) {
02263 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02264 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02265 ast_odbc_release_obj(obj);
02266 goto yuck;
02267 }
02268 res = SQLNumResultCols(stmt, &colcount);
02269 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02270 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02271 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02272 ast_odbc_release_obj(obj);
02273 goto yuck;
02274 }
02275 if (f)
02276 fprintf(f, "[message]\n");
02277 for (x=0;x<colcount;x++) {
02278 rowdata[0] = '\0';
02279 collen = sizeof(coltitle);
02280 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02281 &datatype, &colsize, &decimaldigits, &nullable);
02282 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02283 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02284 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02285 ast_odbc_release_obj(obj);
02286 goto yuck;
02287 }
02288 if (!strcasecmp(coltitle, "recording")) {
02289 off_t offset;
02290 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02291 fdlen = colsize2;
02292 if (fd > -1) {
02293 char tmp[1]="";
02294 lseek(fd, fdlen - 1, SEEK_SET);
02295 if (write(fd, tmp, 1) != 1) {
02296 close(fd);
02297 fd = -1;
02298 continue;
02299 }
02300
02301 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02302 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02303 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02304 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02305 ast_odbc_release_obj(obj);
02306 goto yuck;
02307 } else {
02308 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02309 munmap(fdm, CHUNKSIZE);
02310 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02311 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02312 unlink(full_fn);
02313 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02314 ast_odbc_release_obj(obj);
02315 goto yuck;
02316 }
02317 }
02318 }
02319 if (truncate(full_fn, fdlen) < 0) {
02320 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
02321 }
02322 }
02323 } else {
02324 SQLLEN ind;
02325 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind);
02326 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02327 SQLINTEGER nativeerror = 0;
02328 SQLSMALLINT diagbytes = 0;
02329 unsigned char state[10], diagnostic[256];
02330 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
02331 ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql);
02332 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02333 ast_odbc_release_obj(obj);
02334 goto yuck;
02335 }
02336 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02337 fprintf(f, "%s=%s\n", coltitle, rowdata);
02338 }
02339 }
02340 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02341 ast_odbc_release_obj(obj);
02342 } else
02343 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02344 yuck:
02345 if (f)
02346 fclose(f);
02347 if (fd > -1)
02348 close(fd);
02349 return x - 1;
02350 }
02351
02352 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02353 {
02354 int x = 0;
02355 int res;
02356 SQLHSTMT stmt;
02357 char sql[PATH_MAX];
02358 char rowdata[20];
02359 char *argv[] = { dir };
02360 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02361
02362 struct odbc_obj *obj;
02363 obj = ast_odbc_request_obj(odbc_database, 0);
02364 if (obj) {
02365 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
02366 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02367 if (!stmt) {
02368 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02369 ast_odbc_release_obj(obj);
02370 goto yuck;
02371 }
02372 res = SQLFetch(stmt);
02373 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02374 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02375 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02376 ast_odbc_release_obj(obj);
02377 goto yuck;
02378 }
02379 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02380 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02381 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02382 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02383 ast_odbc_release_obj(obj);
02384 goto yuck;
02385 }
02386 if (sscanf(rowdata, "%d", &x) != 1)
02387 ast_log(LOG_WARNING, "Failed to read message count!\n");
02388 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02389 ast_odbc_release_obj(obj);
02390 } else
02391 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02392 yuck:
02393 return x - 1;
02394 }
02395
02396 static int message_exists(char *dir, int msgnum)
02397 {
02398 int x = 0;
02399 int res;
02400 SQLHSTMT stmt;
02401 char sql[PATH_MAX];
02402 char rowdata[20];
02403 char msgnums[20];
02404 char *argv[] = { dir, msgnums };
02405 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02406
02407 struct odbc_obj *obj;
02408 obj = ast_odbc_request_obj(odbc_database, 0);
02409 if (obj) {
02410 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02411 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02412 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02413 if (!stmt) {
02414 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02415 ast_odbc_release_obj(obj);
02416 goto yuck;
02417 }
02418 res = SQLFetch(stmt);
02419 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02420 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02421 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02422 ast_odbc_release_obj(obj);
02423 goto yuck;
02424 }
02425 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02426 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02427 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02428 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02429 ast_odbc_release_obj(obj);
02430 goto yuck;
02431 }
02432 if (sscanf(rowdata, "%d", &x) != 1)
02433 ast_log(LOG_WARNING, "Failed to read message count!\n");
02434 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02435 ast_odbc_release_obj(obj);
02436 } else
02437 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02438 yuck:
02439 return x;
02440 }
02441
02442 static int count_messages(struct ast_vm_user *vmu, char *dir)
02443 {
02444 return last_message_index(vmu, dir) + 1;
02445 }
02446
02447 static void delete_file(char *sdir, int smsg)
02448 {
02449 SQLHSTMT stmt;
02450 char sql[PATH_MAX];
02451 char msgnums[20];
02452 char *argv[] = { sdir, msgnums };
02453 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02454
02455 struct odbc_obj *obj;
02456 obj = ast_odbc_request_obj(odbc_database, 0);
02457 if (obj) {
02458 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02459 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02460 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02461 if (!stmt)
02462 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02463 else
02464 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02465 ast_odbc_release_obj(obj);
02466 } else
02467 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02468 return;
02469 }
02470
02471 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
02472 {
02473 SQLHSTMT stmt;
02474 char sql[512];
02475 char msgnums[20];
02476 char msgnumd[20];
02477 struct odbc_obj *obj;
02478 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
02479 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02480
02481 delete_file(ddir, dmsg);
02482 obj = ast_odbc_request_obj(odbc_database, 0);
02483 if (obj) {
02484 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02485 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02486 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
02487 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02488 if (!stmt)
02489 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
02490 else
02491 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02492 ast_odbc_release_obj(obj);
02493 } else
02494 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02495 return;
02496 }
02497
02498 struct insert_cb_struct {
02499 char *dir;
02500 char *msgnum;
02501 void *recording;
02502 size_t recordinglen;
02503 SQLLEN indlen;
02504 const char *context;
02505 const char *macrocontext;
02506 const char *callerid;
02507 const char *origtime;
02508 const char *duration;
02509 char *mailboxuser;
02510 char *mailboxcontext;
02511 const char *category;
02512 char *sql;
02513 };
02514
02515 static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd)
02516 {
02517 struct insert_cb_struct *d = vd;
02518 int res;
02519 SQLHSTMT stmt;
02520
02521 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02522 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02523 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02524 return NULL;
02525 }
02526
02527 res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS);
02528 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02529 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql);
02530 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02531 return NULL;
02532 }
02533
02534 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL);
02535 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL);
02536 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen);
02537 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL);
02538 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL);
02539 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL);
02540 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL);
02541 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL);
02542 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL);
02543 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL);
02544 if (!ast_strlen_zero(d->category)) {
02545 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL);
02546 }
02547
02548 return stmt;
02549 }
02550
02551 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
02552 {
02553 int x = 0;
02554 int fd = -1;
02555 void *fdm = MAP_FAILED;
02556 size_t fdlen = -1;
02557 SQLHSTMT stmt;
02558 char sql[PATH_MAX];
02559 char msgnums[20];
02560 char fn[PATH_MAX];
02561 char full_fn[PATH_MAX];
02562 char fmt[80]="";
02563 char *c;
02564 struct insert_cb_struct d = {
02565 .dir = dir,
02566 .msgnum = msgnums,
02567 .context = "",
02568 .macrocontext = "",
02569 .callerid = "",
02570 .origtime = "",
02571 .duration = "",
02572 .mailboxuser = mailboxuser,
02573 .mailboxcontext = mailboxcontext,
02574 .category = "",
02575 .sql = sql
02576 };
02577 struct ast_config *cfg=NULL;
02578 struct odbc_obj *obj;
02579
02580 delete_file(dir, msgnum);
02581 obj = ast_odbc_request_obj(odbc_database, 0);
02582 if (obj) {
02583 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02584 c = strchr(fmt, '|');
02585 if (c)
02586 *c = '\0';
02587 if (!strcasecmp(fmt, "wav49"))
02588 strcpy(fmt, "WAV");
02589 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02590 if (msgnum > -1)
02591 make_file(fn, sizeof(fn), dir, msgnum);
02592 else
02593 ast_copy_string(fn, dir, sizeof(fn));
02594 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02595 cfg = ast_config_load(full_fn);
02596 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02597 fd = open(full_fn, O_RDWR);
02598 if (fd < 0) {
02599 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
02600 ast_odbc_release_obj(obj);
02601 goto yuck;
02602 }
02603 if (cfg) {
02604 d.context = ast_variable_retrieve(cfg, "message", "context");
02605 if (!d.context) d.context = "";
02606 d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
02607 if (!d.macrocontext) d.macrocontext = "";
02608 d.callerid = ast_variable_retrieve(cfg, "message", "callerid");
02609 if (!d.callerid) d.callerid = "";
02610 d.origtime = ast_variable_retrieve(cfg, "message", "origtime");
02611 if (!d.origtime) d.origtime = "";
02612 d.duration = ast_variable_retrieve(cfg, "message", "duration");
02613 if (!d.duration) d.duration = "";
02614 d.category = ast_variable_retrieve(cfg, "message", "category");
02615 if (!d.category) d.category = "";
02616 }
02617 fdlen = lseek(fd, 0, SEEK_END);
02618 lseek(fd, 0, SEEK_SET);
02619 printf("Length is %zd\n", fdlen);
02620 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
02621 if (fdm == MAP_FAILED) {
02622 ast_log(LOG_WARNING, "Memory map failed!\n");
02623 ast_odbc_release_obj(obj);
02624 goto yuck;
02625 }
02626 d.recording = fdm;
02627 d.recordinglen = d.indlen = fdlen;
02628 if (!ast_strlen_zero(d.category))
02629 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
02630 else
02631 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?, ? , ?,?,?,?,?,?,?)",odbc_table);
02632 stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d);
02633 if (stmt) {
02634 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02635 }
02636 ast_odbc_release_obj(obj);
02637 } else
02638 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02639 yuck:
02640 if (cfg)
02641 ast_config_destroy(cfg);
02642 if (fdm != MAP_FAILED)
02643 munmap(fdm, fdlen);
02644 if (fd > -1)
02645 close(fd);
02646 return x;
02647 }
02648
02649 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
02650 {
02651 SQLHSTMT stmt;
02652 char sql[PATH_MAX];
02653 char msgnums[20];
02654 char msgnumd[20];
02655 struct odbc_obj *obj;
02656 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
02657 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02658
02659 delete_file(ddir, dmsg);
02660 obj = ast_odbc_request_obj(odbc_database, 0);
02661 if (obj) {
02662 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02663 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02664 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
02665 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02666 if (!stmt)
02667 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02668 else
02669 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02670 ast_odbc_release_obj(obj);
02671 } else
02672 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02673 return;
02674 }
02675
02676 #else
02677 #ifndef IMAP_STORAGE
02678 static int count_messages(struct ast_vm_user *vmu, char *dir)
02679 {
02680
02681
02682 int vmcount = 0;
02683 DIR *vmdir = NULL;
02684 struct dirent *vment = NULL;
02685
02686 if (vm_lock_path(dir))
02687 return ERROR_LOCK_PATH;
02688
02689 if ((vmdir = opendir(dir))) {
02690 while ((vment = readdir(vmdir))) {
02691 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
02692 vmcount++;
02693 }
02694 closedir(vmdir);
02695 }
02696 ast_unlock_path(dir);
02697
02698 return vmcount;
02699 }
02700
02701 static void rename_file(char *sfn, char *dfn)
02702 {
02703 char stxt[PATH_MAX];
02704 char dtxt[PATH_MAX];
02705 ast_filerename(sfn,dfn,NULL);
02706 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
02707 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
02708 rename(stxt, dtxt);
02709 }
02710 #endif
02711
02712
02713
02714
02715 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
02716 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02717 {
02718 int x;
02719 char fn[PATH_MAX];
02720
02721 if (vm_lock_path(dir))
02722 return ERROR_LOCK_PATH;
02723
02724 for (x = 0; x < vmu->maxmsg; x++) {
02725 make_file(fn, sizeof(fn), dir, x);
02726 if (ast_fileexists(fn, NULL, NULL) < 1)
02727 break;
02728 }
02729 ast_unlock_path(dir);
02730
02731 return x - 1;
02732 }
02733 #endif
02734 #endif
02735 #if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
02736 static int remove_file(char *dir, int msgnum)
02737 {
02738 char fn[PATH_MAX];
02739 char full_fn[PATH_MAX];
02740 char msgnums[80];
02741
02742 if (msgnum > -1) {
02743 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02744 make_file(fn, sizeof(fn), dir, msgnum);
02745 } else {
02746 #ifndef IMAP_STORAGE
02747 ast_copy_string(fn, dir, sizeof(fn));
02748 #else
02749
02750
02751
02752 return 0;
02753 #endif
02754 }
02755 ast_filedelete(fn, NULL);
02756 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02757 unlink(full_fn);
02758 return 0;
02759 }
02760 #endif
02761
02762 static int copy(char *infile, char *outfile)
02763 {
02764 int ifd;
02765 int ofd;
02766 int res;
02767 int len;
02768 char buf[4096];
02769
02770 #ifdef HARDLINK_WHEN_POSSIBLE
02771
02772 if (link(infile, outfile)) {
02773 #endif
02774 if ((ifd = open(infile, O_RDONLY)) < 0) {
02775 ast_log(LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
02776 return -1;
02777 }
02778 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
02779 ast_log(LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
02780 close(ifd);
02781 return -1;
02782 }
02783 do {
02784 len = read(ifd, buf, sizeof(buf));
02785 if (len < 0) {
02786 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
02787 close(ifd);
02788 close(ofd);
02789 unlink(outfile);
02790 }
02791 if (len) {
02792 res = write(ofd, buf, len);
02793 if (errno == ENOMEM || errno == ENOSPC || res != len) {
02794 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
02795 close(ifd);
02796 close(ofd);
02797 unlink(outfile);
02798 }
02799 }
02800 } while (len);
02801 close(ifd);
02802 close(ofd);
02803 return 0;
02804 #ifdef HARDLINK_WHEN_POSSIBLE
02805 } else {
02806
02807 return 0;
02808 }
02809 #endif
02810 }
02811
02812 static void copy_plain_file(char *frompath, char *topath)
02813 {
02814 char frompath2[PATH_MAX], topath2[PATH_MAX];
02815 ast_filecopy(frompath, topath, NULL);
02816 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
02817 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
02818 copy(frompath2, topath2);
02819 }
02820
02821 static int vm_delete(char *file)
02822 {
02823 char *txt;
02824 int txtsize = 0;
02825
02826 txtsize = (strlen(file) + 5)*sizeof(char);
02827 txt = alloca(txtsize);
02828
02829
02830
02831 snprintf(txt, txtsize, "%s.txt", file);
02832 unlink(txt);
02833 return ast_filedelete(file, NULL);
02834 }
02835
02836 static int inbuf(struct baseio *bio, FILE *fi)
02837 {
02838 int l;
02839
02840 if (bio->ateof)
02841 return 0;
02842
02843 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
02844 if (ferror(fi))
02845 return -1;
02846
02847 bio->ateof = 1;
02848 return 0;
02849 }
02850
02851 bio->iolen= l;
02852 bio->iocp= 0;
02853
02854 return 1;
02855 }
02856
02857 static int inchar(struct baseio *bio, FILE *fi)
02858 {
02859 if (bio->iocp>=bio->iolen) {
02860 if (!inbuf(bio, fi))
02861 return EOF;
02862 }
02863
02864 return bio->iobuf[bio->iocp++];
02865 }
02866
02867 static int ochar(struct baseio *bio, int c, FILE *so)
02868 {
02869 if (bio->linelength>=BASELINELEN) {
02870 if (fputs(eol,so)==EOF)
02871 return -1;
02872
02873 bio->linelength= 0;
02874 }
02875
02876 if (putc(((unsigned char)c),so)==EOF)
02877 return -1;
02878
02879 bio->linelength++;
02880
02881 return 1;
02882 }
02883
02884 static int base_encode(char *filename, FILE *so)
02885 {
02886 unsigned char dtable[BASEMAXINLINE];
02887 int i,hiteof= 0;
02888 FILE *fi;
02889 struct baseio bio;
02890
02891 memset(&bio, 0, sizeof(bio));
02892 bio.iocp = BASEMAXINLINE;
02893
02894 if (!(fi = fopen(filename, "rb"))) {
02895 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
02896 return -1;
02897 }
02898
02899 for (i= 0;i<9;i++) {
02900 dtable[i]= 'A'+i;
02901 dtable[i+9]= 'J'+i;
02902 dtable[26+i]= 'a'+i;
02903 dtable[26+i+9]= 'j'+i;
02904 }
02905 for (i= 0;i<8;i++) {
02906 dtable[i+18]= 'S'+i;
02907 dtable[26+i+18]= 's'+i;
02908 }
02909 for (i= 0;i<10;i++) {
02910 dtable[52+i]= '0'+i;
02911 }
02912 dtable[62]= '+';
02913 dtable[63]= '/';
02914
02915 while (!hiteof){
02916 unsigned char igroup[3],ogroup[4];
02917 int c,n;
02918
02919 igroup[0]= igroup[1]= igroup[2]= 0;
02920
02921 for (n= 0;n<3;n++) {
02922 if ((c = inchar(&bio, fi)) == EOF) {
02923 hiteof= 1;
02924 break;
02925 }
02926
02927 igroup[n]= (unsigned char)c;
02928 }
02929
02930 if (n> 0) {
02931 ogroup[0]= dtable[igroup[0]>>2];
02932 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
02933 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
02934 ogroup[3]= dtable[igroup[2]&0x3F];
02935
02936 if (n<3) {
02937 ogroup[3]= '=';
02938
02939 if (n<2)
02940 ogroup[2]= '=';
02941 }
02942
02943 for (i= 0;i<4;i++)
02944 ochar(&bio, ogroup[i], so);
02945 }
02946 }
02947
02948 fclose(fi);
02949
02950 if (fputs(eol,so)==EOF)
02951 return 0;
02952
02953 return 1;
02954 }
02955
02956 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
02957 {
02958 char callerid[256];
02959
02960 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
02961 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
02962 snprintf(passdata, passdatasize, "%d", msgnum);
02963 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
02964 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
02965 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
02966 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
02967 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
02968 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
02969 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
02970 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
02971 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
02972 }
02973
02974 static char *quote(const char *from, char *to, size_t len)
02975 {
02976 char *ptr = to;
02977 *ptr++ = '"';
02978 for (; ptr < to + len - 1; from++) {
02979 if (*from == '"')
02980 *ptr++ = '\\';
02981 else if (*from == '\0')
02982 break;
02983 *ptr++ = *from;
02984 }
02985 if (ptr < to + len - 1)
02986 *ptr++ = '"';
02987 *ptr = '\0';
02988 return to;
02989 }
02990
02991
02992
02993
02994 static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
02995 {
02996 const struct vm_zone *z = NULL;
02997 time_t t = time(NULL);
02998
02999
03000 if (!ast_strlen_zero(vmu->zonetag)) {
03001
03002 AST_LIST_LOCK(&zones);
03003 AST_LIST_TRAVERSE(&zones, z, list) {
03004 if (!strcmp(z->name, vmu->zonetag))
03005 break;
03006 }
03007 AST_LIST_UNLOCK(&zones);
03008 }
03009 ast_localtime(&t, tm, z ? z->timezone : NULL);
03010 return tm;
03011 }
03012
03013
03014
03015
03016
03017 static int check_mime(const char *str)
03018 {
03019 for (; *str; str++) {
03020 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03021 return 1;
03022 }
03023 }
03024 return 0;
03025 }
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03044 {
03045 char tmp[80];
03046 int first_section = 1;
03047 size_t endlen = 0, tmplen = 0;
03048 *end = '\0';
03049
03050 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03051 for (; *start; start++) {
03052 int need_encoding = 0;
03053 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03054 need_encoding = 1;
03055 }
03056 if ((first_section && need_encoding && preamble + tmplen > 70) ||
03057 (first_section && !need_encoding && preamble + tmplen > 72) ||
03058 (!first_section && need_encoding && tmplen > 70) ||
03059 (!first_section && !need_encoding && tmplen > 72)) {
03060
03061 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
03062 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03063 first_section = 0;
03064 }
03065 if (need_encoding && *start == ' ') {
03066 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
03067 } else if (need_encoding) {
03068 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
03069 } else {
03070 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
03071 }
03072 }
03073 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
03074 return end;
03075 }
03076
03077 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
03078 {
03079 char date[256];
03080 char host[MAXHOSTNAMELEN] = "";
03081 char who[256];
03082 char bound[256];
03083 char fname[256];
03084 char dur[256];
03085 char tmpcmd[256];
03086 char enc_cidnum[256] = "", enc_cidname[256] = "";
03087 struct tm tm;
03088 char *passdata = NULL, *passdata2;
03089 size_t len_passdata = 0, len_passdata2, tmplen;
03090 #ifdef IMAP_STORAGE
03091 #define ENDL "\r\n"
03092 #else
03093 #define ENDL "\n"
03094 #endif
03095
03096
03097 len_passdata2 = strlen(vmu->fullname);
03098 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
03099 len_passdata2 = tmplen;
03100 }
03101 if ((tmplen = strlen(emailtitle)) > len_passdata2) {
03102 len_passdata2 = tmplen;
03103 }
03104 if ((tmplen = strlen(fromstring)) > len_passdata2) {
03105 len_passdata2 = tmplen;
03106 }
03107 len_passdata2 = len_passdata2 * 3 + 200;
03108 passdata2 = alloca(len_passdata2);
03109
03110 if (cidnum) {
03111 strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
03112 }
03113 if (cidname) {
03114 strip_control(cidname, enc_cidname, sizeof(enc_cidname));
03115 }
03116 gethostname(host, sizeof(host) - 1);
03117 if (strchr(srcemail, '@'))
03118 ast_copy_string(who, srcemail, sizeof(who));
03119 else {
03120 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03121 }
03122 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03123 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03124 fprintf(p, "Date: %s" ENDL, date);
03125
03126
03127 strftime(date, sizeof(date), emaildateformat, &tm);
03128
03129 if (*fromstring) {
03130 struct ast_channel *ast;
03131 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03132 char *ptr;
03133 memset(passdata2, 0, len_passdata2);
03134 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category);
03135 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
03136 len_passdata = strlen(passdata2) * 3 + 300;
03137 passdata = alloca(len_passdata);
03138 if (check_mime(passdata2)) {
03139 int first_line = 1;
03140 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
03141 while ((ptr = strchr(passdata, ' '))) {
03142 *ptr = '\0';
03143 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
03144 first_line = 0;
03145 passdata = ptr + 1;
03146 }
03147 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
03148 } else {
03149 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
03150 }
03151 ast_channel_free(ast);
03152 } else
03153 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03154 } else
03155 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03156
03157 if (check_mime(vmu->fullname)) {
03158 int first_line = 1;
03159 char *ptr;
03160 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
03161 while ((ptr = strchr(passdata2, ' '))) {
03162 *ptr = '\0';
03163 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
03164 first_line = 0;
03165 passdata2 = ptr + 1;
03166 }
03167 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
03168 } else {
03169 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
03170 }
03171 if (emailsubject) {
03172 struct ast_channel *ast;
03173 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03174 int vmlen = strlen(emailsubject) * 3 + 200;
03175
03176 if (vmlen > len_passdata) {
03177 passdata = alloca(vmlen);
03178 len_passdata = vmlen;
03179 }
03180
03181 memset(passdata, 0, len_passdata);
03182 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, len_passdata, category);
03183 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
03184 if (check_mime(passdata)) {
03185 int first_line = 1;
03186 char *ptr;
03187 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
03188 while ((ptr = strchr(passdata2, ' '))) {
03189 *ptr = '\0';
03190 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03191 first_line = 0;
03192 passdata2 = ptr + 1;
03193 }
03194 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03195 } else {
03196 fprintf(p, "Subject: %s" ENDL, passdata);
03197 }
03198 ast_channel_free(ast);
03199 } else {
03200 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03201 }
03202 } else if (*emailtitle) {
03203 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
03204 fprintf(p, ENDL) ;
03205 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
03206 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03207 } else {
03208 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03209 }
03210 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
03211 if (imap) {
03212
03213 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
03214
03215 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
03216 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
03217 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
03218 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
03219 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
03220 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
03221 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
03222 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
03223 if (!ast_strlen_zero(category)) {
03224 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
03225 }
03226 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
03227 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
03228 }
03229 if (!ast_strlen_zero(cidnum)) {
03230 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
03231 }
03232 if (!ast_strlen_zero(cidname)) {
03233 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
03234 }
03235 fprintf(p, "MIME-Version: 1.0" ENDL);
03236 if (attach_user_voicemail) {
03237
03238 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
03239
03240 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
03241 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
03242 fprintf(p, "--%s" ENDL, bound);
03243 }
03244 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
03245 if (emailbody) {
03246 struct ast_channel *ast;
03247 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03248 char *passdata;
03249 int vmlen = strlen(emailbody)*3 + 200;
03250 if ((passdata = alloca(vmlen))) {
03251 memset(passdata, 0, vmlen);
03252 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03253 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
03254 fprintf(p, "%s" ENDL, passdata);
03255 } else
03256 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03257 ast_channel_free(ast);
03258 } else
03259 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03260 } else {
03261 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
03262
03263 "in mailbox %s from %s, on %s so you might" ENDL
03264 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname,
03265 dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
03266 }
03267 if (attach_user_voicemail) {
03268
03269 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03270 char tmpdir[256], newtmp[256];
03271 int tmpfd = -1;
03272
03273 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03274 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03275 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03276 tmpfd = mkstemp(newtmp);
03277 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03278 if (option_debug > 2)
03279 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
03280 if (tmpfd > -1) {
03281 int soxstatus;
03282 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03283 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03284 attach = newtmp;
03285 if (option_debug > 2) {
03286 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03287 }
03288 } else {
03289 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03290 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03291 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03292 }
03293 }
03294 }
03295 fprintf(p, "--%s" ENDL, bound);
03296 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03297 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03298 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03299 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03300 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03301 base_encode(fname, p);
03302 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03303 if (tmpfd > -1) {
03304 unlink(fname);
03305 close(tmpfd);
03306 unlink(newtmp);
03307 }
03308 }
03309 #undef ENDL
03310 }
03311 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
03312 {
03313 FILE *p=NULL;
03314 char tmp[80] = "/tmp/astmail-XXXXXX";
03315 char tmp2[256];
03316
03317 if (vmu && ast_strlen_zero(vmu->email)) {
03318 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03319 return(0);
03320 }
03321 if (!strcmp(format, "wav49"))
03322 format = "WAV";
03323 if (option_debug > 2)
03324 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
03325
03326
03327 if ((p = vm_mkftemp(tmp)) == NULL) {
03328 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03329 return -1;
03330 } else {
03331 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03332 fclose(p);
03333 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03334 ast_safe_system(tmp2);
03335 if (option_debug > 2)
03336 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03337 }
03338 return 0;
03339 }
03340
03341 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category)
03342 {
03343 char date[256];
03344 char host[MAXHOSTNAMELEN] = "";
03345 char who[256];
03346 char dur[PATH_MAX];
03347 char tmp[80] = "/tmp/astmail-XXXXXX";
03348 char tmp2[PATH_MAX];
03349 struct tm tm;
03350 FILE *p;
03351
03352 if ((p = vm_mkftemp(tmp)) == NULL) {
03353 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03354 return -1;
03355 } else {
03356 gethostname(host, sizeof(host)-1);
03357 if (strchr(srcemail, '@'))
03358 ast_copy_string(who, srcemail, sizeof(who));
03359 else {
03360 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03361 }
03362 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03363 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03364 fprintf(p, "Date: %s\n", date);
03365
03366 if (*pagerfromstring) {
03367 struct ast_channel *ast;
03368 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03369 char *passdata;
03370 int vmlen = strlen(fromstring)*3 + 200;
03371 if ((passdata = alloca(vmlen))) {
03372 memset(passdata, 0, vmlen);
03373 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03374 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03375 fprintf(p, "From: %s <%s>\n", passdata, who);
03376 } else
03377 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03378 ast_channel_free(ast);
03379 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03380 } else
03381 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03382 fprintf(p, "To: %s\n", pager);
03383 if (pagersubject) {
03384 struct ast_channel *ast;
03385 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03386 char *passdata;
03387 int vmlen = strlen(pagersubject) * 3 + 200;
03388 if ((passdata = alloca(vmlen))) {
03389 memset(passdata, 0, vmlen);
03390 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03391 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03392 fprintf(p, "Subject: %s\n\n", passdata);
03393 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03394 ast_channel_free(ast);
03395 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03396 } else
03397 fprintf(p, "Subject: New VM\n\n");
03398 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03399 if (pagerbody) {
03400 struct ast_channel *ast;
03401 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03402 char *passdata;
03403 int vmlen = strlen(pagerbody)*3 + 200;
03404 if ((passdata = alloca(vmlen))) {
03405 memset(passdata, 0, vmlen);
03406 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03407 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03408 fprintf(p, "%s\n", passdata);
03409 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03410 ast_channel_free(ast);
03411 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03412 } else {
03413 fprintf(p, "New %s long msg in box %s\n"
03414 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03415 }
03416 fclose(p);
03417 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03418 ast_safe_system(tmp2);
03419 if (option_debug > 2)
03420 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
03421 }
03422 return 0;
03423 }
03424
03425 static int get_date(char *s, int len)
03426 {
03427 struct tm tm;
03428 time_t t;
03429
03430 time(&t);
03431
03432 ast_localtime(&t, &tm, NULL);
03433
03434 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
03435 }
03436
03437 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03438 {
03439 int res = -2;
03440
03441 #ifdef ODBC_STORAGE
03442 int success =
03443 #endif
03444 RETRIEVE(filename, -1, vmu);
03445 if (ast_fileexists(filename, NULL, NULL) > 0) {
03446 res = ast_streamfile(chan, filename, chan->language);
03447 if (res > -1)
03448 res = ast_waitstream(chan, ecodes);
03449 #ifdef ODBC_STORAGE
03450 if (success == -1) {
03451
03452 if (option_debug)
03453 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03454 store_file(filename, vmu->mailbox, vmu->context, -1);
03455 }
03456 #endif
03457 }
03458 DISPOSE(filename, -1);
03459
03460 return res;
03461 }
03462
03463 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03464 {
03465 int res;
03466 char fn[PATH_MAX];
03467 char dest[PATH_MAX];
03468
03469 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03470
03471 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
03472 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03473 return -1;
03474 }
03475
03476 res = play_greeting(chan, vmu, fn, ecodes);
03477 if (res == -2) {
03478
03479 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
03480 if (res)
03481 return res;
03482 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03483 }
03484
03485 if (res)
03486 return res;
03487
03488 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
03489 return res;
03490 }
03491
03492 static void free_zone(struct vm_zone *z)
03493 {
03494 free(z);
03495 }
03496
03497 #ifdef ODBC_STORAGE
03498
03499 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03500 {
03501 int x = -1;
03502 int res;
03503 SQLHSTMT stmt;
03504 char sql[PATH_MAX];
03505 char rowdata[20];
03506 char tmp[PATH_MAX] = "";
03507 struct odbc_obj *obj;
03508 char *context;
03509 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03510
03511 if (newmsgs)
03512 *newmsgs = 0;
03513 if (oldmsgs)
03514 *oldmsgs = 0;
03515
03516
03517 if (ast_strlen_zero(mailbox))
03518 return 0;
03519
03520 ast_copy_string(tmp, mailbox, sizeof(tmp));
03521
03522 context = strchr(tmp, '@');
03523 if (context) {
03524 *context = '\0';
03525 context++;
03526 } else
03527 context = "default";
03528
03529 obj = ast_odbc_request_obj(odbc_database, 0);
03530 if (obj) {
03531 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03532 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03533 if (!stmt) {
03534 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03535 ast_odbc_release_obj(obj);
03536 goto yuck;
03537 }
03538 res = SQLFetch(stmt);
03539 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03540 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03541 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03542 ast_odbc_release_obj(obj);
03543 goto yuck;
03544 }
03545 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03546 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03547 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03548 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03549 ast_odbc_release_obj(obj);
03550 goto yuck;
03551 }
03552 *newmsgs = atoi(rowdata);
03553 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03554
03555 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03556 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03557 if (!stmt) {
03558 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03559 ast_odbc_release_obj(obj);
03560 goto yuck;
03561 }
03562 res = SQLFetch(stmt);
03563 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03564 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03565 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03566 ast_odbc_release_obj(obj);
03567 goto yuck;
03568 }
03569 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03570 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03571 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03572 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03573 ast_odbc_release_obj(obj);
03574 goto yuck;
03575 }
03576 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03577 ast_odbc_release_obj(obj);
03578 *oldmsgs = atoi(rowdata);
03579 x = 0;
03580 } else
03581 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03582
03583 yuck:
03584 return x;
03585 }
03586
03587 static int messagecount(const char *context, const char *mailbox, const char *folder)
03588 {
03589 struct odbc_obj *obj = NULL;
03590 int nummsgs = 0;
03591 int res;
03592 SQLHSTMT stmt = NULL;
03593 char sql[PATH_MAX];
03594 char rowdata[20];
03595 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03596 if (!folder)
03597 folder = "INBOX";
03598
03599 if (ast_strlen_zero(mailbox))
03600 return 0;
03601
03602 obj = ast_odbc_request_obj(odbc_database, 0);
03603 if (obj) {
03604 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
03605 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03606 if (!stmt) {
03607 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03608 goto yuck;
03609 }
03610 res = SQLFetch(stmt);
03611 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03612 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03613 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03614 goto yuck;
03615 }
03616 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03618 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03619 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03620 goto yuck;
03621 }
03622 nummsgs = atoi(rowdata);
03623 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03624 } else
03625 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03626
03627 yuck:
03628 if (obj)
03629 ast_odbc_release_obj(obj);
03630 return nummsgs;
03631 }
03632
03633 static int has_voicemail(const char *mailbox, const char *folder)
03634 {
03635 char tmp[256], *tmp2 = tmp, *mbox, *context;
03636 ast_copy_string(tmp, mailbox, sizeof(tmp));
03637 while ((context = mbox = strsep(&tmp2, ","))) {
03638 strsep(&context, "@");
03639 if (ast_strlen_zero(context))
03640 context = "default";
03641 if (messagecount(context, mbox, folder))
03642 return 1;
03643 }
03644 return 0;
03645 }
03646 #endif
03647 #ifndef IMAP_STORAGE
03648
03649 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)
03650 {
03651 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
03652 const char *frombox = mbox(imbox);
03653 int recipmsgnum;
03654
03655 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
03656
03657 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
03658
03659 if (!dir)
03660 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
03661 else
03662 ast_copy_string(fromdir, dir, sizeof(fromdir));
03663
03664 make_file(frompath, sizeof(frompath), fromdir, msgnum);
03665
03666 if (vm_lock_path(todir))
03667 return ERROR_LOCK_PATH;
03668
03669 recipmsgnum = 0;
03670 do {
03671 make_file(topath, sizeof(topath), todir, recipmsgnum);
03672 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
03673 break;
03674 recipmsgnum++;
03675 } while (recipmsgnum < recip->maxmsg);
03676 if (recipmsgnum < recip->maxmsg) {
03677 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
03678 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
03679 } else {
03680
03681
03682
03683
03684
03685 copy_plain_file(frompath, topath);
03686 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL);
03687 vm_delete(topath);
03688 }
03689 } else {
03690 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
03691 }
03692 ast_unlock_path(todir);
03693 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
03694
03695 return 0;
03696 }
03697 #endif
03698 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
03699 static int messagecount(const char *context, const char *mailbox, const char *folder)
03700 {
03701 return __has_voicemail(context, mailbox, folder, 0);
03702 }
03703
03704
03705 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
03706 {
03707 DIR *dir;
03708 struct dirent *de;
03709 char fn[256];
03710 int ret = 0;
03711 if (!folder)
03712 folder = "INBOX";
03713
03714 if (ast_strlen_zero(mailbox))
03715 return 0;
03716 if (!context)
03717 context = "default";
03718 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
03719 dir = opendir(fn);
03720 if (!dir)
03721 return 0;
03722 while ((de = readdir(dir))) {
03723 if (!strncasecmp(de->d_name, "msg", 3)) {
03724 if (shortcircuit) {
03725 ret = 1;
03726 break;
03727 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
03728 ret++;
03729 }
03730 }
03731 closedir(dir);
03732 return ret;
03733 }
03734
03735
03736 static int has_voicemail(const char *mailbox, const char *folder)
03737 {
03738 char tmp[256], *tmp2 = tmp, *mbox, *context;
03739 ast_copy_string(tmp, mailbox, sizeof(tmp));
03740 while ((mbox = strsep(&tmp2, ","))) {
03741 if ((context = strchr(mbox, '@')))
03742 *context++ = '\0';
03743 else
03744 context = "default";
03745 if (__has_voicemail(context, mbox, folder, 1))
03746 return 1;
03747 }
03748 return 0;
03749 }
03750
03751
03752 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03753 {
03754 char tmp[256];
03755 char *context;
03756
03757 if (newmsgs)
03758 *newmsgs = 0;
03759 if (oldmsgs)
03760 *oldmsgs = 0;
03761
03762 if (ast_strlen_zero(mailbox))
03763 return 0;
03764 if (strchr(mailbox, ',')) {
03765 int tmpnew, tmpold;
03766 char *mb, *cur;
03767
03768 ast_copy_string(tmp, mailbox, sizeof(tmp));
03769 mb = tmp;
03770 while ((cur = strsep(&mb, ", "))) {
03771 if (!ast_strlen_zero(cur)) {
03772 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
03773 return -1;
03774 else {
03775 if (newmsgs)
03776 *newmsgs += tmpnew;
03777 if (oldmsgs)
03778 *oldmsgs += tmpold;
03779 }
03780 }
03781 }
03782 return 0;
03783 }
03784 ast_copy_string(tmp, mailbox, sizeof(tmp));
03785 context = strchr(tmp, '@');
03786 if (context) {
03787 *context = '\0';
03788 context++;
03789 } else
03790 context = "default";
03791 if (newmsgs)
03792 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
03793 if (oldmsgs)
03794 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
03795 return 0;
03796 }
03797
03798 #endif
03799
03800 static void run_externnotify(char *context, char *extension)
03801 {
03802 char arguments[255];
03803 char ext_context[256] = "";
03804 int newvoicemails = 0, oldvoicemails = 0;
03805 struct ast_smdi_mwi_message *mwi_msg;
03806
03807 if (!ast_strlen_zero(context))
03808 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
03809 else
03810 ast_copy_string(ext_context, extension, sizeof(ext_context));
03811
03812 if (!strcasecmp(externnotify, "smdi")) {
03813 if (ast_app_has_voicemail(ext_context, NULL))
03814 ast_smdi_mwi_set(smdi_iface, extension);
03815 else
03816 ast_smdi_mwi_unset(smdi_iface, extension);
03817
03818 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
03819 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
03820 if (!strncmp(mwi_msg->cause, "INV", 3))
03821 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
03822 else if (!strncmp(mwi_msg->cause, "BLK", 3))
03823 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
03824 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
03825 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
03826 } else {
03827 if (option_debug)
03828 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
03829 }
03830 } else if (!ast_strlen_zero(externnotify)) {
03831 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
03832 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
03833 } else {
03834 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
03835 if (option_debug)
03836 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
03837 ast_safe_system(arguments);
03838 }
03839 }
03840 }
03841
03842 struct leave_vm_options {
03843 unsigned int flags;
03844 signed char record_gain;
03845 };
03846
03847 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
03848 {
03849 #ifdef IMAP_STORAGE
03850 int newmsgs, oldmsgs;
03851 #endif
03852 struct vm_state *vms = NULL;
03853 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
03854 char callerid[256];
03855 FILE *txt;
03856 char date[256];
03857 int txtdes;
03858 int res = 0;
03859 int msgnum;
03860 int duration = 0;
03861 int ausemacro = 0;
03862 int ousemacro = 0;
03863 int ouseexten = 0;
03864 char dir[PATH_MAX], tmpdir[PATH_MAX];
03865 char dest[PATH_MAX];
03866 char fn[PATH_MAX];
03867 char prefile[PATH_MAX] = "";
03868 char tempfile[PATH_MAX] = "";
03869 char ext_context[256] = "";
03870 char fmt[80];
03871 char *context;
03872 char ecodes[16] = "#";
03873 char tmp[1024] = "", *tmpptr;
03874 struct ast_vm_user *vmu;
03875 struct ast_vm_user svm;
03876 const char *category = NULL;
03877
03878 ast_copy_string(tmp, ext, sizeof(tmp));
03879 ext = tmp;
03880 context = strchr(tmp, '@');
03881 if (context) {
03882 *context++ = '\0';
03883 tmpptr = strchr(context, '&');
03884 } else {
03885 tmpptr = strchr(ext, '&');
03886 }
03887
03888 if (tmpptr)
03889 *tmpptr++ = '\0';
03890
03891 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
03892
03893 if (option_debug > 2)
03894 ast_log(LOG_DEBUG, "Before find_user\n");
03895 if (!(vmu = find_user(&svm, context, ext))) {
03896 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
03897 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
03898 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03899 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03900 return res;
03901 }
03902
03903 if (strcmp(vmu->context, "default"))
03904 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
03905 else
03906 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
03907 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
03908 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
03909 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
03910 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
03911 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
03912 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
03913 }
03914 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
03915 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
03916 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
03917 return -1;
03918 }
03919 RETRIEVE(tempfile, -1, vmu);
03920 if (ast_fileexists(tempfile, NULL, NULL) > 0)
03921 ast_copy_string(prefile, tempfile, sizeof(prefile));
03922 DISPOSE(tempfile, -1);
03923
03924 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
03925 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
03926
03927
03928 if (ast_test_flag(vmu, VM_OPERATOR)) {
03929 if (!ast_strlen_zero(vmu->exit)) {
03930 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
03931 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03932 ouseexten = 1;
03933 }
03934 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
03935 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03936 ouseexten = 1;
03937 }
03938 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
03939 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03940 ousemacro = 1;
03941 }
03942 }
03943
03944 if (!ast_strlen_zero(vmu->exit)) {
03945 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
03946 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03947 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
03948 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03949 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
03950 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03951 ausemacro = 1;
03952 }
03953
03954
03955 if (!ast_strlen_zero(prefile)) {
03956 res = play_greeting(chan, vmu, prefile, ecodes);
03957 if (res == -2) {
03958
03959 if (option_debug)
03960 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
03961 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
03962 }
03963 if (res < 0) {
03964 if (option_debug)
03965 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
03966 free_user(vmu);
03967 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03968 return -1;
03969 }
03970 }
03971 if (res == '#') {
03972
03973 ast_set_flag(options, OPT_SILENT);
03974 res = 0;
03975 }
03976 if (!res && !ast_test_flag(options, OPT_SILENT)) {
03977 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
03978 if (res == '#') {
03979 ast_set_flag(options, OPT_SILENT);
03980 res = 0;
03981 }
03982 }
03983 if (res > 0)
03984 ast_stopstream(chan);
03985
03986
03987 if (res == '*') {
03988 chan->exten[0] = 'a';
03989 chan->exten[1] = '\0';
03990 if (!ast_strlen_zero(vmu->exit)) {
03991 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
03992 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
03993 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
03994 }
03995 chan->priority = 0;
03996 free_user(vmu);
03997 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
03998 return 0;
03999 }
04000
04001
04002 if (res == '0') {
04003 transfer:
04004 if (ouseexten || ousemacro) {
04005 chan->exten[0] = 'o';
04006 chan->exten[1] = '\0';
04007 if (!ast_strlen_zero(vmu->exit)) {
04008 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04009 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
04010 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04011 }
04012 ast_play_and_wait(chan, "transfer");
04013 chan->priority = 0;
04014 free_user(vmu);
04015 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04016 }
04017 return 0;
04018 }
04019 if (res < 0) {
04020 free_user(vmu);
04021 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04022 return -1;
04023 }
04024
04025 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04026 if (!ast_strlen_zero(fmt)) {
04027 msgnum = 0;
04028
04029 #ifdef IMAP_STORAGE
04030
04031
04032 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
04033 if (res < 0) {
04034 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
04035 return -1;
04036 }
04037 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
04038
04039
04040 if (!(vms = create_vm_state_from_user(vmu))) {
04041 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
04042 return -1;
04043 }
04044 }
04045 vms->newmessages++;
04046
04047 msgnum = newmsgs + oldmsgs;
04048 if (option_debug > 2)
04049 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
04050 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
04051
04052 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04053
04054
04055 check_quota(vms, imapfolder);
04056 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
04057 if (option_debug)
04058 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
04059 ast_play_and_wait(chan, "vm-mailboxfull");
04060 return -1;
04061 }
04062 if (option_debug > 2)
04063 ast_log(LOG_DEBUG, "Checking message number quota - mailbox has %d messages, maximum is set to %d\n",msgnum,vmu->maxmsg);
04064 if (msgnum >= vmu->maxmsg) {
04065 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04066 if (!res)
04067 res = ast_waitstream(chan, "");
04068 ast_log(LOG_WARNING, "No more messages possible\n");
04069 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04070 goto leave_vm_out;
04071 }
04072
04073
04074 if (msgnum >= vmu->maxmsg) {
04075 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
04076 ast_play_and_wait(chan, "vm-mailboxfull");
04077 return -1;
04078 }
04079 #else
04080 if (count_messages(vmu, dir) >= vmu->maxmsg) {
04081 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04082 if (!res)
04083 res = ast_waitstream(chan, "");
04084 ast_log(LOG_WARNING, "No more messages possible\n");
04085 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04086 goto leave_vm_out;
04087 }
04088
04089 #endif
04090 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
04091 txtdes = mkstemp(tmptxtfile);
04092 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
04093 if (txtdes < 0) {
04094 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04095 if (!res)
04096 res = ast_waitstream(chan, "");
04097 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
04098 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04099 goto leave_vm_out;
04100 }
04101
04102
04103 if (res >= 0) {
04104
04105 res = ast_stream_and_wait(chan, "beep", chan->language, "");
04106 }
04107
04108
04109 txt = fdopen(txtdes, "w+");
04110 if (txt) {
04111 get_date(date, sizeof(date));
04112 fprintf(txt,
04113 ";\n"
04114 "; Message Information file\n"
04115 ";\n"
04116 "[message]\n"
04117 "origmailbox=%s\n"
04118 "context=%s\n"
04119 "macrocontext=%s\n"
04120 "exten=%s\n"
04121 "priority=%d\n"
04122 "callerchan=%s\n"
04123 "callerid=%s\n"
04124 "origdate=%s\n"
04125 "origtime=%ld\n"
04126 "category=%s\n",
04127 ext,
04128 chan->context,
04129 chan->macrocontext,
04130 chan->exten,
04131 chan->priority,
04132 chan->name,
04133 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
04134 date, (long)time(NULL),
04135 category ? category : "");
04136 } else
04137 ast_log(LOG_WARNING, "Error opening text file for output\n");
04138 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
04139
04140 if (txt) {
04141 if (duration < vmminmessage) {
04142 fclose(txt);
04143 if (option_verbose > 2)
04144 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
04145 ast_filedelete(tmptxtfile, NULL);
04146 unlink(tmptxtfile);
04147 } else {
04148 fprintf(txt, "duration=%d\n", duration);
04149 fclose(txt);
04150 if (vm_lock_path(dir)) {
04151 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04152
04153 ast_filedelete(tmptxtfile, NULL);
04154 unlink(tmptxtfile);
04155 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04156 if (option_debug)
04157 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
04158 unlink(tmptxtfile);
04159 ast_unlock_path(dir);
04160 } else {
04161 for (;;) {
04162 make_file(fn, sizeof(fn), dir, msgnum);
04163 if (!EXISTS(dir, msgnum, fn, NULL))
04164 break;
04165 msgnum++;
04166 }
04167
04168
04169 #ifndef IMAP_STORAGE
04170 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04171 #else
04172 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04173 #endif
04174
04175 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04176 ast_filerename(tmptxtfile, fn, NULL);
04177 rename(tmptxtfile, txtfile);
04178
04179 ast_unlock_path(dir);
04180
04181
04182
04183 if (ast_fileexists(fn, NULL, NULL) > 0) {
04184 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04185 }
04186
04187
04188 while (tmpptr) {
04189 struct ast_vm_user recipu, *recip;
04190 char *exten, *context;
04191
04192 exten = strsep(&tmpptr, "&");
04193 context = strchr(exten, '@');
04194 if (context) {
04195 *context = '\0';
04196 context++;
04197 }
04198 if ((recip = find_user(&recipu, context, exten))) {
04199 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04200 free_user(recip);
04201 }
04202 }
04203
04204 if (ast_fileexists(fn, NULL, NULL)) {
04205 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04206 DISPOSE(dir, msgnum);
04207 }
04208 }
04209 }
04210 }
04211 if (res == '0') {
04212 goto transfer;
04213 } else if (res > 0)
04214 res = 0;
04215
04216 if (duration < vmminmessage)
04217
04218 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04219 else
04220 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04221 } else
04222 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04223 leave_vm_out:
04224 free_user(vmu);
04225
04226 return res;
04227 }
04228
04229 #ifndef IMAP_STORAGE
04230 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
04231 {
04232
04233
04234 int x,dest;
04235 char sfn[PATH_MAX];
04236 char dfn[PATH_MAX];
04237
04238 if (vm_lock_path(dir))
04239 return ERROR_LOCK_PATH;
04240
04241 for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
04242 make_file(sfn, sizeof(sfn), dir, x);
04243 if (EXISTS(dir, x, sfn, NULL)) {
04244
04245 if (x != dest) {
04246 make_file(dfn, sizeof(dfn), dir, dest);
04247 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04248 }
04249
04250 dest++;
04251 }
04252 }
04253 ast_unlock_path(dir);
04254
04255 return 0;
04256 }
04257 #endif
04258
04259 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04260 {
04261 int d;
04262 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
04263 return d;
04264 }
04265
04266 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04267 {
04268 #ifdef IMAP_STORAGE
04269
04270
04271 char sequence[10];
04272
04273 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04274 if (option_debug > 2)
04275 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
04276 ast_mutex_lock(&vms->lock);
04277 if (box == 1) {
04278 mail_setflag(vms->mailstream, sequence, "\\Seen");
04279 } else if (box == 0) {
04280 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04281 }
04282 if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1)) {
04283 ast_mutex_unlock(&vms->lock);
04284 return 0;
04285 } else {
04286 int res = !mail_copy(vms->mailstream,sequence,(char *) mbox(box));
04287 ast_mutex_unlock(&vms->lock);
04288 return res;
04289 }
04290 #else
04291 char *dir = vms->curdir;
04292 char *username = vms->username;
04293 char *context = vmu->context;
04294 char sfn[PATH_MAX];
04295 char dfn[PATH_MAX];
04296 char ddir[PATH_MAX];
04297 const char *dbox = mbox(box);
04298 int x;
04299 make_file(sfn, sizeof(sfn), dir, msg);
04300 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04301
04302 if (vm_lock_path(ddir))
04303 return ERROR_LOCK_PATH;
04304
04305 for (x = 0; x < vmu->maxmsg; x++) {
04306 make_file(dfn, sizeof(dfn), ddir, x);
04307 if (!EXISTS(ddir, x, dfn, NULL))
04308 break;
04309 }
04310 if (x >= vmu->maxmsg) {
04311 ast_unlock_path(ddir);
04312 return ERROR_MAILBOX_FULL;
04313 }
04314 if (strcmp(sfn, dfn)) {
04315 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04316 }
04317 ast_unlock_path(ddir);
04318 #endif
04319 return 0;
04320 }
04321
04322 static int adsi_logo(unsigned char *buf)
04323 {
04324 int bytes = 0;
04325 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04326 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04327 return bytes;
04328 }
04329
04330 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04331 {
04332 unsigned char buf[256];
04333 int bytes=0;
04334 int x;
04335 char num[5];
04336
04337 *useadsi = 0;
04338 bytes += ast_adsi_data_mode(buf + bytes);
04339 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04340
04341 bytes = 0;
04342 bytes += adsi_logo(buf);
04343 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04344 #ifdef DISPLAY
04345 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04346 #endif
04347 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04348 bytes += ast_adsi_data_mode(buf + bytes);
04349 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04350
04351 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04352 bytes = 0;
04353 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04354 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04355 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04356 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04357 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04358 return 0;
04359 }
04360
04361 #ifdef DISPLAY
04362
04363 bytes = 0;
04364 bytes += ast_adsi_logo(buf);
04365 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04366 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04367 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04368 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04369 #endif
04370 bytes = 0;
04371 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04372 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04373 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04374 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04375 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04376 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04377 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04378
04379 #ifdef DISPLAY
04380
04381 bytes = 0;
04382 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04383 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04384
04385 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04386 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04387 #endif
04388
04389 bytes = 0;
04390
04391 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04392 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04393 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04394 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04395 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04396 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04397 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04398
04399 #ifdef DISPLAY
04400
04401 bytes = 0;
04402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04403 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04404 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04405 #endif
04406
04407 bytes = 0;
04408 for (x=0;x<5;x++) {
04409 snprintf(num, sizeof(num), "%d", x);
04410 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04411 }
04412 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04413 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04414
04415 #ifdef DISPLAY
04416
04417 bytes = 0;
04418 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04419 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04420 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04421 #endif
04422
04423 if (ast_adsi_end_download(chan)) {
04424 bytes = 0;
04425 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04426 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04427 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04428 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04429 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04430 return 0;
04431 }
04432 bytes = 0;
04433 bytes += ast_adsi_download_disconnect(buf + bytes);
04434 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04435 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04436
04437 if (option_debug)
04438 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
04439
04440 #ifdef DISPLAY
04441
04442 bytes = 0;
04443 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04444 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04445 #endif
04446 if (option_debug)
04447 ast_log(LOG_DEBUG, "Restarting session...\n");
04448
04449 bytes = 0;
04450
04451 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04452 *useadsi = 1;
04453 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04454 } else
04455 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04456
04457 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04458 return 0;
04459 }
04460
04461 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04462 {
04463 int x;
04464 if (!ast_adsi_available(chan))
04465 return;
04466 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04467 if (x < 0)
04468 return;
04469 if (!x) {
04470 if (adsi_load_vmail(chan, useadsi)) {
04471 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04472 return;
04473 }
04474 } else
04475 *useadsi = 1;
04476 }
04477
04478 static void adsi_login(struct ast_channel *chan)
04479 {
04480 unsigned char buf[256];
04481 int bytes=0;
04482 unsigned char keys[8];
04483 int x;
04484 if (!ast_adsi_available(chan))
04485 return;
04486
04487 for (x=0;x<8;x++)
04488 keys[x] = 0;
04489
04490 keys[3] = ADSI_KEY_APPS + 3;
04491
04492 bytes += adsi_logo(buf + bytes);
04493 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04494 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04495 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04496 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04497 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
04498 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
04499 bytes += ast_adsi_set_keys(buf + bytes, keys);
04500 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04501 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04502 }
04503
04504 static void adsi_password(struct ast_channel *chan)
04505 {
04506 unsigned char buf[256];
04507 int bytes=0;
04508 unsigned char keys[8];
04509 int x;
04510 if (!ast_adsi_available(chan))
04511 return;
04512
04513 for (x=0;x<8;x++)
04514 keys[x] = 0;
04515
04516 keys[3] = ADSI_KEY_APPS + 3;
04517
04518 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04519 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
04520 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
04521 bytes += ast_adsi_set_keys(buf + bytes, keys);
04522 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04523 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04524 }
04525
04526 static void adsi_folders(struct ast_channel *chan, int start, char *label)
04527 {
04528 unsigned char buf[256];
04529 int bytes=0;
04530 unsigned char keys[8];
04531 int x,y;
04532
04533 if (!ast_adsi_available(chan))
04534 return;
04535
04536 for (x=0;x<5;x++) {
04537 y = ADSI_KEY_APPS + 12 + start + x;
04538 if (y > ADSI_KEY_APPS + 12 + 4)
04539 y = 0;
04540 keys[x] = ADSI_KEY_SKT | y;
04541 }
04542 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
04543 keys[6] = 0;
04544 keys[7] = 0;
04545
04546 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
04547 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
04548 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04549 bytes += ast_adsi_set_keys(buf + bytes, keys);
04550 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04551
04552 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04553 }
04554
04555 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
04556 {
04557 int bytes=0;
04558 unsigned char buf[256];
04559 char buf1[256], buf2[256];
04560 char fn2[PATH_MAX];
04561
04562 char cid[256]="";
04563 char *val;
04564 char *name, *num;
04565 char datetime[21]="";
04566 FILE *f;
04567
04568 unsigned char keys[8];
04569
04570 int x;
04571
04572 if (!ast_adsi_available(chan))
04573 return;
04574
04575
04576 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
04577 f = fopen(fn2, "r");
04578 if (f) {
04579 while (!feof(f)) {
04580 if (!fgets((char *)buf, sizeof(buf), f)) {
04581 continue;
04582 }
04583 if (!feof(f)) {
04584 char *stringp=NULL;
04585 stringp = (char *)buf;
04586 strsep(&stringp, "=");
04587 val = strsep(&stringp, "=");
04588 if (!ast_strlen_zero(val)) {
04589 if (!strcmp((char *)buf, "callerid"))
04590 ast_copy_string(cid, val, sizeof(cid));
04591 if (!strcmp((char *)buf, "origdate"))
04592 ast_copy_string(datetime, val, sizeof(datetime));
04593 }
04594 }
04595 }
04596 fclose(f);
04597 }
04598
04599 for (x=0;x<5;x++)
04600 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
04601 keys[6] = 0x0;
04602 keys[7] = 0x0;
04603
04604 if (!vms->curmsg) {
04605
04606 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04607 }
04608 if (vms->curmsg >= vms->lastmsg) {
04609
04610 if (vms->curmsg) {
04611
04612 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04613 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04614
04615 } else {
04616
04617 keys[3] = 1;
04618 }
04619 }
04620
04621 if (!ast_strlen_zero(cid)) {
04622 ast_callerid_parse(cid, &name, &num);
04623 if (!name)
04624 name = num;
04625 } else
04626 name = "Unknown Caller";
04627
04628
04629
04630 if (vms->deleted[vms->curmsg])
04631 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
04632
04633
04634 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
04635 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
04636 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
04637 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
04638
04639 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04640 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04641 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
04642 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
04643 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04644 bytes += ast_adsi_set_keys(buf + bytes, keys);
04645 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04646
04647 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04648 }
04649
04650 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
04651 {
04652 int bytes=0;
04653 unsigned char buf[256];
04654 unsigned char keys[8];
04655
04656 int x;
04657
04658 if (!ast_adsi_available(chan))
04659 return;
04660
04661
04662 for (x=0;x<5;x++)
04663 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
04664
04665 keys[6] = 0x0;
04666 keys[7] = 0x0;
04667
04668 if (!vms->curmsg) {
04669
04670 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04671 }
04672 if (vms->curmsg >= vms->lastmsg) {
04673
04674 if (vms->curmsg) {
04675
04676 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04677 } else {
04678
04679 keys[3] = 1;
04680 }
04681 }
04682
04683
04684 if (vms->deleted[vms->curmsg])
04685 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
04686
04687
04688 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
04689 bytes += ast_adsi_set_keys(buf + bytes, keys);
04690 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04691
04692 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04693 }
04694
04695 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
04696 {
04697 unsigned char buf[256] = "";
04698 char buf1[256] = "", buf2[256] = "";
04699 int bytes=0;
04700 unsigned char keys[8];
04701 int x;
04702
04703 char *newm = (vms->newmessages == 1) ? "message" : "messages";
04704 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
04705 if (!ast_adsi_available(chan))
04706 return;
04707 if (vms->newmessages) {
04708 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
04709 if (vms->oldmessages) {
04710 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
04711 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
04712 } else {
04713 snprintf(buf2, sizeof(buf2), "%s.", newm);
04714 }
04715 } else if (vms->oldmessages) {
04716 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
04717 snprintf(buf2, sizeof(buf2), "%s.", oldm);
04718 } else {
04719 strcpy(buf1, "You have no messages.");
04720 buf2[0] = ' ';
04721 buf2[1] = '\0';
04722 }
04723 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04724 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04725 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04726
04727 for (x=0;x<6;x++)
04728 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
04729 keys[6] = 0;
04730 keys[7] = 0;
04731
04732
04733 if (vms->lastmsg < 0)
04734 keys[0] = 1;
04735 bytes += ast_adsi_set_keys(buf + bytes, keys);
04736
04737 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04738
04739 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04740 }
04741
04742 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
04743 {
04744 unsigned char buf[256] = "";
04745 char buf1[256] = "", buf2[256] = "";
04746 int bytes=0;
04747 unsigned char keys[8];
04748 int x;
04749
04750 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
04751
04752 if (!ast_adsi_available(chan))
04753 return;
04754
04755
04756 for (x=0;x<6;x++)
04757 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
04758
04759 keys[6] = 0;
04760 keys[7] = 0;
04761
04762 if ((vms->lastmsg + 1) < 1)
04763 keys[0] = 0;
04764
04765 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
04766 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
04767
04768 if (vms->lastmsg + 1)
04769 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
04770 else
04771 strcpy(buf2, "no messages.");
04772 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04773 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04774 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
04775 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04776 bytes += ast_adsi_set_keys(buf + bytes, keys);
04777
04778 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04779
04780 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04781
04782 }
04783
04784
04785
04786
04787
04788
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798 static void adsi_goodbye(struct ast_channel *chan)
04799 {
04800 unsigned char buf[256];
04801 int bytes=0;
04802
04803 if (!ast_adsi_available(chan))
04804 return;
04805 bytes += adsi_logo(buf + bytes);
04806 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
04807 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
04808 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04809 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04810
04811 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04812 }
04813
04814
04815
04816
04817
04818 static int get_folder(struct ast_channel *chan, int start)
04819 {
04820 int x;
04821 int d;
04822 char fn[PATH_MAX];
04823 d = ast_play_and_wait(chan, "vm-press");
04824 if (d)
04825 return d;
04826 for (x = start; x< 5; x++) {
04827 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
04828 return d;
04829 d = ast_play_and_wait(chan, "vm-for");
04830 if (d)
04831 return d;
04832 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
04833 d = vm_play_folder_name(chan, fn);
04834 if (d)
04835 return d;
04836 d = ast_waitfordigit(chan, 500);
04837 if (d)
04838 return d;
04839 }
04840 d = ast_play_and_wait(chan, "vm-tocancel");
04841 if (d)
04842 return d;
04843 d = ast_waitfordigit(chan, 4000);
04844 return d;
04845 }
04846
04847 static int get_folder2(struct ast_channel *chan, char *fn, int start)
04848 {
04849 int res = 0;
04850 res = ast_play_and_wait(chan, fn);
04851 while (((res < '0') || (res > '9')) &&
04852 (res != '#') && (res >= 0)) {
04853 res = get_folder(chan, 0);
04854 }
04855 return res;
04856 }
04857
04858 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
04859 char *context, signed char record_gain, long *duration, struct vm_state *vms)
04860 {
04861 int cmd = 0;
04862 int retries = 0, prepend_duration = 0, already_recorded = 0;
04863 signed char zero_gain = 0;
04864 struct ast_config *msg_cfg;
04865 const char *duration_str;
04866 char msgfile[PATH_MAX], backup[PATH_MAX];
04867 char textfile[PATH_MAX];
04868
04869
04870 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
04871 strcpy(textfile, msgfile);
04872 strcpy(backup, msgfile);
04873 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
04874 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
04875
04876 if (!(msg_cfg = ast_config_load(textfile))) {
04877 return -1;
04878 }
04879
04880 *duration = 0;
04881 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
04882 *duration = atoi(duration_str);
04883
04884 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
04885 if (cmd)
04886 retries = 0;
04887 switch (cmd) {
04888 case '1':
04889
04890 {
04891 prepend_duration = 0;
04892
04893
04894 if (!msg_cfg) {
04895 cmd = 0;
04896 break;
04897 }
04898
04899
04900 if (already_recorded)
04901 ast_filecopy(backup, msgfile, NULL);
04902 else
04903 ast_filecopy(msgfile, backup, NULL);
04904 already_recorded = 1;
04905
04906 if (record_gain)
04907 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
04908
04909 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
04910 if (record_gain)
04911 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
04912
04913 if (prepend_duration) {
04914 struct ast_category *msg_cat;
04915
04916 char duration_str[12];
04917
04918 prepend_duration += *duration;
04919 msg_cat = ast_category_get(msg_cfg, "message");
04920 snprintf(duration_str, 11, "%d", prepend_duration);
04921 if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
04922 config_text_file_save(textfile, msg_cfg, "app_voicemail");
04923 }
04924 }
04925
04926 break;
04927 }
04928 case '2':
04929 cmd = 't';
04930 break;
04931 case '*':
04932 cmd = '*';
04933 break;
04934 default:
04935 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
04936
04937 if (!cmd)
04938 cmd = ast_play_and_wait(chan,"vm-starmain");
04939
04940 if (!cmd)
04941 cmd = ast_waitfordigit(chan,6000);
04942 if (!cmd)
04943 retries++;
04944 if (retries > 3)
04945 cmd = 't';
04946 }
04947 }
04948
04949 ast_config_destroy(msg_cfg);
04950 if (already_recorded)
04951 ast_filedelete(backup, NULL);
04952 if (prepend_duration)
04953 *duration = prepend_duration;
04954
04955 if (cmd == 't' || cmd == 'S')
04956 cmd = 0;
04957 return cmd;
04958 }
04959
04960 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
04961 {
04962 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
04963 int newmsgs = 0, oldmsgs = 0;
04964 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04965
04966 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
04967 make_file(fn, sizeof(fn), todir, msgnum);
04968 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
04969
04970 if (!ast_strlen_zero(vmu->attachfmt)) {
04971 if (strstr(fmt, vmu->attachfmt)) {
04972 fmt = vmu->attachfmt;
04973 } else {
04974 ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
04975 }
04976 }
04977
04978
04979 fmt = ast_strdupa(fmt);
04980 stringp = fmt;
04981 strsep(&stringp, "|");
04982
04983 if (!ast_strlen_zero(vmu->email)) {
04984 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
04985 char *myserveremail = serveremail;
04986 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
04987 if (!ast_strlen_zero(vmu->serveremail))
04988 myserveremail = vmu->serveremail;
04989
04990 if (attach_user_voicemail)
04991 RETRIEVE(todir, msgnum, vmu);
04992
04993
04994 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
04995
04996 if (attach_user_voicemail)
04997 DISPOSE(todir, msgnum);
04998 }
04999
05000 if (!ast_strlen_zero(vmu->pager)) {
05001 char *myserveremail = serveremail;
05002 if (!ast_strlen_zero(vmu->serveremail))
05003 myserveremail = vmu->serveremail;
05004 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category);
05005 }
05006
05007 if (ast_test_flag(vmu, VM_DELETE)) {
05008 DELETE(todir, msgnum, fn, vmu);
05009 }
05010
05011
05012 if (ast_app_has_voicemail(ext_context, NULL)) {
05013 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
05014 }
05015 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
05016 run_externnotify(vmu->context, vmu->mailbox);
05017 return 0;
05018 }
05019
05020 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int flag, signed char record_gain)
05021 {
05022 #ifdef IMAP_STORAGE
05023 int todircount=0;
05024 struct vm_state *dstvms;
05025 #endif
05026 char username[70]="";
05027 int res = 0, cmd = 0;
05028 struct ast_vm_user *receiver = NULL, *vmtmp;
05029 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
05030 char *stringp;
05031 const char *s;
05032 int saved_messages = 0, found = 0;
05033 int valid_extensions = 0;
05034 char *dir;
05035 int curmsg;
05036
05037 if (vms == NULL) return -1;
05038 dir = vms->curdir;
05039 curmsg = vms->curmsg;
05040
05041 while (!res && !valid_extensions) {
05042 int use_directory = 0;
05043 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
05044 int done = 0;
05045 int retries = 0;
05046 cmd=0;
05047 while ((cmd >= 0) && !done ){
05048 if (cmd)
05049 retries = 0;
05050 switch (cmd) {
05051 case '1':
05052 use_directory = 0;
05053 done = 1;
05054 break;
05055 case '2':
05056 use_directory = 1;
05057 done=1;
05058 break;
05059 case '*':
05060 cmd = 't';
05061 done = 1;
05062 break;
05063 default:
05064
05065 cmd = ast_play_and_wait(chan,"vm-forward");
05066 if (!cmd)
05067 cmd = ast_waitfordigit(chan,3000);
05068 if (!cmd)
05069 retries++;
05070 if (retries > 3)
05071 {
05072 cmd = 't';
05073 done = 1;
05074 }
05075
05076 }
05077 }
05078 if (cmd < 0 || cmd == 't')
05079 break;
05080 }
05081
05082 if (use_directory) {
05083
05084
05085 char old_context[sizeof(chan->context)];
05086 char old_exten[sizeof(chan->exten)];
05087 int old_priority;
05088 struct ast_app* app;
05089
05090
05091 app = pbx_findapp("Directory");
05092 if (app) {
05093 char vmcontext[256];
05094
05095 memcpy(old_context, chan->context, sizeof(chan->context));
05096 memcpy(old_exten, chan->exten, sizeof(chan->exten));
05097 old_priority = chan->priority;
05098
05099
05100 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
05101 res = pbx_exec(chan, app, vmcontext);
05102
05103 ast_copy_string(username, chan->exten, sizeof(username));
05104
05105
05106 memcpy(chan->context, old_context, sizeof(chan->context));
05107 memcpy(chan->exten, old_exten, sizeof(chan->exten));
05108 chan->priority = old_priority;
05109
05110 } else {
05111 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
05112 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
05113 }
05114 } else {
05115
05116 res = ast_streamfile(chan, "vm-extension", chan->language);
05117 if (res)
05118 break;
05119 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
05120 break;
05121 }
05122
05123
05124 if (ast_strlen_zero(username))
05125 continue;
05126 stringp = username;
05127 s = strsep(&stringp, "*");
05128
05129 valid_extensions = 1;
05130 while (s) {
05131
05132 if ((flag == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
05133 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
05134 found++;
05135 } else {
05136 valid_extensions = 0;
05137 break;
05138 }
05139 s = strsep(&stringp, "*");
05140 }
05141
05142 if (valid_extensions)
05143 break;
05144
05145 res = ast_play_and_wait(chan, "pbx-invalid");
05146 }
05147
05148 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
05149 return res;
05150 if (flag==1) {
05151 struct leave_vm_options leave_options;
05152 char mailbox[AST_MAX_EXTENSION * 2 + 2];
05153
05154 if (context)
05155 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
05156 else
05157 ast_copy_string(mailbox, username, sizeof(mailbox));
05158
05159
05160 memset(&leave_options, 0, sizeof(leave_options));
05161 leave_options.record_gain = record_gain;
05162 cmd = leave_voicemail(chan, mailbox, &leave_options);
05163 } else {
05164
05165 long duration = 0;
05166 char origmsgfile[PATH_MAX], msgfile[PATH_MAX];
05167 struct vm_state vmstmp;
05168
05169 memcpy(&vmstmp, vms, sizeof(vmstmp));
05170
05171 make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg);
05172 create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp");
05173 make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg);
05174
05175 RETRIEVE(dir, curmsg, sender);
05176
05177
05178 copy_plain_file(origmsgfile, msgfile);
05179
05180 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05181 if (!cmd) {
05182 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05183 #ifdef IMAP_STORAGE
05184 char *myserveremail;
05185 int attach_user_voicemail;
05186
05187 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
05188 if (!dstvms) {
05189 dstvms = create_vm_state_from_user(vmtmp);
05190 }
05191 if (dstvms) {
05192 init_mailstream(dstvms, 0);
05193 if (!dstvms->mailstream) {
05194 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
05195 } else {
05196 STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05197 run_externnotify(vmtmp->context, vmtmp->mailbox);
05198 }
05199 } else {
05200 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
05201 }
05202 myserveremail = serveremail;
05203 if (!ast_strlen_zero(vmtmp->serveremail))
05204 myserveremail = vmtmp->serveremail;
05205 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05206
05207 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
05208 #else
05209 copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir);
05210 #endif
05211 saved_messages++;
05212 AST_LIST_REMOVE_CURRENT(&extensions, list);
05213 free_user(vmtmp);
05214 if (res)
05215 break;
05216 }
05217 AST_LIST_TRAVERSE_SAFE_END;
05218 if (saved_messages > 0) {
05219
05220
05221
05222
05223
05224
05225
05226
05227 res = ast_play_and_wait(chan, "vm-msgsaved");
05228 }
05229 }
05230
05231
05232 vm_delete(msgfile);
05233 DISPOSE(dir, curmsg);
05234 }
05235
05236
05237 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
05238 free_user(vmtmp);
05239 return res ? res : cmd;
05240 }
05241
05242 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05243 {
05244 int res;
05245 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
05246 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05247 return res;
05248 }
05249
05250 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05251 {
05252 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
05253 }
05254
05255 static int play_message_category(struct ast_channel *chan, const char *category)
05256 {
05257 int res = 0;
05258
05259 if (!ast_strlen_zero(category))
05260 res = ast_play_and_wait(chan, category);
05261
05262 if (res) {
05263 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05264 res = 0;
05265 }
05266
05267 return res;
05268 }
05269
05270 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05271 {
05272 int res = 0;
05273 struct vm_zone *the_zone = NULL;
05274 time_t t;
05275
05276 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05277 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05278 return 0;
05279 }
05280
05281
05282 if (!ast_strlen_zero(vmu->zonetag)) {
05283
05284 struct vm_zone *z;
05285 AST_LIST_LOCK(&zones);
05286 AST_LIST_TRAVERSE(&zones, z, list) {
05287 if (!strcmp(z->name, vmu->zonetag)) {
05288 the_zone = z;
05289 break;
05290 }
05291 }
05292 AST_LIST_UNLOCK(&zones);
05293 }
05294
05295
05296 #if 0
05297
05298 ast_localtime(&t, &time_now, NULL);
05299 tv_now = ast_tvnow();
05300 tnow = tv_now.tv_sec;
05301 ast_localtime(&tnow, &time_then, NULL);
05302
05303
05304 if (time_now.tm_year == time_then.tm_year)
05305 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
05306 else
05307 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05308 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05309
05310
05311 #endif
05312 if (the_zone)
05313 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05314 else if (!strncasecmp(chan->language,"pl",2))
05315 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05316 else if (!strncasecmp(chan->language,"se",2))
05317 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05318 else if (!strncasecmp(chan->language,"no",2))
05319 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05320 else if (!strncasecmp(chan->language,"de",2))
05321 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05322 else if (!strncasecmp(chan->language,"nl",2))
05323 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05324 else if (!strncasecmp(chan->language,"it",2))
05325 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);
05326 else if (!strncasecmp(chan->language,"gr",2))
05327 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05328 else if (!strcasecmp(chan->language,"pt_BR"))
05329 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);
05330 else if (!strcasecmp(chan->language,"he"))
05331 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'at2' kM", NULL);
05332 else
05333 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05334 #if 0
05335 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05336 #endif
05337 return res;
05338 }
05339
05340
05341
05342 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05343 {
05344 int res = 0;
05345 int i;
05346 char *callerid, *name;
05347 char prefile[PATH_MAX] = "";
05348
05349
05350
05351
05352 if ((cid == NULL)||(context == NULL))
05353 return res;
05354
05355
05356 if (option_debug > 2)
05357 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05358 ast_callerid_parse(cid, &name, &callerid);
05359 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05360
05361
05362 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
05363 if (option_debug > 2)
05364 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05365 if ((strcmp(cidinternalcontexts[i], context) == 0))
05366 break;
05367 }
05368 if (i != MAX_NUM_CID_CONTEXTS){
05369 if (!res) {
05370 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05371 if (!ast_strlen_zero(prefile)) {
05372
05373 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05374 if (option_verbose > 2)
05375 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05376 if (!callback)
05377 res = wait_file2(chan, vms, "vm-from");
05378 res = ast_stream_and_wait(chan, prefile, chan->language, "");
05379 } else {
05380 if (option_verbose > 2)
05381 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
05382
05383 if (!callback)
05384 res = wait_file2(chan, vms, "vm-from-extension");
05385 res = ast_say_digit_str(chan, callerid, "", chan->language);
05386 }
05387 }
05388 }
05389 }
05390
05391 else if (!res){
05392 if (option_debug > 2)
05393 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
05394
05395 if (!callback)
05396 res = wait_file2(chan, vms, "vm-from-phonenumber");
05397 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05398 }
05399 } else {
05400
05401 if (option_debug)
05402 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
05403
05404 res = wait_file2(chan, vms, "vm-unknown-caller");
05405 }
05406 return res;
05407 }
05408
05409 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05410 {
05411 int res = 0;
05412 int durationm;
05413 int durations;
05414
05415 if (duration == NULL)
05416 return res;
05417
05418
05419 durations=atoi(duration);
05420 durationm=(durations / 60);
05421
05422 if (option_debug > 2)
05423 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05424
05425 if ((!res) && (durationm >= minduration)) {
05426 res = wait_file2(chan, vms, "vm-duration");
05427
05428
05429 if (!strncasecmp(chan->language, "pl",2)) {
05430 div_t num = div(durationm, 10);
05431
05432 if (durationm == 1) {
05433 res = ast_play_and_wait(chan, "digits/1z");
05434 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05435 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05436 if (num.rem == 2) {
05437 if (!num.quot) {
05438 res = ast_play_and_wait(chan, "digits/2-ie");
05439 } else {
05440 res = say_and_wait(chan, durationm - 2 , chan->language);
05441 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05442 }
05443 } else {
05444 res = say_and_wait(chan, durationm, chan->language);
05445 }
05446 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05447 } else {
05448 res = say_and_wait(chan, durationm, chan->language);
05449 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05450 }
05451
05452 } else {
05453 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05454 res = wait_file2(chan, vms, "vm-minutes");
05455 }
05456 }
05457 return res;
05458 }
05459
05460 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05461 {
05462 int res = 0;
05463 char filename[256], *cid;
05464 const char *origtime, *context, *category, *duration;
05465 struct ast_config *msg_cfg;
05466
05467 vms->starting = 0;
05468 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05469 adsi_message(chan, vms);
05470 if (!strcasecmp(chan->language, "he")) {
05471
05472
05473
05474
05475 if (!vms->curmsg) {
05476 res = wait_file2(chan, vms, "vm-message");
05477 res = wait_file2(chan, vms, "vm-first");
05478 } else if (vms->curmsg == vms->lastmsg) {
05479 res = wait_file2(chan, vms, "vm-message");
05480 res = wait_file2(chan, vms, "vm-last");
05481 } else {
05482 res = wait_file2(chan, vms, "vm-message");
05483 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05484 ast_log(LOG_DEBUG, "curmsg: %d\n", vms->curmsg);
05485 ast_log(LOG_DEBUG, "lagmsg: %d\n", vms->lastmsg);
05486 if (!res) {
05487 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
05488 }
05489 }
05490 }
05491 } else {
05492 if (!vms->curmsg)
05493 res = wait_file2(chan, vms, "vm-first");
05494 else if (vms->curmsg == vms->lastmsg)
05495 res = wait_file2(chan, vms, "vm-last");
05496 }
05497 if (!res) {
05498
05499 if (!strncasecmp(chan->language, "pl",2)) {
05500 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05501 int ten, one;
05502 char nextmsg[256];
05503 ten = (vms->curmsg + 1) / 10;
05504 one = (vms->curmsg + 1) % 10;
05505
05506 if (vms->curmsg < 20) {
05507 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
05508 res = wait_file2(chan, vms, nextmsg);
05509 } else {
05510 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
05511 res = wait_file2(chan, vms, nextmsg);
05512 if (one > 0) {
05513 if (!res) {
05514 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
05515 res = wait_file2(chan, vms, nextmsg);
05516 }
05517 }
05518 }
05519 }
05520 if (!res)
05521 res = wait_file2(chan, vms, "vm-message");
05522 } else {
05523 if (!strncasecmp(chan->language,"se",2))
05524 res = wait_file2(chan, vms, "vm-meddelandet");
05525 else
05526 res = wait_file2(chan, vms, "vm-message");
05527 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05528 if (!res)
05529 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
05530 }
05531 }
05532 }
05533
05534
05535 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
05536 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
05537 RETRIEVE(vms->curdir, vms->curmsg, vmu);
05538 msg_cfg = ast_config_load(filename);
05539 if (!msg_cfg) {
05540 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
05541 return 0;
05542 }
05543
05544 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
05545 ast_log(LOG_WARNING, "No origtime?!\n");
05546 DISPOSE(vms->curdir, vms->curmsg);
05547 ast_config_destroy(msg_cfg);
05548 return 0;
05549 }
05550
05551 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
05552 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
05553 category = ast_variable_retrieve(msg_cfg, "message", "category");
05554
05555 context = ast_variable_retrieve(msg_cfg, "message", "context");
05556 if (!strncasecmp("macro",context,5))
05557 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
05558 if (!res)
05559 res = play_message_category(chan, category);
05560 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
05561 res = play_message_datetime(chan, vmu, origtime, filename);
05562 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
05563 res = play_message_callerid(chan, vms, cid, context, 0);
05564 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
05565 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
05566
05567 if (res == '1')
05568 res = 0;
05569 ast_config_destroy(msg_cfg);
05570
05571 if (!res) {
05572 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05573 vms->heard[vms->curmsg] = 1;
05574 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
05575 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
05576 res = 0;
05577 }
05578 }
05579 DISPOSE(vms->curdir, vms->curmsg);
05580 return res;
05581 }
05582
05583 #ifndef IMAP_STORAGE
05584 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
05585 {
05586 int res = 0;
05587 int count_msg, last_msg;
05588
05589 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
05590
05591
05592
05593
05594 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
05595
05596
05597 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
05598
05599 count_msg = count_messages(vmu, vms->curdir);
05600 if (count_msg < 0)
05601 return count_msg;
05602 else
05603 vms->lastmsg = count_msg - 1;
05604
05605
05606
05607
05608
05609
05610
05611
05612 last_msg = last_message_index(vmu, vms->curdir);
05613 if (last_msg < 0)
05614 return last_msg;
05615 else if (vms->lastmsg != last_msg)
05616 {
05617 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
05618 res = resequence_mailbox(vmu, vms->curdir);
05619 if (res)
05620 return res;
05621 }
05622
05623 return 0;
05624 }
05625 #endif
05626
05627 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
05628 {
05629 int x = 0;
05630 #ifndef IMAP_STORAGE
05631 int res = 0, nummsg;
05632 #endif
05633
05634 if (vms->lastmsg <= -1)
05635 goto done;
05636
05637 vms->curmsg = -1;
05638 #ifndef IMAP_STORAGE
05639
05640 if (vm_lock_path(vms->curdir))
05641 return ERROR_LOCK_PATH;
05642
05643 for (x = 0; x < vmu->maxmsg; x++) {
05644 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
05645
05646 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
05647 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
05648 break;
05649 vms->curmsg++;
05650 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
05651 if (strcmp(vms->fn, vms->fn2)) {
05652 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
05653 }
05654 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
05655
05656 res = save_to_folder(vmu, vms, x, 1);
05657 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
05658
05659 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
05660 vms->deleted[x] = 0;
05661 vms->heard[x] = 0;
05662 --x;
05663 }
05664 }
05665 }
05666
05667
05668 nummsg = x - 1;
05669 for (x = vms->curmsg + 1; x <= nummsg; x++) {
05670 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
05671 if (EXISTS(vms->curdir, x, vms->fn, NULL))
05672 DELETE(vms->curdir, x, vms->fn, vmu);
05673 }
05674 ast_unlock_path(vms->curdir);
05675 #else
05676 if (vms->deleted) {
05677 for (x=0;x < vmu->maxmsg;x++) {
05678 if (vms->deleted[x]) {
05679 if (option_debug > 2)
05680 ast_log(LOG_DEBUG,"IMAP delete of %d\n",x);
05681 DELETE(vms->curdir, x, vms->fn, vmu);
05682 }
05683 }
05684 }
05685 #endif
05686
05687 done:
05688 if (vms->deleted)
05689 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
05690 if (vms->heard)
05691 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
05692
05693 return 0;
05694 }
05695
05696
05697
05698
05699
05700
05701
05702 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
05703 {
05704 int cmd;
05705 char *buf;
05706
05707 buf = alloca(strlen(mbox)+2);
05708 strcpy(buf, mbox);
05709 strcat(buf,"s");
05710
05711 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
05712 cmd = ast_play_and_wait(chan, buf);
05713 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05714 } else {
05715 cmd = ast_play_and_wait(chan, "vm-messages");
05716 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05717 }
05718 }
05719
05720 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
05721 {
05722 int cmd;
05723
05724 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
05725 if (!strcasecmp(mbox, "vm-INBOX"))
05726 cmd = ast_play_and_wait(chan, "vm-new-e");
05727 else
05728 cmd = ast_play_and_wait(chan, "vm-old-e");
05729 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05730 } else {
05731 cmd = ast_play_and_wait(chan, "vm-messages");
05732 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05733 }
05734 }
05735
05736 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
05737 {
05738 int cmd;
05739
05740 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
05741 cmd = ast_play_and_wait(chan, "vm-messages");
05742 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05743 } else {
05744 cmd = ast_play_and_wait(chan, mbox);
05745 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05746 }
05747 }
05748
05749 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
05750 {
05751 int cmd;
05752
05753 if (!strncasecmp(chan->language, "it", 2) || !strncasecmp(chan->language, "es", 2) || !strncasecmp(chan->language, "fr", 2) || !strncasecmp(chan->language, "pt", 2)) {
05754 cmd = ast_play_and_wait(chan, "vm-messages");
05755 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05756 } else if (!strncasecmp(chan->language, "gr", 2)){
05757 return vm_play_folder_name_gr(chan, mbox);
05758 } else if (!strncasecmp(chan->language, "pl", 2)){
05759 return vm_play_folder_name_pl(chan, mbox);
05760 } else if (!strncasecmp(chan->language, "ua", 2)){
05761 return vm_play_folder_name_ua(chan, mbox);
05762 } else if (!strcasecmp(chan->language, "he")){
05763 cmd = ast_play_and_wait(chan, mbox);
05764 return cmd;
05765 } else {
05766 cmd = ast_play_and_wait(chan, mbox);
05767 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05768 }
05769 }
05770
05771
05772
05773
05774
05775
05776
05777
05778
05779
05780
05781
05782
05783 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
05784 {
05785 int res = 0;
05786
05787 if (vms->newmessages) {
05788 res = ast_play_and_wait(chan, "vm-youhave");
05789 if (!res)
05790 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
05791 if (!res) {
05792 if ((vms->newmessages == 1)) {
05793 res = ast_play_and_wait(chan, "vm-INBOX");
05794 if (!res)
05795 res = ast_play_and_wait(chan, "vm-message");
05796 } else {
05797 res = ast_play_and_wait(chan, "vm-INBOXs");
05798 if (!res)
05799 res = ast_play_and_wait(chan, "vm-messages");
05800 }
05801 }
05802 } else if (vms->oldmessages){
05803 res = ast_play_and_wait(chan, "vm-youhave");
05804 if (!res)
05805 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
05806 if ((vms->oldmessages == 1)){
05807 res = ast_play_and_wait(chan, "vm-Old");
05808 if (!res)
05809 res = ast_play_and_wait(chan, "vm-message");
05810 } else {
05811 res = ast_play_and_wait(chan, "vm-Olds");
05812 if (!res)
05813 res = ast_play_and_wait(chan, "vm-messages");
05814 }
05815 } else if (!vms->oldmessages && !vms->newmessages)
05816 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
05817 return res;
05818 }
05819
05820
05821 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
05822 {
05823 int res;
05824
05825
05826 res = ast_play_and_wait(chan, "vm-youhave");
05827 if (!res) {
05828 if (vms->newmessages) {
05829 res = say_and_wait(chan, vms->newmessages, chan->language);
05830 if (!res)
05831 res = ast_play_and_wait(chan, "vm-INBOX");
05832 if (vms->oldmessages && !res)
05833 res = ast_play_and_wait(chan, "vm-and");
05834 else if (!res) {
05835 if ((vms->newmessages == 1))
05836 res = ast_play_and_wait(chan, "vm-message");
05837 else
05838 res = ast_play_and_wait(chan, "vm-messages");
05839 }
05840
05841 }
05842 if (!res && vms->oldmessages) {
05843 res = say_and_wait(chan, vms->oldmessages, chan->language);
05844 if (!res)
05845 res = ast_play_and_wait(chan, "vm-Old");
05846 if (!res) {
05847 if (vms->oldmessages == 1)
05848 res = ast_play_and_wait(chan, "vm-message");
05849 else
05850 res = ast_play_and_wait(chan, "vm-messages");
05851 }
05852 }
05853 if (!res) {
05854 if (!vms->oldmessages && !vms->newmessages) {
05855 res = ast_play_and_wait(chan, "vm-no");
05856 if (!res)
05857 res = ast_play_and_wait(chan, "vm-messages");
05858 }
05859 }
05860 }
05861 return res;
05862 }
05863
05864
05865 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
05866 {
05867 int res=0;
05868
05869
05870 if (!res) {
05871 if ((vms->newmessages) || (vms->oldmessages)) {
05872 res = ast_play_and_wait(chan, "vm-youhave");
05873 }
05874
05875
05876
05877
05878
05879 if (vms->newmessages) {
05880 if (!res) {
05881 if (vms->newmessages == 1) {
05882 res = ast_play_and_wait(chan, "vm-INBOX1");
05883 } else {
05884 if (vms->newmessages == 2) {
05885 res = ast_play_and_wait(chan, "vm-shtei");
05886 } else {
05887 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
05888 }
05889 res = ast_play_and_wait(chan, "vm-INBOX");
05890 }
05891 }
05892 if (vms->oldmessages && !res) {
05893 res = ast_play_and_wait(chan, "vm-and");
05894 if (vms->oldmessages == 1) {
05895 res = ast_play_and_wait(chan, "vm-Old1");
05896 } else {
05897 if (vms->oldmessages == 2) {
05898 res = ast_play_and_wait(chan, "vm-shtei");
05899 } else {
05900 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
05901 }
05902 res = ast_play_and_wait(chan, "vm-Old");
05903 }
05904 }
05905 }
05906 if (!res && vms->oldmessages && !vms->newmessages) {
05907 if (!res) {
05908 if (vms->oldmessages == 1) {
05909 res = ast_play_and_wait(chan, "vm-Old1");
05910 } else {
05911 if (vms->oldmessages == 2) {
05912 res = ast_play_and_wait(chan, "vm-shtei");
05913 } else {
05914 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
05915 }
05916 res = ast_play_and_wait(chan, "vm-Old");
05917 }
05918 }
05919 }
05920 if (!res) {
05921 if (!vms->oldmessages && !vms->newmessages) {
05922 if (!res) {
05923 res = ast_play_and_wait(chan, "vm-nomessages");
05924 }
05925 }
05926 }
05927 }
05928 return res;
05929 }
05930
05931
05932
05933 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
05934 {
05935
05936 int res;
05937 if (!vms->oldmessages && !vms->newmessages)
05938 res = ast_play_and_wait(chan, "vm-no") ||
05939 ast_play_and_wait(chan, "vm-message");
05940 else
05941 res = ast_play_and_wait(chan, "vm-youhave");
05942 if (!res && vms->newmessages) {
05943 res = (vms->newmessages == 1) ?
05944 ast_play_and_wait(chan, "digits/un") ||
05945 ast_play_and_wait(chan, "vm-nuovo") ||
05946 ast_play_and_wait(chan, "vm-message") :
05947
05948 say_and_wait(chan, vms->newmessages, chan->language) ||
05949 ast_play_and_wait(chan, "vm-nuovi") ||
05950 ast_play_and_wait(chan, "vm-messages");
05951 if (!res && vms->oldmessages)
05952 res = ast_play_and_wait(chan, "vm-and");
05953 }
05954 if (!res && vms->oldmessages) {
05955 res = (vms->oldmessages == 1) ?
05956 ast_play_and_wait(chan, "digits/un") ||
05957 ast_play_and_wait(chan, "vm-vecchio") ||
05958 ast_play_and_wait(chan, "vm-message") :
05959
05960 say_and_wait(chan, vms->oldmessages, chan->language) ||
05961 ast_play_and_wait(chan, "vm-vecchi") ||
05962 ast_play_and_wait(chan, "vm-messages");
05963 }
05964 return res;
05965 }
05966
05967
05968 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
05969 {
05970
05971 int res;
05972 div_t num;
05973
05974 if (!vms->oldmessages && !vms->newmessages) {
05975 res = ast_play_and_wait(chan, "vm-no");
05976 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05977 return res;
05978 } else {
05979 res = ast_play_and_wait(chan, "vm-youhave");
05980 }
05981
05982 if (vms->newmessages) {
05983 num = div(vms->newmessages, 10);
05984 if (vms->newmessages == 1) {
05985 res = ast_play_and_wait(chan, "digits/1-a");
05986 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
05987 res = res ? res : ast_play_and_wait(chan, "vm-message");
05988 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05989 if (num.rem == 2) {
05990 if (!num.quot) {
05991 res = ast_play_and_wait(chan, "digits/2-ie");
05992 } else {
05993 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
05994 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05995 }
05996 } else {
05997 res = say_and_wait(chan, vms->newmessages, chan->language);
05998 }
05999 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
06000 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06001 } else {
06002 res = say_and_wait(chan, vms->newmessages, chan->language);
06003 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
06004 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06005 }
06006 if (!res && vms->oldmessages)
06007 res = ast_play_and_wait(chan, "vm-and");
06008 }
06009 if (!res && vms->oldmessages) {
06010 num = div(vms->oldmessages, 10);
06011 if (vms->oldmessages == 1) {
06012 res = ast_play_and_wait(chan, "digits/1-a");
06013 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
06014 res = res ? res : ast_play_and_wait(chan, "vm-message");
06015 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06016 if (num.rem == 2) {
06017 if (!num.quot) {
06018 res = ast_play_and_wait(chan, "digits/2-ie");
06019 } else {
06020 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
06021 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06022 }
06023 } else {
06024 res = say_and_wait(chan, vms->oldmessages, chan->language);
06025 }
06026 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
06027 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06028 } else {
06029 res = say_and_wait(chan, vms->oldmessages, chan->language);
06030 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
06031 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06032 }
06033 }
06034
06035 return res;
06036 }
06037
06038
06039 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
06040 {
06041
06042 int res;
06043
06044 res = ast_play_and_wait(chan, "vm-youhave");
06045 if (res)
06046 return res;
06047
06048 if (!vms->oldmessages && !vms->newmessages) {
06049 res = ast_play_and_wait(chan, "vm-no");
06050 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06051 return res;
06052 }
06053
06054 if (vms->newmessages) {
06055 if ((vms->newmessages == 1)) {
06056 res = ast_play_and_wait(chan, "digits/ett");
06057 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
06058 res = res ? res : ast_play_and_wait(chan, "vm-message");
06059 } else {
06060 res = say_and_wait(chan, vms->newmessages, chan->language);
06061 res = res ? res : ast_play_and_wait(chan, "vm-nya");
06062 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06063 }
06064 if (!res && vms->oldmessages)
06065 res = ast_play_and_wait(chan, "vm-and");
06066 }
06067 if (!res && vms->oldmessages) {
06068 if (vms->oldmessages == 1) {
06069 res = ast_play_and_wait(chan, "digits/ett");
06070 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
06071 res = res ? res : ast_play_and_wait(chan, "vm-message");
06072 } else {
06073 res = say_and_wait(chan, vms->oldmessages, chan->language);
06074 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
06075 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06076 }
06077 }
06078
06079 return res;
06080 }
06081
06082
06083 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
06084 {
06085
06086 int res;
06087
06088 res = ast_play_and_wait(chan, "vm-youhave");
06089 if (res)
06090 return res;
06091
06092 if (!vms->oldmessages && !vms->newmessages) {
06093 res = ast_play_and_wait(chan, "vm-no");
06094 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06095 return res;
06096 }
06097
06098 if (vms->newmessages) {
06099 if ((vms->newmessages == 1)) {
06100 res = ast_play_and_wait(chan, "digits/1");
06101 res = res ? res : ast_play_and_wait(chan, "vm-ny");
06102 res = res ? res : ast_play_and_wait(chan, "vm-message");
06103 } else {
06104 res = say_and_wait(chan, vms->newmessages, chan->language);
06105 res = res ? res : ast_play_and_wait(chan, "vm-nye");
06106 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06107 }
06108 if (!res && vms->oldmessages)
06109 res = ast_play_and_wait(chan, "vm-and");
06110 }
06111 if (!res && vms->oldmessages) {
06112 if (vms->oldmessages == 1) {
06113 res = ast_play_and_wait(chan, "digits/1");
06114 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
06115 res = res ? res : ast_play_and_wait(chan, "vm-message");
06116 } else {
06117 res = say_and_wait(chan, vms->oldmessages, chan->language);
06118 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
06119 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06120 }
06121 }
06122
06123 return res;
06124 }
06125
06126
06127 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
06128 {
06129
06130 int res;
06131 res = ast_play_and_wait(chan, "vm-youhave");
06132 if (!res) {
06133 if (vms->newmessages) {
06134 if ((vms->newmessages == 1))
06135 res = ast_play_and_wait(chan, "digits/1F");
06136 else
06137 res = say_and_wait(chan, vms->newmessages, chan->language);
06138 if (!res)
06139 res = ast_play_and_wait(chan, "vm-INBOX");
06140 if (vms->oldmessages && !res)
06141 res = ast_play_and_wait(chan, "vm-and");
06142 else if (!res) {
06143 if ((vms->newmessages == 1))
06144 res = ast_play_and_wait(chan, "vm-message");
06145 else
06146 res = ast_play_and_wait(chan, "vm-messages");
06147 }
06148
06149 }
06150 if (!res && vms->oldmessages) {
06151 if (vms->oldmessages == 1)
06152 res = ast_play_and_wait(chan, "digits/1F");
06153 else
06154 res = say_and_wait(chan, vms->oldmessages, chan->language);
06155 if (!res)
06156 res = ast_play_and_wait(chan, "vm-Old");
06157 if (!res) {
06158 if (vms->oldmessages == 1)
06159 res = ast_play_and_wait(chan, "vm-message");
06160 else
06161 res = ast_play_and_wait(chan, "vm-messages");
06162 }
06163 }
06164 if (!res) {
06165 if (!vms->oldmessages && !vms->newmessages) {
06166 res = ast_play_and_wait(chan, "vm-no");
06167 if (!res)
06168 res = ast_play_and_wait(chan, "vm-messages");
06169 }
06170 }
06171 }
06172 return res;
06173 }
06174
06175
06176 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
06177 {
06178
06179 int res;
06180 if (!vms->oldmessages && !vms->newmessages) {
06181 res = ast_play_and_wait(chan, "vm-youhaveno");
06182 if (!res)
06183 res = ast_play_and_wait(chan, "vm-messages");
06184 } else {
06185 res = ast_play_and_wait(chan, "vm-youhave");
06186 }
06187 if (!res) {
06188 if (vms->newmessages) {
06189 if (!res) {
06190 if ((vms->newmessages == 1)) {
06191 res = ast_play_and_wait(chan, "digits/1M");
06192 if (!res)
06193 res = ast_play_and_wait(chan, "vm-message");
06194 if (!res)
06195 res = ast_play_and_wait(chan, "vm-INBOXs");
06196 } else {
06197 res = say_and_wait(chan, vms->newmessages, chan->language);
06198 if (!res)
06199 res = ast_play_and_wait(chan, "vm-messages");
06200 if (!res)
06201 res = ast_play_and_wait(chan, "vm-INBOX");
06202 }
06203 }
06204 if (vms->oldmessages && !res)
06205 res = ast_play_and_wait(chan, "vm-and");
06206 }
06207 if (vms->oldmessages) {
06208 if (!res) {
06209 if (vms->oldmessages == 1) {
06210 res = ast_play_and_wait(chan, "digits/1M");
06211 if (!res)
06212 res = ast_play_and_wait(chan, "vm-message");
06213 if (!res)
06214 res = ast_play_and_wait(chan, "vm-Olds");
06215 } else {
06216 res = say_and_wait(chan, vms->oldmessages, chan->language);
06217 if (!res)
06218 res = ast_play_and_wait(chan, "vm-messages");
06219 if (!res)
06220 res = ast_play_and_wait(chan, "vm-Old");
06221 }
06222 }
06223 }
06224 }
06225 return res;
06226 }
06227
06228
06229 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
06230
06231 int res;
06232 if (!vms->oldmessages && !vms->newmessages) {
06233 res = ast_play_and_wait(chan, "vm-nomessages");
06234 return res;
06235 }
06236 else {
06237 res = ast_play_and_wait(chan, "vm-youhave");
06238 }
06239 if (vms->newmessages) {
06240 if (!res)
06241 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06242 if ((vms->newmessages == 1)) {
06243 if (!res)
06244 res = ast_play_and_wait(chan, "vm-message");
06245 if (!res)
06246 res = ast_play_and_wait(chan, "vm-INBOXs");
06247 }
06248 else {
06249 if (!res)
06250 res = ast_play_and_wait(chan, "vm-messages");
06251 if (!res)
06252 res = ast_play_and_wait(chan, "vm-INBOX");
06253 }
06254 if (vms->oldmessages && !res)
06255 res = ast_play_and_wait(chan, "vm-and");
06256 }
06257 if (vms->oldmessages) {
06258 if (!res)
06259 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06260 if (vms->oldmessages == 1) {
06261 if (!res)
06262 res = ast_play_and_wait(chan, "vm-message");
06263 if (!res)
06264 res = ast_play_and_wait(chan, "vm-Olds");
06265 }
06266 else {
06267 if (!res)
06268 res = ast_play_and_wait(chan, "vm-messages");
06269 if (!res)
06270 res = ast_play_and_wait(chan, "vm-Old");
06271 }
06272 }
06273 return res;
06274 }
06275
06276
06277 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
06278 {
06279
06280 int res;
06281 res = ast_play_and_wait(chan, "vm-youhave");
06282 if (!res) {
06283 if (vms->newmessages) {
06284 res = say_and_wait(chan, vms->newmessages, chan->language);
06285 if (!res)
06286 res = ast_play_and_wait(chan, "vm-INBOX");
06287 if (vms->oldmessages && !res)
06288 res = ast_play_and_wait(chan, "vm-and");
06289 else if (!res) {
06290 if ((vms->newmessages == 1))
06291 res = ast_play_and_wait(chan, "vm-message");
06292 else
06293 res = ast_play_and_wait(chan, "vm-messages");
06294 }
06295
06296 }
06297 if (!res && vms->oldmessages) {
06298 res = say_and_wait(chan, vms->oldmessages, chan->language);
06299 if (!res)
06300 res = ast_play_and_wait(chan, "vm-Old");
06301 if (!res) {
06302 if (vms->oldmessages == 1)
06303 res = ast_play_and_wait(chan, "vm-message");
06304 else
06305 res = ast_play_and_wait(chan, "vm-messages");
06306 }
06307 }
06308 if (!res) {
06309 if (!vms->oldmessages && !vms->newmessages) {
06310 res = ast_play_and_wait(chan, "vm-no");
06311 if (!res)
06312 res = ast_play_and_wait(chan, "vm-messages");
06313 }
06314 }
06315 }
06316 return res;
06317 }
06318
06319
06320 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
06321 {
06322
06323 int res;
06324 res = ast_play_and_wait(chan, "vm-youhave");
06325 if (!res) {
06326 if (vms->newmessages) {
06327 res = say_and_wait(chan, vms->newmessages, chan->language);
06328 if (!res) {
06329 if (vms->newmessages == 1)
06330 res = ast_play_and_wait(chan, "vm-INBOXs");
06331 else
06332 res = ast_play_and_wait(chan, "vm-INBOX");
06333 }
06334 if (vms->oldmessages && !res)
06335 res = ast_play_and_wait(chan, "vm-and");
06336 else if (!res) {
06337 if ((vms->newmessages == 1))
06338 res = ast_play_and_wait(chan, "vm-message");
06339 else
06340 res = ast_play_and_wait(chan, "vm-messages");
06341 }
06342
06343 }
06344 if (!res && vms->oldmessages) {
06345 res = say_and_wait(chan, vms->oldmessages, chan->language);
06346 if (!res) {
06347 if (vms->oldmessages == 1)
06348 res = ast_play_and_wait(chan, "vm-Olds");
06349 else
06350 res = ast_play_and_wait(chan, "vm-Old");
06351 }
06352 if (!res) {
06353 if (vms->oldmessages == 1)
06354 res = ast_play_and_wait(chan, "vm-message");
06355 else
06356 res = ast_play_and_wait(chan, "vm-messages");
06357 }
06358 }
06359 if (!res) {
06360 if (!vms->oldmessages && !vms->newmessages) {
06361 res = ast_play_and_wait(chan, "vm-no");
06362 if (!res)
06363 res = ast_play_and_wait(chan, "vm-messages");
06364 }
06365 }
06366 }
06367 return res;
06368 }
06369
06370
06371 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
06372 {
06373
06374 int res;
06375 res = ast_play_and_wait(chan, "vm-youhave");
06376 if (!res) {
06377 if (vms->newmessages) {
06378 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06379 if (!res) {
06380 if ((vms->newmessages == 1)) {
06381 res = ast_play_and_wait(chan, "vm-message");
06382 if (!res)
06383 res = ast_play_and_wait(chan, "vm-INBOXs");
06384 } else {
06385 res = ast_play_and_wait(chan, "vm-messages");
06386 if (!res)
06387 res = ast_play_and_wait(chan, "vm-INBOX");
06388 }
06389 }
06390 if (vms->oldmessages && !res)
06391 res = ast_play_and_wait(chan, "vm-and");
06392 }
06393 if (!res && vms->oldmessages) {
06394 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06395 if (!res) {
06396 if (vms->oldmessages == 1) {
06397 res = ast_play_and_wait(chan, "vm-message");
06398 if (!res)
06399 res = ast_play_and_wait(chan, "vm-Olds");
06400 } else {
06401 res = ast_play_and_wait(chan, "vm-messages");
06402 if (!res)
06403 res = ast_play_and_wait(chan, "vm-Old");
06404 }
06405 }
06406 }
06407 if (!res) {
06408 if (!vms->oldmessages && !vms->newmessages) {
06409 res = ast_play_and_wait(chan, "vm-no");
06410 if (!res)
06411 res = ast_play_and_wait(chan, "vm-messages");
06412 }
06413 }
06414 }
06415 return res;
06416 }
06417
06418
06419
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429
06430
06431
06432
06433
06434 static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
06435 {
06436 int res;
06437 res = ast_play_and_wait(chan, "vm-youhave");
06438 if (!res) {
06439 if (vms->newmessages) {
06440 if (vms->newmessages == 1) {
06441 res = ast_play_and_wait(chan, "digits/jednu");
06442 } else {
06443 res = say_and_wait(chan, vms->newmessages, chan->language);
06444 }
06445 if (!res) {
06446 if ((vms->newmessages == 1))
06447 res = ast_play_and_wait(chan, "vm-novou");
06448 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
06449 res = ast_play_and_wait(chan, "vm-nove");
06450 if (vms->newmessages > 4)
06451 res = ast_play_and_wait(chan, "vm-novych");
06452 }
06453 if (vms->oldmessages && !res)
06454 res = ast_play_and_wait(chan, "vm-and");
06455 else if (!res) {
06456 if ((vms->newmessages == 1))
06457 res = ast_play_and_wait(chan, "vm-zpravu");
06458 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
06459 res = ast_play_and_wait(chan, "vm-zpravy");
06460 if (vms->newmessages > 4)
06461 res = ast_play_and_wait(chan, "vm-zprav");
06462 }
06463 }
06464 if (!res && vms->oldmessages) {
06465 res = say_and_wait(chan, vms->oldmessages, chan->language);
06466 if (!res) {
06467 if ((vms->oldmessages == 1))
06468 res = ast_play_and_wait(chan, "vm-starou");
06469 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
06470 res = ast_play_and_wait(chan, "vm-stare");
06471 if (vms->oldmessages > 4)
06472 res = ast_play_and_wait(chan, "vm-starych");
06473 }
06474 if (!res) {
06475 if ((vms->oldmessages == 1))
06476 res = ast_play_and_wait(chan, "vm-zpravu");
06477 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
06478 res = ast_play_and_wait(chan, "vm-zpravy");
06479 if (vms->oldmessages > 4)
06480 res = ast_play_and_wait(chan, "vm-zprav");
06481 }
06482 }
06483 if (!res) {
06484 if (!vms->oldmessages && !vms->newmessages) {
06485 res = ast_play_and_wait(chan, "vm-no");
06486 if (!res)
06487 res = ast_play_and_wait(chan, "vm-zpravy");
06488 }
06489 }
06490 }
06491 return res;
06492 }
06493
06494 static int get_lastdigits(int num)
06495 {
06496 num %= 100;
06497 return (num < 20) ? num : num % 10;
06498 }
06499
06500 static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
06501 {
06502 int res;
06503 int lastnum = 0;
06504 int dcnum;
06505
06506 res = ast_play_and_wait(chan, "vm-youhave");
06507 if (!res && vms->newmessages) {
06508 lastnum = get_lastdigits(vms->newmessages);
06509 dcnum = vms->newmessages - lastnum;
06510 if (dcnum)
06511 res = say_and_wait(chan, dcnum, chan->language);
06512 if (!res && lastnum) {
06513 if (lastnum == 1)
06514 res = ast_play_and_wait(chan, "digits/odno");
06515 else
06516 res = say_and_wait(chan, lastnum, chan->language);
06517 }
06518
06519 if (!res)
06520 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-novoe" : "vm-novyh");
06521
06522 if (!res && vms->oldmessages)
06523 res = ast_play_and_wait(chan, "vm-and");
06524 }
06525
06526 if (!res && vms->oldmessages) {
06527 lastnum = get_lastdigits(vms->oldmessages);
06528 dcnum = vms->oldmessages - lastnum;
06529 if (dcnum)
06530 res = say_and_wait(chan, dcnum, chan->language);
06531 if (!res && lastnum) {
06532 if (lastnum == 1)
06533 res = ast_play_and_wait(chan, "digits/odno");
06534 else
06535 res = say_and_wait(chan, lastnum, chan->language);
06536 }
06537
06538 if (!res)
06539 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-staroe" : "vm-staryh");
06540 }
06541
06542 if (!res && !vms->newmessages && !vms->oldmessages) {
06543 lastnum = 0;
06544 res = ast_play_and_wait(chan, "vm-no");
06545 }
06546
06547 if (!res) {
06548 switch (lastnum) {
06549 case 1:
06550 res = ast_play_and_wait(chan, "vm-soobshenie");
06551 break;
06552 case 2:
06553 case 3:
06554 case 4:
06555 res = ast_play_and_wait(chan, "vm-soobsheniya");
06556 break;
06557 default:
06558 res = ast_play_and_wait(chan, "vm-soobsheniy");
06559 break;
06560 }
06561 }
06562
06563 return res;
06564 }
06565
06566
06567
06568
06569
06570
06571
06572
06573
06574 static int vm_intro_ua(struct ast_channel *chan,struct vm_state *vms)
06575 {
06576 int res;
06577 int lastnum = 0;
06578 int dcnum;
06579
06580 res = ast_play_and_wait(chan, "vm-youhave");
06581 if (!res && vms->newmessages) {
06582 lastnum = get_lastdigits(vms->newmessages);
06583 dcnum = vms->newmessages - lastnum;
06584 if (dcnum)
06585 res = say_and_wait(chan, dcnum, chan->language);
06586 if (!res && lastnum) {
06587 if (lastnum == 1)
06588 res = ast_play_and_wait(chan, "digits/ua/1e");
06589 else
06590 res = say_and_wait(chan, lastnum, chan->language);
06591 }
06592
06593 if (!res)
06594 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-nove" : "vm-INBOX");
06595
06596 if (!res && vms->oldmessages)
06597 res = ast_play_and_wait(chan, "vm-and");
06598 }
06599
06600 if (!res && vms->oldmessages) {
06601 lastnum = get_lastdigits(vms->oldmessages);
06602 dcnum = vms->oldmessages - lastnum;
06603 if (dcnum)
06604 res = say_and_wait(chan, dcnum, chan->language);
06605 if (!res && lastnum) {
06606 if (lastnum == 1)
06607 res = ast_play_and_wait(chan, "digits/ua/1e");
06608 else
06609 res = say_and_wait(chan, lastnum, chan->language);
06610 }
06611
06612 if (!res)
06613 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-stare" : "vm-Old");
06614 }
06615
06616 if (!res && !vms->newmessages && !vms->oldmessages) {
06617 lastnum = 0;
06618 res = ast_play_and_wait(chan, "vm-no");
06619 }
06620
06621 if (!res) {
06622 switch (lastnum) {
06623 case 1:
06624 case 2:
06625 case 3:
06626 case 4:
06627 res = ast_play_and_wait(chan, "vm-message");
06628 break;
06629 default:
06630 res = ast_play_and_wait(chan, "vm-messages");
06631 break;
06632 }
06633 }
06634
06635 return res;
06636 }
06637
06638
06639 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06640 {
06641 char prefile[256];
06642
06643
06644 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06645 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
06646 RETRIEVE(prefile, -1, vmu);
06647 if (ast_fileexists(prefile, NULL, NULL) > 0)
06648 ast_play_and_wait(chan, "vm-tempgreetactive");
06649 DISPOSE(prefile, -1);
06650 }
06651
06652
06653 if (!strncasecmp(chan->language, "de", 2)) {
06654 return vm_intro_de(chan, vms);
06655 } else if (!strncasecmp(chan->language, "es", 2)) {
06656 return vm_intro_es(chan, vms);
06657 } else if (!strncasecmp(chan->language, "it", 2)) {
06658 return vm_intro_it(chan, vms);
06659 } else if (!strncasecmp(chan->language, "fr", 2)) {
06660 return vm_intro_fr(chan, vms);
06661 } else if (!strncasecmp(chan->language, "nl", 2)) {
06662 return vm_intro_nl(chan, vms);
06663 } else if (!strcasecmp(chan->language, "pt_BR")) {
06664 return vm_intro_pt_BR(chan, vms);
06665 } else if (!strncasecmp(chan->language, "pt", 2)) {
06666 return vm_intro_pt(chan, vms);
06667 } else if (!strncasecmp(chan->language, "cz", 2)) {
06668 return vm_intro_cz(chan, vms);
06669 } else if (!strncasecmp(chan->language, "gr", 2)) {
06670 return vm_intro_gr(chan, vms);
06671 } else if (!strncasecmp(chan->language, "pl", 2)) {
06672 return vm_intro_pl(chan, vms);
06673 } else if (!strncasecmp(chan->language, "se", 2)) {
06674 return vm_intro_se(chan, vms);
06675 } else if (!strncasecmp(chan->language, "no", 2)) {
06676 return vm_intro_no(chan, vms);
06677 } else if (!strncasecmp(chan->language, "ru", 2)) {
06678 return vm_intro_ru(chan, vms);
06679 } else if (!strncasecmp(chan->language, "ua", 2)) {
06680 return vm_intro_ua(chan, vms);
06681 } else if (!strcasecmp(chan->language, "he")) {
06682 return vm_intro_he(chan, vms);
06683 } else {
06684 return vm_intro_en(chan, vms);
06685 }
06686 }
06687
06688 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
06689 {
06690 int res = 0;
06691
06692 while (!res) {
06693 if (vms->starting) {
06694 if (vms->lastmsg > -1) {
06695 res = ast_play_and_wait(chan, "vm-onefor");
06696 if (!strcasecmp(chan->language, "he"))
06697 res = ast_play_and_wait(chan, "vm-for");
06698 if (!res)
06699 res = vm_play_folder_name(chan, vms->vmbox);
06700 }
06701 if (!res)
06702 res = ast_play_and_wait(chan, "vm-opts");
06703 } else {
06704 if (vms->curmsg)
06705 res = ast_play_and_wait(chan, "vm-prev");
06706 if (!res && !skipadvanced)
06707 res = ast_play_and_wait(chan, "vm-advopts");
06708 if (!res)
06709 res = ast_play_and_wait(chan, "vm-repeat");
06710 if (!res && (vms->curmsg != vms->lastmsg))
06711 res = ast_play_and_wait(chan, "vm-next");
06712 if (!res) {
06713 if (!vms->deleted[vms->curmsg])
06714 res = ast_play_and_wait(chan, "vm-delete");
06715 else
06716 res = ast_play_and_wait(chan, "vm-undelete");
06717 if (!res)
06718 res = ast_play_and_wait(chan, "vm-toforward");
06719 if (!res)
06720 res = ast_play_and_wait(chan, "vm-savemessage");
06721 }
06722 }
06723 if (!res)
06724 res = ast_play_and_wait(chan, "vm-helpexit");
06725 if (!res)
06726 res = ast_waitfordigit(chan, 6000);
06727 if (!res) {
06728 vms->repeats++;
06729 if (vms->repeats > 2) {
06730 res = 't';
06731 }
06732 }
06733 }
06734 return res;
06735 }
06736
06737 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06738 {
06739 int cmd = 0;
06740 int duration = 0;
06741 int tries = 0;
06742 char newpassword[80] = "";
06743 char newpassword2[80] = "";
06744 char prefile[PATH_MAX] = "";
06745 unsigned char buf[256];
06746 int bytes=0;
06747
06748 if (ast_adsi_available(chan)) {
06749 bytes += adsi_logo(buf + bytes);
06750 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
06751 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06752 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06753 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06754 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06755 }
06756
06757
06758
06759 for (;;) {
06760 newpassword[1] = '\0';
06761 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
06762 if (cmd == '#')
06763 newpassword[0] = '\0';
06764 if (cmd < 0 || cmd == 't' || cmd == '#')
06765 return cmd;
06766 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
06767 if (cmd < 0 || cmd == 't' || cmd == '#')
06768 return cmd;
06769 newpassword2[1] = '\0';
06770 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
06771 if (cmd == '#')
06772 newpassword2[0] = '\0';
06773 if (cmd < 0 || cmd == 't' || cmd == '#')
06774 return cmd;
06775 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
06776 if (cmd < 0 || cmd == 't' || cmd == '#')
06777 return cmd;
06778 if (!strcmp(newpassword, newpassword2))
06779 break;
06780 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
06781 cmd = ast_play_and_wait(chan, "vm-mismatch");
06782 if (++tries == 3)
06783 return -1;
06784 }
06785 if (ast_strlen_zero(ext_pass_cmd))
06786 vm_change_password(vmu,newpassword);
06787 else
06788 vm_change_password_shell(vmu,newpassword);
06789 if (option_debug > 2)
06790 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
06791 cmd = ast_play_and_wait(chan,"vm-passchanged");
06792
06793
06794 if (ast_test_flag(vmu, VM_FORCENAME)) {
06795 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
06796 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06797 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06798 if (cmd < 0 || cmd == 't' || cmd == '#')
06799 return cmd;
06800 }
06801 }
06802
06803
06804 if (ast_test_flag(vmu, VM_FORCEGREET)) {
06805 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06806 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06807 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06808 if (cmd < 0 || cmd == 't' || cmd == '#')
06809 return cmd;
06810 }
06811
06812 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06813 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06814 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06815 if (cmd < 0 || cmd == 't' || cmd == '#')
06816 return cmd;
06817 }
06818 }
06819
06820 return cmd;
06821 }
06822
06823 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06824 {
06825 int cmd = 0;
06826 int retries = 0;
06827 int duration = 0;
06828 char newpassword[80] = "";
06829 char newpassword2[80] = "";
06830 char prefile[PATH_MAX] = "";
06831 unsigned char buf[256];
06832 int bytes=0;
06833
06834 if (ast_adsi_available(chan))
06835 {
06836 bytes += adsi_logo(buf + bytes);
06837 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
06838 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06839 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06840 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06841 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06842 }
06843 while ((cmd >= 0) && (cmd != 't')) {
06844 if (cmd)
06845 retries = 0;
06846 switch (cmd) {
06847 case '1':
06848 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06849 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06850 break;
06851 case '2':
06852 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06853 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06854 break;
06855 case '3':
06856 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
06857 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06858 break;
06859 case '4':
06860 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
06861 break;
06862 case '5':
06863 if (vmu->password[0] == '-') {
06864 cmd = ast_play_and_wait(chan, "vm-no");
06865 break;
06866 }
06867 newpassword[1] = '\0';
06868 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
06869 if (cmd == '#')
06870 newpassword[0] = '\0';
06871 else {
06872 if (cmd < 0)
06873 break;
06874 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
06875 break;
06876 }
06877 }
06878 newpassword2[1] = '\0';
06879 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
06880 if (cmd == '#')
06881 newpassword2[0] = '\0';
06882 else {
06883 if (cmd < 0)
06884 break;
06885
06886 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
06887 break;
06888 }
06889 }
06890 if (strcmp(newpassword, newpassword2)) {
06891 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
06892 cmd = ast_play_and_wait(chan, "vm-mismatch");
06893 break;
06894 }
06895 if (ast_strlen_zero(ext_pass_cmd))
06896 vm_change_password(vmu,newpassword);
06897 else
06898 vm_change_password_shell(vmu,newpassword);
06899 if (option_debug > 2)
06900 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
06901 cmd = ast_play_and_wait(chan,"vm-passchanged");
06902 break;
06903 case '*':
06904 cmd = 't';
06905 break;
06906 default:
06907 cmd = 0;
06908 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06909 RETRIEVE(prefile, -1, vmu);
06910 if (ast_fileexists(prefile, NULL, NULL))
06911 cmd = ast_play_and_wait(chan, "vm-tmpexists");
06912 DISPOSE(prefile, -1);
06913 if (!cmd)
06914 cmd = ast_play_and_wait(chan, "vm-options");
06915 if (!cmd)
06916 cmd = ast_waitfordigit(chan,6000);
06917 if (!cmd)
06918 retries++;
06919 if (retries > 3)
06920 cmd = 't';
06921 }
06922 }
06923 if (cmd == 't')
06924 cmd = 0;
06925 return cmd;
06926 }
06927
06928 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06929 {
06930 int res;
06931 int cmd = 0;
06932 int retries = 0;
06933 int duration = 0;
06934 char prefile[PATH_MAX] = "";
06935 unsigned char buf[256];
06936 char dest[PATH_MAX];
06937 int bytes = 0;
06938
06939 if (ast_adsi_available(chan)) {
06940 bytes += adsi_logo(buf + bytes);
06941 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
06942 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06943 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06944 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06945 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06946 }
06947
06948 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06949 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
06950 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
06951 return -1;
06952 }
06953 while ((cmd >= 0) && (cmd != 't')) {
06954 if (cmd)
06955 retries = 0;
06956 RETRIEVE(prefile, -1, vmu);
06957 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
06958 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06959 cmd = 't';
06960 } else {
06961 switch (cmd) {
06962 case '1':
06963 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06964 break;
06965 case '2':
06966 DELETE(prefile, -1, prefile, vmu);
06967 ast_play_and_wait(chan, "vm-tempremoved");
06968 cmd = 't';
06969 break;
06970 case '*':
06971 cmd = 't';
06972 break;
06973 default:
06974 cmd = ast_play_and_wait(chan,
06975 ast_fileexists(prefile, NULL, NULL) > 0 ?
06976 "vm-tempgreeting2" : "vm-tempgreeting");
06977 if (!cmd)
06978 cmd = ast_waitfordigit(chan,6000);
06979 if (!cmd)
06980 retries++;
06981 if (retries > 3)
06982 cmd = 't';
06983 }
06984 }
06985 DISPOSE(prefile, -1);
06986 }
06987 if (cmd == 't')
06988 cmd = 0;
06989 return cmd;
06990 }
06991
06992
06993 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06994 {
06995 int cmd=0;
06996
06997 if (vms->lastmsg > -1) {
06998 cmd = play_message(chan, vmu, vms);
06999 } else {
07000 cmd = ast_play_and_wait(chan, "vm-youhave");
07001 if (!cmd)
07002 cmd = ast_play_and_wait(chan, "vm-no");
07003 if (!cmd) {
07004 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07005 cmd = ast_play_and_wait(chan, vms->fn);
07006 }
07007 if (!cmd)
07008 cmd = ast_play_and_wait(chan, "vm-messages");
07009 }
07010 return cmd;
07011 }
07012
07013
07014 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07015 {
07016 int cmd = 0;
07017
07018 if (vms->lastmsg > -1) {
07019 cmd = play_message(chan, vmu, vms);
07020 } else {
07021 if (!strcasecmp(vms->fn, "INBOX")) {
07022 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
07023 } else {
07024 cmd = ast_play_and_wait(chan, "vm-nomessages");
07025 }
07026 }
07027 return cmd;
07028 }
07029
07030
07031
07032 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07033 {
07034 int cmd=0;
07035
07036 if (vms->lastmsg > -1) {
07037 cmd = play_message(chan, vmu, vms);
07038 } else {
07039 cmd = ast_play_and_wait(chan, "vm-youhaveno");
07040 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
07041 if (!cmd) {
07042 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
07043 cmd = ast_play_and_wait(chan, vms->fn);
07044 }
07045 if (!cmd)
07046 cmd = ast_play_and_wait(chan, "vm-messages");
07047 } else {
07048 if (!cmd)
07049 cmd = ast_play_and_wait(chan, "vm-messages");
07050 if (!cmd) {
07051 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07052 cmd = ast_play_and_wait(chan, vms->fn);
07053 }
07054 }
07055 }
07056 return cmd;
07057 }
07058
07059 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07060 {
07061 if (!strncasecmp(chan->language, "es", 2) ||
07062 !strncasecmp(chan->language, "it", 2) ||
07063 !strncasecmp(chan->language, "pt", 2) ||
07064 !strncasecmp(chan->language, "gr", 2)) {
07065 return vm_browse_messages_latin(chan, vms, vmu);
07066 } else if (!strcasecmp(chan->language, "he")) {
07067 return vm_browse_messages_he(chan, vms, vmu);
07068 } else {
07069 return vm_browse_messages_en(chan, vms, vmu);
07070 }
07071 }
07072
07073 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
07074 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
07075 int skipuser, int maxlogins, int silent)
07076 {
07077 int useadsi=0, valid=0, logretries=0;
07078 char password[AST_MAX_EXTENSION]="", *passptr;
07079 struct ast_vm_user vmus, *vmu = NULL;
07080
07081
07082 adsi_begin(chan, &useadsi);
07083 if (!skipuser && useadsi)
07084 adsi_login(chan);
07085 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
07086 ast_log(LOG_WARNING, "Couldn't stream login file\n");
07087 return -1;
07088 }
07089
07090
07091
07092 while (!valid && (logretries < maxlogins)) {
07093
07094 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
07095 ast_log(LOG_WARNING, "Couldn't read username\n");
07096 return -1;
07097 }
07098 if (ast_strlen_zero(mailbox)) {
07099 if (chan->cid.cid_num) {
07100 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
07101 } else {
07102 if (option_verbose > 2)
07103 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
07104 return -1;
07105 }
07106 }
07107 if (useadsi)
07108 adsi_password(chan);
07109
07110 if (!ast_strlen_zero(prefix)) {
07111 char fullusername[80] = "";
07112 ast_copy_string(fullusername, prefix, sizeof(fullusername));
07113 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
07114 ast_copy_string(mailbox, fullusername, mailbox_size);
07115 }
07116
07117 if (option_debug)
07118 ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
07119 vmu = find_user(&vmus, context, mailbox);
07120 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
07121
07122 password[0] = '\0';
07123 } else {
07124 if (ast_streamfile(chan, "vm-password", chan->language)) {
07125 ast_log(LOG_WARNING, "Unable to stream password file\n");
07126 return -1;
07127 }
07128 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
07129 ast_log(LOG_WARNING, "Unable to read password\n");
07130 return -1;
07131 }
07132 }
07133
07134 if (vmu) {
07135 passptr = vmu->password;
07136 if (passptr[0] == '-') passptr++;
07137 }
07138 if (vmu && !strcmp(passptr, password))
07139 valid++;
07140 else {
07141 if (option_verbose > 2)
07142 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
07143 if (!ast_strlen_zero(prefix))
07144 mailbox[0] = '\0';
07145 }
07146 logretries++;
07147 if (!valid) {
07148 if (skipuser || logretries >= maxlogins) {
07149 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
07150 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
07151 return -1;
07152 }
07153 } else {
07154 if (useadsi)
07155 adsi_login(chan);
07156 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
07157 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
07158 return -1;
07159 }
07160 }
07161 if (ast_waitstream(chan, ""))
07162 return -1;
07163 }
07164 }
07165 if (!valid && (logretries >= maxlogins)) {
07166 ast_stopstream(chan);
07167 ast_play_and_wait(chan, "vm-goodbye");
07168 return -1;
07169 }
07170 if (vmu && !skipuser) {
07171 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
07172 }
07173 return 0;
07174 }
07175
07176 static int vm_execmain(struct ast_channel *chan, void *data)
07177 {
07178
07179
07180
07181 int res=-1;
07182 int cmd=0;
07183 int valid = 0;
07184 struct ast_module_user *u;
07185 char prefixstr[80] ="";
07186 char ext_context[256]="";
07187 int box;
07188 int useadsi = 0;
07189 int skipuser = 0;
07190 struct vm_state vms;
07191 struct ast_vm_user *vmu = NULL, vmus;
07192 char *context=NULL;
07193 int silentexit = 0;
07194 struct ast_flags flags = { 0 };
07195 signed char record_gain = 0;
07196 int play_auto = 0;
07197 int play_folder = 0;
07198 #ifdef IMAP_STORAGE
07199 int deleted = 0;
07200 #endif
07201 u = ast_module_user_add(chan);
07202
07203
07204 memset(&vms, 0, sizeof(vms));
07205 vms.lastmsg = -1;
07206
07207 memset(&vmus, 0, sizeof(vmus));
07208
07209 if (chan->_state != AST_STATE_UP) {
07210 if (option_debug)
07211 ast_log(LOG_DEBUG, "Before ast_answer\n");
07212 ast_answer(chan);
07213 }
07214
07215 if (!ast_strlen_zero(data)) {
07216 char *opts[OPT_ARG_ARRAY_SIZE];
07217 char *parse;
07218 AST_DECLARE_APP_ARGS(args,
07219 AST_APP_ARG(argv0);
07220 AST_APP_ARG(argv1);
07221 );
07222
07223 parse = ast_strdupa(data);
07224
07225 AST_STANDARD_APP_ARGS(args, parse);
07226
07227 if (args.argc == 2) {
07228 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
07229 ast_module_user_remove(u);
07230 return -1;
07231 }
07232 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07233 int gain;
07234 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
07235 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
07236 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07237 ast_module_user_remove(u);
07238 return -1;
07239 } else {
07240 record_gain = (signed char) gain;
07241 }
07242 } else {
07243 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
07244 }
07245 }
07246 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
07247 play_auto = 1;
07248 if (opts[OPT_ARG_PLAYFOLDER]) {
07249 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%d", &play_folder) != 1) {
07250 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
07251 }
07252 } else {
07253 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
07254 }
07255 if ( play_folder > 9 || play_folder < 0) {
07256 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
07257 play_folder = 0;
07258 }
07259 }
07260 } else {
07261
07262 while (*(args.argv0)) {
07263 if (*(args.argv0) == 's')
07264 ast_set_flag(&flags, OPT_SILENT);
07265 else if (*(args.argv0) == 'p')
07266 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
07267 else
07268 break;
07269 (args.argv0)++;
07270 }
07271
07272 }
07273
07274 valid = ast_test_flag(&flags, OPT_SILENT);
07275
07276 if ((context = strchr(args.argv0, '@')))
07277 *context++ = '\0';
07278
07279 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
07280 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
07281 else
07282 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
07283
07284 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
07285 skipuser++;
07286 else
07287 valid = 0;
07288 }
07289
07290 if (!valid)
07291 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
07292
07293 if (option_debug)
07294 ast_log(LOG_DEBUG, "After vm_authenticate\n");
07295 if (!res) {
07296 valid = 1;
07297 if (!skipuser)
07298 vmu = &vmus;
07299 } else {
07300 res = 0;
07301 }
07302
07303
07304 adsi_begin(chan, &useadsi);
07305
07306 #ifdef IMAP_STORAGE
07307 vms.interactive = 1;
07308 vms.updated = 1;
07309 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
07310 vmstate_insert(&vms);
07311 init_vm_state(&vms);
07312 #endif
07313 if (!valid)
07314 goto out;
07315
07316 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07317
07318 }
07319 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07320
07321 }
07322
07323
07324 if (!ast_strlen_zero(vmu->language))
07325 ast_string_field_set(chan, language, vmu->language);
07326 create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
07327
07328 if (option_debug)
07329 ast_log(LOG_DEBUG, "Before open_mailbox\n");
07330 res = open_mailbox(&vms, vmu, 1);
07331 if (res == ERROR_LOCK_PATH)
07332 goto out;
07333 vms.oldmessages = vms.lastmsg + 1;
07334 if (option_debug > 2)
07335 ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
07336
07337 res = open_mailbox(&vms, vmu, 0);
07338 if (res == ERROR_LOCK_PATH)
07339 goto out;
07340 vms.newmessages = vms.lastmsg + 1;
07341 if (option_debug > 2)
07342 ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
07343
07344
07345 if (play_auto) {
07346 res = open_mailbox(&vms, vmu, play_folder);
07347 if (res == ERROR_LOCK_PATH)
07348 goto out;
07349
07350
07351 if (vms.lastmsg == -1) {
07352 cmd = vm_browse_messages(chan, &vms, vmu);
07353 res = 0;
07354 goto out;
07355 }
07356 } else {
07357 if (!vms.newmessages && vms.oldmessages) {
07358
07359 res = open_mailbox(&vms, vmu, 1);
07360 play_folder = 1;
07361 if (res == ERROR_LOCK_PATH)
07362 goto out;
07363 }
07364 }
07365
07366 if (useadsi)
07367 adsi_status(chan, &vms);
07368 res = 0;
07369
07370
07371 if (!strcasecmp(vmu->mailbox, vmu->password) &&
07372 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
07373 if (ast_play_and_wait(chan, "vm-newuser") == -1)
07374 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
07375 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
07376 if ((cmd == 't') || (cmd == '#')) {
07377
07378 res = 0;
07379 goto out;
07380 } else if (cmd < 0) {
07381
07382 res = -1;
07383 goto out;
07384 }
07385 }
07386 #ifdef IMAP_STORAGE
07387 if (option_debug > 2)
07388 ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
07389 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
07390 if (option_debug)
07391 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
07392 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07393 }
07394 if (option_debug > 2)
07395 ast_log(LOG_DEBUG, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07396 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
07397 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07398 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07399 }
07400 #endif
07401 if (play_auto) {
07402 cmd = '1';
07403 } else {
07404 cmd = vm_intro(chan, vmu, &vms);
07405 }
07406
07407 vms.repeats = 0;
07408 vms.starting = 1;
07409 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07410
07411 switch (cmd) {
07412 case '1':
07413 vms.curmsg = 0;
07414
07415 case '5':
07416 cmd = vm_browse_messages(chan, &vms, vmu);
07417 break;
07418 case '2':
07419 if (useadsi)
07420 adsi_folders(chan, 0, "Change to folder...");
07421 cmd = get_folder2(chan, "vm-changeto", 0);
07422 if (cmd == '#') {
07423 cmd = 0;
07424 } else if (cmd > 0) {
07425 cmd = cmd - '0';
07426 res = close_mailbox(&vms, vmu);
07427 if (res == ERROR_LOCK_PATH)
07428 goto out;
07429 res = open_mailbox(&vms, vmu, cmd);
07430 if (res == ERROR_LOCK_PATH)
07431 goto out;
07432 play_folder = cmd;
07433 cmd = 0;
07434 }
07435 if (useadsi)
07436 adsi_status2(chan, &vms);
07437
07438 if (!cmd)
07439 cmd = vm_play_folder_name(chan, vms.vmbox);
07440
07441 vms.starting = 1;
07442 break;
07443 case '3':
07444 cmd = 0;
07445 vms.repeats = 0;
07446 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07447 switch (cmd) {
07448 case '1':
07449 if (vms.lastmsg > -1 && !vms.starting) {
07450 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
07451 if (cmd == ERROR_LOCK_PATH) {
07452 res = cmd;
07453 goto out;
07454 }
07455 } else
07456 cmd = ast_play_and_wait(chan, "vm-sorry");
07457 cmd = 't';
07458 break;
07459 case '2':
07460 if (option_verbose > 2 && !vms.starting)
07461 ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
07462 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
07463 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
07464 if (cmd == 9) {
07465 silentexit = 1;
07466 goto out;
07467 } else if (cmd == ERROR_LOCK_PATH) {
07468 res = cmd;
07469 goto out;
07470 }
07471 }
07472 else
07473 cmd = ast_play_and_wait(chan, "vm-sorry");
07474 cmd = 't';
07475 break;
07476 case '3':
07477 if (vms.lastmsg > -1 && !vms.starting) {
07478 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
07479 if (cmd == ERROR_LOCK_PATH) {
07480 res = cmd;
07481 goto out;
07482 }
07483 } else
07484 cmd = ast_play_and_wait(chan, "vm-sorry");
07485 cmd = 't';
07486 break;
07487 case '4':
07488 if (!ast_strlen_zero(vmu->dialout)) {
07489 cmd = dialout(chan, vmu, NULL, vmu->dialout);
07490 if (cmd == 9) {
07491 silentexit = 1;
07492 goto out;
07493 }
07494 }
07495 else
07496 cmd = ast_play_and_wait(chan, "vm-sorry");
07497 cmd = 't';
07498 break;
07499
07500 case '5':
07501 if (ast_test_flag(vmu, VM_SVMAIL)) {
07502 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
07503 if (cmd == ERROR_LOCK_PATH) {
07504 res = cmd;
07505 ast_log(LOG_WARNING, "forward_message failed to lock path.\n");
07506 goto out;
07507 }
07508 } else
07509 cmd = ast_play_and_wait(chan,"vm-sorry");
07510 cmd='t';
07511 break;
07512
07513 case '*':
07514 cmd = 't';
07515 break;
07516
07517 default:
07518 cmd = 0;
07519 if (!vms.starting) {
07520 cmd = ast_play_and_wait(chan, "vm-toreply");
07521 }
07522 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
07523 cmd = ast_play_and_wait(chan, "vm-tocallback");
07524 }
07525 if (!cmd && !vms.starting) {
07526 cmd = ast_play_and_wait(chan, "vm-tohearenv");
07527 }
07528 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
07529 cmd = ast_play_and_wait(chan, "vm-tomakecall");
07530 }
07531 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
07532 cmd=ast_play_and_wait(chan, "vm-leavemsg");
07533 if (!cmd)
07534 cmd = ast_play_and_wait(chan, "vm-starmain");
07535 if (!cmd)
07536 cmd = ast_waitfordigit(chan,6000);
07537 if (!cmd)
07538 vms.repeats++;
07539 if (vms.repeats > 3)
07540 cmd = 't';
07541 }
07542 }
07543 if (cmd == 't') {
07544 cmd = 0;
07545 vms.repeats = 0;
07546 }
07547 break;
07548 case '4':
07549 if (vms.curmsg > 0) {
07550 vms.curmsg--;
07551 cmd = play_message(chan, vmu, &vms);
07552 } else {
07553 cmd = ast_play_and_wait(chan, "vm-nomore");
07554 }
07555 break;
07556 case '6':
07557 if (vms.curmsg < vms.lastmsg) {
07558 vms.curmsg++;
07559 cmd = play_message(chan, vmu, &vms);
07560 } else {
07561 cmd = ast_play_and_wait(chan, "vm-nomore");
07562 }
07563 break;
07564 case '7':
07565 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
07566 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
07567 if (useadsi)
07568 adsi_delete(chan, &vms);
07569 if (vms.deleted[vms.curmsg]) {
07570 if (play_folder == 0)
07571 vms.newmessages--;
07572 else if (play_folder == 1)
07573 vms.oldmessages--;
07574 cmd = ast_play_and_wait(chan, "vm-deleted");
07575 }
07576 else {
07577 if (play_folder == 0)
07578 vms.newmessages++;
07579 else if (play_folder == 1)
07580 vms.oldmessages++;
07581 cmd = ast_play_and_wait(chan, "vm-undeleted");
07582 }
07583 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
07584 if (vms.curmsg < vms.lastmsg) {
07585 vms.curmsg++;
07586 cmd = play_message(chan, vmu, &vms);
07587 } else {
07588 cmd = ast_play_and_wait(chan, "vm-nomore");
07589 }
07590 }
07591 } else
07592 cmd = 0;
07593 #ifdef IMAP_STORAGE
07594 deleted = 1;
07595 #endif
07596 break;
07597
07598 case '8':
07599 if (vms.lastmsg > -1) {
07600 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
07601 if (cmd == ERROR_LOCK_PATH) {
07602 res = cmd;
07603 goto out;
07604 }
07605 } else
07606 cmd = ast_play_and_wait(chan, "vm-nomore");
07607 break;
07608 case '9':
07609 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
07610
07611 cmd = 0;
07612 break;
07613 }
07614 if (useadsi)
07615 adsi_folders(chan, 1, "Save to folder...");
07616 cmd = get_folder2(chan, "vm-savefolder", 1);
07617 box = 0;
07618 if (cmd == '#') {
07619 cmd = 0;
07620 break;
07621 } else if (cmd > 0) {
07622 box = cmd = cmd - '0';
07623 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
07624 if (cmd == ERROR_LOCK_PATH) {
07625 res = cmd;
07626 goto out;
07627 #ifndef IMAP_STORAGE
07628 } else if (!cmd) {
07629 vms.deleted[vms.curmsg] = 1;
07630 #endif
07631 } else {
07632 vms.deleted[vms.curmsg] = 0;
07633 vms.heard[vms.curmsg] = 0;
07634 }
07635 }
07636 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
07637 if (useadsi)
07638 adsi_message(chan, &vms);
07639 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
07640 if (!cmd) {
07641 cmd = ast_play_and_wait(chan, "vm-message");
07642 if (!cmd)
07643 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
07644 if (!cmd)
07645 cmd = ast_play_and_wait(chan, "vm-savedto");
07646 if (!cmd)
07647 cmd = vm_play_folder_name(chan, vms.fn);
07648 } else {
07649 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07650 }
07651 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
07652 if (vms.curmsg < vms.lastmsg) {
07653 vms.curmsg++;
07654 cmd = play_message(chan, vmu, &vms);
07655 } else {
07656 cmd = ast_play_and_wait(chan, "vm-nomore");
07657 }
07658 }
07659 break;
07660 case '*':
07661 if (!vms.starting) {
07662 cmd = ast_play_and_wait(chan, "vm-onefor");
07663 if (!strcasecmp(chan->language, "he"))
07664 cmd = ast_play_and_wait(chan, "vm-for");
07665 if (!cmd)
07666 cmd = vm_play_folder_name(chan, vms.vmbox);
07667 if (!cmd)
07668 cmd = ast_play_and_wait(chan, "vm-opts");
07669 if (!cmd)
07670 cmd = vm_instructions(chan, &vms, 1);
07671 } else
07672 cmd = 0;
07673 break;
07674 case '0':
07675 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
07676 if (useadsi)
07677 adsi_status(chan, &vms);
07678 break;
07679 default:
07680 cmd = vm_instructions(chan, &vms, 0);
07681 break;
07682 }
07683 }
07684 if ((cmd == 't') || (cmd == '#')) {
07685
07686 res = 0;
07687 } else {
07688
07689 res = -1;
07690 }
07691
07692 out:
07693 if (res > -1) {
07694 ast_stopstream(chan);
07695 adsi_goodbye(chan);
07696 if (valid) {
07697 if (silentexit)
07698 res = ast_play_and_wait(chan, "vm-dialout");
07699 else
07700 res = ast_play_and_wait(chan, "vm-goodbye");
07701 if (res > 0)
07702 res = 0;
07703 }
07704 if (useadsi)
07705 ast_adsi_unload_session(chan);
07706 }
07707 if (vmu)
07708 close_mailbox(&vms, vmu);
07709 if (valid) {
07710 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
07711 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
07712 run_externnotify(vmu->context, vmu->mailbox);
07713 }
07714 #ifdef IMAP_STORAGE
07715
07716 if (option_debug > 2)
07717 ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
07718 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
07719 ast_mutex_lock(&vms.lock);
07720 #ifdef HAVE_IMAP_TK2006
07721 if (LEVELUIDPLUS (vms.mailstream)) {
07722 mail_expunge_full(vms.mailstream,NIL,EX_UID);
07723 } else
07724 #endif
07725 mail_expunge(vms.mailstream);
07726 ast_mutex_unlock(&vms.lock);
07727 }
07728
07729
07730 vmstate_delete(&vms);
07731 #endif
07732 if (vmu)
07733 free_user(vmu);
07734 if (vms.deleted)
07735 free(vms.deleted);
07736 if (vms.heard)
07737 free(vms.heard);
07738 ast_module_user_remove(u);
07739
07740 return res;
07741 }
07742
07743 static int vm_exec(struct ast_channel *chan, void *data)
07744 {
07745 int res = 0;
07746 struct ast_module_user *u;
07747 char *tmp;
07748 struct leave_vm_options leave_options;
07749 struct ast_flags flags = { 0 };
07750 static int deprecate_warning = 0;
07751 char *opts[OPT_ARG_ARRAY_SIZE];
07752 AST_DECLARE_APP_ARGS(args,
07753 AST_APP_ARG(argv0);
07754 AST_APP_ARG(argv1);
07755 );
07756
07757 u = ast_module_user_add(chan);
07758
07759 memset(&leave_options, 0, sizeof(leave_options));
07760
07761 if (chan->_state != AST_STATE_UP)
07762 ast_answer(chan);
07763
07764 if (!ast_strlen_zero(data)) {
07765 tmp = ast_strdupa(data);
07766 AST_STANDARD_APP_ARGS(args, tmp);
07767 if (args.argc == 2) {
07768 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
07769 ast_module_user_remove(u);
07770 return -1;
07771 }
07772 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
07773 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07774 int gain;
07775
07776 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
07777 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07778 ast_module_user_remove(u);
07779 return -1;
07780 } else {
07781 leave_options.record_gain = (signed char) gain;
07782 }
07783 }
07784 } else {
07785
07786 int old = 0;
07787 char *orig_argv0 = args.argv0;
07788 while (*(args.argv0)) {
07789 if (*(args.argv0) == 's') {
07790 old = 1;
07791 ast_set_flag(&leave_options, OPT_SILENT);
07792 } else if (*(args.argv0) == 'b') {
07793 old = 1;
07794 ast_set_flag(&leave_options, OPT_BUSY_GREETING);
07795 } else if (*(args.argv0) == 'u') {
07796 old = 1;
07797 ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING);
07798 } else if (*(args.argv0) == 'j') {
07799 old = 1;
07800 ast_set_flag(&leave_options, OPT_PRIORITY_JUMP);
07801 } else
07802 break;
07803 (args.argv0)++;
07804 }
07805 if (!deprecate_warning && old) {
07806 deprecate_warning = 1;
07807 ast_log(LOG_WARNING, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0);
07808 ast_log(LOG_WARNING, "Please move all leading options to the second argument.\n");
07809 }
07810 }
07811 } else {
07812 char tmp[256];
07813 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
07814 if (res < 0) {
07815 ast_module_user_remove(u);
07816 return res;
07817 }
07818 if (ast_strlen_zero(tmp)) {
07819 ast_module_user_remove(u);
07820 return 0;
07821 }
07822 args.argv0 = ast_strdupa(tmp);
07823 }
07824
07825 res = leave_voicemail(chan, args.argv0, &leave_options);
07826
07827 if (res == ERROR_LOCK_PATH) {
07828 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
07829
07830 if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
07831 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07832 ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
07833 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
07834 res = 0;
07835 }
07836
07837 ast_module_user_remove(u);
07838
07839 return res;
07840 }
07841
07842 static struct ast_vm_user *find_or_create(char *context, char *mbox)
07843 {
07844 struct ast_vm_user *vmu;
07845 AST_LIST_TRAVERSE(&users, vmu, list) {
07846 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox))
07847 break;
07848 if (context && (!strcasecmp(context, vmu->context)) && (!strcasecmp(mbox, vmu->mailbox)))
07849 break;
07850 }
07851
07852 if (!vmu) {
07853 if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
07854 ast_copy_string(vmu->context, context, sizeof(vmu->context));
07855 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
07856 AST_LIST_INSERT_TAIL(&users, vmu, list);
07857 }
07858 }
07859 return vmu;
07860 }
07861
07862 static int append_mailbox(char *context, char *mbox, char *data)
07863 {
07864
07865 char *tmp;
07866 char *stringp;
07867 char *s;
07868 struct ast_vm_user *vmu;
07869
07870 tmp = ast_strdupa(data);
07871
07872 if ((vmu = find_or_create(context, mbox))) {
07873 populate_defaults(vmu);
07874
07875 stringp = tmp;
07876 if ((s = strsep(&stringp, ",")))
07877 ast_copy_string(vmu->password, s, sizeof(vmu->password));
07878 if (stringp && (s = strsep(&stringp, ",")))
07879 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
07880 if (stringp && (s = strsep(&stringp, ",")))
07881 ast_copy_string(vmu->email, s, sizeof(vmu->email));
07882 if (stringp && (s = strsep(&stringp, ",")))
07883 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
07884 if (stringp && (s = strsep(&stringp, ",")))
07885 apply_options(vmu, s);
07886 }
07887 return 0;
07888 }
07889
07890 static int vm_box_exists(struct ast_channel *chan, void *data)
07891 {
07892 struct ast_module_user *u;
07893 struct ast_vm_user svm;
07894 char *context, *box;
07895 int priority_jump = 0;
07896 AST_DECLARE_APP_ARGS(args,
07897 AST_APP_ARG(mbox);
07898 AST_APP_ARG(options);
07899 );
07900
07901 if (ast_strlen_zero(data)) {
07902 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
07903 return -1;
07904 }
07905
07906 u = ast_module_user_add(chan);
07907
07908 box = ast_strdupa(data);
07909
07910 AST_STANDARD_APP_ARGS(args, box);
07911
07912 if (args.options) {
07913 if (strchr(args.options, 'j'))
07914 priority_jump = 1;
07915 }
07916
07917 if ((context = strchr(args.mbox, '@'))) {
07918 *context = '\0';
07919 context++;
07920 }
07921
07922 if (find_user(&svm, context, args.mbox)) {
07923 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
07924 if (priority_jump || ast_opt_priority_jumping)
07925 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07926 ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
07927 } else
07928 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
07929 ast_module_user_remove(u);
07930 return 0;
07931 }
07932
07933 static int vmauthenticate(struct ast_channel *chan, void *data)
07934 {
07935 struct ast_module_user *u;
07936 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
07937 struct ast_vm_user vmus;
07938 char *options = NULL;
07939 int silent = 0, skipuser = 0;
07940 int res = -1;
07941
07942 u = ast_module_user_add(chan);
07943
07944 if (s) {
07945 s = ast_strdupa(s);
07946 user = strsep(&s, "|");
07947 options = strsep(&s, "|");
07948 if (user) {
07949 s = user;
07950 user = strsep(&s, "@");
07951 context = strsep(&s, "");
07952 if (!ast_strlen_zero(user))
07953 skipuser++;
07954 ast_copy_string(mailbox, user, sizeof(mailbox));
07955 }
07956 }
07957
07958 if (options) {
07959 silent = (strchr(options, 's')) != NULL;
07960 }
07961
07962 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
07963 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
07964 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
07965 ast_play_and_wait(chan, "auth-thankyou");
07966 res = 0;
07967 }
07968
07969 ast_module_user_remove(u);
07970 return res;
07971 }
07972
07973 static char voicemail_show_users_help[] =
07974 "Usage: voicemail show users [for <context>]\n"
07975 " Lists all mailboxes currently set up\n";
07976
07977 static char voicemail_show_zones_help[] =
07978 "Usage: voicemail show zones\n"
07979 " Lists zone message formats\n";
07980
07981 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
07982 {
07983 struct ast_vm_user *vmu;
07984 char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
07985
07986 if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
07987 else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
07988
07989 AST_LIST_LOCK(&users);
07990 if (!AST_LIST_EMPTY(&users)) {
07991 if (argc == 3)
07992 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
07993 else {
07994 int count = 0;
07995 AST_LIST_TRAVERSE(&users, vmu, list) {
07996 if (!strcmp(argv[4],vmu->context))
07997 count++;
07998 }
07999 if (count) {
08000 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
08001 } else {
08002 ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
08003 AST_LIST_UNLOCK(&users);
08004 return RESULT_FAILURE;
08005 }
08006 }
08007 AST_LIST_TRAVERSE(&users, vmu, list) {
08008 int newmsgs = 0, oldmsgs = 0;
08009 char count[12], tmp[256] = "";
08010
08011 if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
08012 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
08013 inboxcount(tmp, &newmsgs, &oldmsgs);
08014 snprintf(count,sizeof(count),"%d",newmsgs);
08015 ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
08016 }
08017 }
08018 } else {
08019 ast_cli(fd, "There are no voicemail users currently defined\n");
08020 AST_LIST_UNLOCK(&users);
08021 return RESULT_FAILURE;
08022 }
08023 AST_LIST_UNLOCK(&users);
08024 return RESULT_SUCCESS;
08025 }
08026
08027 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
08028 {
08029 struct vm_zone *zone;
08030 char *output_format = "%-15s %-20s %-45s\n";
08031 int res = RESULT_SUCCESS;
08032
08033 if (argc != 3)
08034 return RESULT_SHOWUSAGE;
08035
08036 AST_LIST_LOCK(&zones);
08037 if (!AST_LIST_EMPTY(&zones)) {
08038 ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
08039 AST_LIST_TRAVERSE(&zones, zone, list) {
08040 ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
08041 }
08042 } else {
08043 ast_cli(fd, "There are no voicemail zones currently defined\n");
08044 res = RESULT_FAILURE;
08045 }
08046 AST_LIST_UNLOCK(&zones);
08047
08048 return res;
08049 }
08050
08051 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
08052 {
08053 int which = 0;
08054 int wordlen;
08055 struct ast_vm_user *vmu;
08056 const char *context = "";
08057
08058
08059 if (pos > 4)
08060 return NULL;
08061 if (pos == 3)
08062 return (state == 0) ? ast_strdup("for") : NULL;
08063 wordlen = strlen(word);
08064 AST_LIST_TRAVERSE(&users, vmu, list) {
08065 if (!strncasecmp(word, vmu->context, wordlen)) {
08066 if (context && strcmp(context, vmu->context) && ++which > state)
08067 return ast_strdup(vmu->context);
08068
08069 context = vmu->context;
08070 }
08071 }
08072 return NULL;
08073 }
08074
08075 static struct ast_cli_entry cli_show_voicemail_users_deprecated = {
08076 { "show", "voicemail", "users", NULL },
08077 handle_voicemail_show_users, NULL,
08078 NULL, complete_voicemail_show_users };
08079
08080 static struct ast_cli_entry cli_show_voicemail_zones_deprecated = {
08081 { "show", "voicemail", "zones", NULL },
08082 handle_voicemail_show_zones, NULL,
08083 NULL, NULL };
08084
08085 static struct ast_cli_entry cli_voicemail[] = {
08086 { { "voicemail", "show", "users", NULL },
08087 handle_voicemail_show_users, "List defined voicemail boxes",
08088 voicemail_show_users_help, complete_voicemail_show_users, &cli_show_voicemail_users_deprecated },
08089
08090 { { "voicemail", "show", "zones", NULL },
08091 handle_voicemail_show_zones, "List zone message formats",
08092 voicemail_show_zones_help, NULL, &cli_show_voicemail_zones_deprecated },
08093 };
08094
08095 static void free_vm_users(void)
08096 {
08097 struct ast_vm_user *cur;
08098 struct vm_zone *zcur;
08099
08100 AST_LIST_LOCK(&users);
08101 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
08102 ast_set_flag(cur, VM_ALLOCED);
08103 free_user(cur);
08104 }
08105 AST_LIST_UNLOCK(&users);
08106
08107 AST_LIST_LOCK(&zones);
08108 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list))) {
08109 free_zone(zcur);
08110 }
08111 AST_LIST_UNLOCK(&zones);
08112 }
08113
08114 static int load_config(void)
08115 {
08116 struct ast_vm_user *cur;
08117 struct ast_config *cfg, *ucfg;
08118 char *cat;
08119 struct ast_variable *var;
08120 const char *notifystr = NULL;
08121 const char *smdistr = NULL;
08122 const char *astattach;
08123 const char *astsearch;
08124 const char *astsaycid;
08125 const char *send_voicemail;
08126 #ifdef IMAP_STORAGE
08127 const char *imap_server;
08128 const char *imap_port;
08129 const char *imap_flags;
08130 const char *imap_folder;
08131 const char *auth_user;
08132 const char *auth_password;
08133 const char *expunge_on_hangup;
08134 const char *imap_timeout;
08135 #endif
08136 const char *astcallop;
08137 const char *astreview;
08138 const char *asttempgreetwarn;
08139 const char *astskipcmd;
08140 const char *asthearenv;
08141 const char *astsaydurationinfo;
08142 const char *astsaydurationminfo;
08143 const char *silencestr;
08144 const char *maxmsgstr;
08145 const char *astdirfwd;
08146 const char *thresholdstr;
08147 const char *fmt;
08148 const char *astemail;
08149 const char *ucontext;
08150 const char *astmailcmd = SENDMAIL;
08151 const char *astforcename;
08152 const char *astforcegreet;
08153 const char *s;
08154 char *q,*stringp;
08155 const char *dialoutcxt = NULL;
08156 const char *callbackcxt = NULL;
08157 const char *exitcxt = NULL;
08158 const char *extpc;
08159 const char *emaildateformatstr;
08160 const char *volgainstr;
08161 int x;
08162 int tmpadsi[4];
08163
08164 cfg = ast_config_load(VOICEMAIL_CONFIG);
08165
08166 free_vm_users();
08167
08168 AST_LIST_LOCK(&users);
08169
08170 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
08171
08172 if (cfg) {
08173
08174
08175 if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
08176 ucontext = "default";
08177 ast_copy_string(userscontext, ucontext, sizeof(userscontext));
08178
08179 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
08180 astattach = "yes";
08181 ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);
08182
08183 if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
08184 astsearch = "no";
08185 ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
08186
08187 volgain = 0.0;
08188 if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
08189 sscanf(volgainstr, "%lf", &volgain);
08190
08191 #ifdef ODBC_STORAGE
08192 strcpy(odbc_database, "asterisk");
08193 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
08194 ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
08195 }
08196 strcpy(odbc_table, "voicemessages");
08197 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
08198 ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
08199 }
08200 #endif
08201
08202 strcpy(mailcmd, SENDMAIL);
08203 if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
08204 ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd));
08205
08206 maxsilence = 0;
08207 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
08208 maxsilence = atoi(silencestr);
08209 if (maxsilence > 0)
08210 maxsilence *= 1000;
08211 }
08212
08213 if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
08214 maxmsg = MAXMSG;
08215 } else {
08216 maxmsg = atoi(maxmsgstr);
08217 if (maxmsg <= 0) {
08218 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
08219 maxmsg = MAXMSG;
08220 } else if (maxmsg > MAXMSGLIMIT) {
08221 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
08222 maxmsg = MAXMSGLIMIT;
08223 }
08224 }
08225
08226
08227 if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
08228 ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
08229 }
08230
08231
08232 if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
08233 ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
08234 }
08235 #ifdef IMAP_STORAGE
08236
08237 if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
08238 ast_copy_string(imapserver, imap_server, sizeof(imapserver));
08239 } else {
08240 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
08241 }
08242
08243 if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
08244 ast_copy_string(imapport, imap_port, sizeof(imapport));
08245 } else {
08246 ast_copy_string(imapport,"143", sizeof(imapport));
08247 }
08248
08249 if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
08250 ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
08251 }
08252
08253 if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
08254 ast_copy_string(authuser, auth_user, sizeof(authuser));
08255 }
08256
08257 if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
08258 ast_copy_string(authpassword, auth_password, sizeof(authpassword));
08259 }
08260
08261 if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
08262 if (ast_false(expunge_on_hangup))
08263 expungeonhangup = 0;
08264 else
08265 expungeonhangup = 1;
08266 } else {
08267 expungeonhangup = 1;
08268 }
08269
08270 if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
08271 ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
08272 } else {
08273 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
08274 }
08275
08276
08277
08278
08279
08280
08281 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
08282 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(imap_timeout)));
08283 } else {
08284 mail_parameters(NIL, SET_READTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08285 }
08286
08287 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
08288 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(imap_timeout)));
08289 } else {
08290 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08291 }
08292
08293 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
08294 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(imap_timeout)));
08295 } else {
08296 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08297 }
08298
08299 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
08300 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(imap_timeout)));
08301 } else {
08302 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08303 }
08304
08305 #endif
08306
08307
08308 if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
08309 ast_copy_string(externnotify, notifystr, sizeof(externnotify));
08310 if (option_debug > 2)
08311 ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
08312 if (!strcasecmp(externnotify, "smdi")) {
08313 if (option_debug)
08314 ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
08315 if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
08316 smdi_iface = ast_smdi_interface_find(smdistr);
08317 } else {
08318 if (option_debug)
08319 ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
08320 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
08321 }
08322
08323 if (!smdi_iface) {
08324 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
08325 externnotify[0] = '\0';
08326 }
08327 }
08328 } else {
08329 externnotify[0] = '\0';
08330 }
08331
08332
08333 silencethreshold = 256;
08334 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
08335 silencethreshold = atoi(thresholdstr);
08336
08337 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
08338 astemail = ASTERISK_USERNAME;
08339 ast_copy_string(serveremail, astemail, sizeof(serveremail));
08340
08341 vmmaxmessage = 0;
08342 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
08343 if (sscanf(s, "%d", &x) == 1) {
08344 vmmaxmessage = x;
08345 } else {
08346 ast_log(LOG_WARNING, "Invalid max message time length\n");
08347 }
08348 }
08349
08350 vmminmessage = 0;
08351 if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
08352 if (sscanf(s, "%d", &x) == 1) {
08353 vmminmessage = x;
08354 if (maxsilence <= vmminmessage)
08355 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
08356 } else {
08357 ast_log(LOG_WARNING, "Invalid min message time length\n");
08358 }
08359 }
08360 fmt = ast_variable_retrieve(cfg, "general", "format");
08361 if (!fmt)
08362 fmt = "wav";
08363 ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
08364
08365 skipms = 3000;
08366 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
08367 if (sscanf(s, "%d", &x) == 1) {
08368 maxgreet = x;
08369 } else {
08370 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
08371 }
08372 }
08373
08374 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
08375 if (sscanf(s, "%d", &x) == 1) {
08376 skipms = x;
08377 } else {
08378 ast_log(LOG_WARNING, "Invalid skipms value\n");
08379 }
08380 }
08381
08382 maxlogins = 3;
08383 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
08384 if (sscanf(s, "%d", &x) == 1) {
08385 maxlogins = x;
08386 } else {
08387 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
08388 }
08389 }
08390
08391
08392 if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename")))
08393 astforcename = "no";
08394 ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
08395
08396
08397 if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings")))
08398 astforcegreet = "no";
08399 ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
08400
08401 if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
08402 if (option_debug > 2)
08403 ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
08404 stringp = ast_strdupa(s);
08405 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
08406 if (!ast_strlen_zero(stringp)) {
08407 q = strsep(&stringp,",");
08408 while ((*q == ' ')||(*q == '\t'))
08409 q++;
08410 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
08411 if (option_debug > 2)
08412 ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
08413 } else {
08414 cidinternalcontexts[x][0] = '\0';
08415 }
08416 }
08417 }
08418 if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
08419 if (option_debug)
08420 ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
08421 astreview = "no";
08422 }
08423 ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);
08424
08425
08426 if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
08427 if (option_debug)
08428 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option disabled globally\n");
08429 asttempgreetwarn = "no";
08430 } else {
08431 if (option_debug)
08432 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option enabled globally\n");
08433 }
08434 ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
08435
08436 if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
08437 if (option_debug)
08438 ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
08439 astcallop = "no";
08440 }
08441 ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);
08442
08443 if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
08444 if (option_debug)
08445 ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
08446 astsaycid = "no";
08447 }
08448 ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);
08449
08450 if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
08451 if (option_debug)
08452 ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
08453 send_voicemail = "no";
08454 }
08455 ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
08456
08457 if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
08458 if (option_debug)
08459 ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
08460 asthearenv = "yes";
08461 }
08462 ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);
08463
08464 if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
08465 if (option_debug)
08466 ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
08467 astsaydurationinfo = "yes";
08468 }
08469 ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);
08470
08471 saydurationminfo = 2;
08472 if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
08473 if (sscanf(astsaydurationminfo, "%d", &x) == 1) {
08474 saydurationminfo = x;
08475 } else {
08476 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
08477 }
08478 }
08479
08480 if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
08481 if (option_debug)
08482 ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
08483 astskipcmd = "no";
08484 }
08485 ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
08486
08487 if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
08488 ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
08489 if (option_debug)
08490 ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
08491 } else {
08492 dialcontext[0] = '\0';
08493 }
08494
08495 if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
08496 ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
08497 if (option_debug)
08498 ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
08499 } else {
08500 callcontext[0] = '\0';
08501 }
08502
08503 if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
08504 ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
08505 if (option_debug)
08506 ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
08507 } else {
08508 exitcontext[0] = '\0';
08509 }
08510
08511 if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory")))
08512 astdirfwd = "no";
08513 ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);
08514 if ((ucfg = ast_config_load("users.conf"))) {
08515 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
08516 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
08517 continue;
08518 if ((cur = find_or_create(userscontext, cat))) {
08519 populate_defaults(cur);
08520 apply_options_full(cur, ast_variable_browse(ucfg, cat));
08521 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
08522 }
08523 }
08524 ast_config_destroy(ucfg);
08525 }
08526 cat = ast_category_browse(cfg, NULL);
08527 while (cat) {
08528 if (strcasecmp(cat, "general")) {
08529 var = ast_variable_browse(cfg, cat);
08530 if (strcasecmp(cat, "zonemessages")) {
08531
08532 while (var) {
08533 append_mailbox(cat, var->name, var->value);
08534 var = var->next;
08535 }
08536 } else {
08537
08538 while (var) {
08539 struct vm_zone *z;
08540 if ((z = ast_malloc(sizeof(*z)))) {
08541 char *msg_format, *timezone;
08542 msg_format = ast_strdupa(var->value);
08543 timezone = strsep(&msg_format, "|");
08544 if (msg_format) {
08545 ast_copy_string(z->name, var->name, sizeof(z->name));
08546 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
08547 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
08548 AST_LIST_LOCK(&zones);
08549 AST_LIST_INSERT_HEAD(&zones, z, list);
08550 AST_LIST_UNLOCK(&zones);
08551 } else {
08552 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
08553 free(z);
08554 }
08555 } else {
08556 free(z);
08557 AST_LIST_UNLOCK(&users);
08558 ast_config_destroy(cfg);
08559 return -1;
08560 }
08561 var = var->next;
08562 }
08563 }
08564 }
08565 cat = ast_category_browse(cfg, cat);
08566 }
08567 memset(fromstring,0,sizeof(fromstring));
08568 memset(pagerfromstring,0,sizeof(pagerfromstring));
08569 memset(emailtitle,0,sizeof(emailtitle));
08570 strcpy(charset, "ISO-8859-1");
08571 if (emailbody) {
08572 free(emailbody);
08573 emailbody = NULL;
08574 }
08575 if (emailsubject) {
08576 free(emailsubject);
08577 emailsubject = NULL;
08578 }
08579 if (pagerbody) {
08580 free(pagerbody);
08581 pagerbody = NULL;
08582 }
08583 if (pagersubject) {
08584 free(pagersubject);
08585 pagersubject = NULL;
08586 }
08587 if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
08588 ast_set2_flag((&globalflags), ast_true(s), VM_PBXSKIP);
08589 if ((s = ast_variable_retrieve(cfg, "general", "fromstring")))
08590 ast_copy_string(fromstring,s,sizeof(fromstring));
08591 if ((s = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
08592 ast_copy_string(pagerfromstring,s,sizeof(pagerfromstring));
08593 if ((s = ast_variable_retrieve(cfg, "general", "charset")))
08594 ast_copy_string(charset,s,sizeof(charset));
08595 if ((s = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
08596 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
08597 for (x = 0; x < 4; x++) {
08598 memcpy(&adsifdn[x], &tmpadsi[x], 1);
08599 }
08600 }
08601 if ((s = ast_variable_retrieve(cfg, "general", "adsisec"))) {
08602 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
08603 for (x = 0; x < 4; x++) {
08604 memcpy(&adsisec[x], &tmpadsi[x], 1);
08605 }
08606 }
08607 if ((s = ast_variable_retrieve(cfg, "general", "adsiver")))
08608 if (atoi(s)) {
08609 adsiver = atoi(s);
08610 }
08611 if ((s = ast_variable_retrieve(cfg, "general", "emailtitle"))) {
08612 ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
08613 ast_copy_string(emailtitle,s,sizeof(emailtitle));
08614 }
08615 if ((s = ast_variable_retrieve(cfg, "general", "emailsubject")))
08616 emailsubject = ast_strdup(s);
08617 if ((s = ast_variable_retrieve(cfg, "general", "emailbody"))) {
08618 char *tmpread, *tmpwrite;
08619 emailbody = ast_strdup(s);
08620
08621
08622 tmpread = tmpwrite = emailbody;
08623 while ((tmpwrite = strchr(tmpread,'\\'))) {
08624 switch (tmpwrite[1]) {
08625 case 'r':
08626 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08627 *tmpwrite = '\r';
08628 break;
08629 case 'n':
08630 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08631 *tmpwrite = '\n';
08632 break;
08633 case 't':
08634 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08635 *tmpwrite = '\t';
08636 break;
08637 default:
08638 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
08639 }
08640 tmpread = tmpwrite + 1;
08641 }
08642 }
08643 if ((s = ast_variable_retrieve(cfg, "general", "tz"))) {
08644 ast_copy_string(zonetag, s, sizeof(zonetag));
08645 }
08646 if ((s = ast_variable_retrieve(cfg, "general", "pagersubject")))
08647 pagersubject = ast_strdup(s);
08648 if ((s = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
08649 char *tmpread, *tmpwrite;
08650 pagerbody = ast_strdup(s);
08651
08652
08653 tmpread = tmpwrite = pagerbody;
08654 while ((tmpwrite = strchr(tmpread, '\\'))) {
08655 switch (tmpwrite[1]) {
08656 case 'r':
08657 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08658 *tmpwrite = '\r';
08659 break;
08660 case 'n':
08661 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08662 *tmpwrite = '\n';
08663 break;
08664 case 't':
08665 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08666 *tmpwrite = '\t';
08667 break;
08668 default:
08669 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
08670 }
08671 tmpread = tmpwrite + 1;
08672 }
08673 }
08674 AST_LIST_UNLOCK(&users);
08675 ast_config_destroy(cfg);
08676 return 0;
08677 } else {
08678 AST_LIST_UNLOCK(&users);
08679 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
08680 return 0;
08681 }
08682 }
08683
08684 static int reload(void)
08685 {
08686 return(load_config());
08687 }
08688
08689 static int unload_module(void)
08690 {
08691 int res;
08692
08693 res = ast_unregister_application(app);
08694 res |= ast_unregister_application(app2);
08695 res |= ast_unregister_application(app3);
08696 res |= ast_unregister_application(app4);
08697 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
08698 ast_uninstall_vm_functions();
08699
08700 ast_module_user_hangup_all();
08701
08702 return res;
08703 }
08704
08705 static int load_module(void)
08706 {
08707 int res;
08708 char *adsi_loaded = ast_module_helper("", "res_adsi.so", 0, 0, 0, 0);
08709 free(adsi_loaded);
08710 if (!adsi_loaded) {
08711
08712 adsi_loaded = ast_module_helper("", "res_adsi", 0, 0, 0, 0);
08713 ast_free(adsi_loaded);
08714 if (!adsi_loaded) {
08715 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_adsi.so\n");
08716 return AST_MODULE_LOAD_DECLINE;
08717 }
08718 }
08719
08720 my_umask = umask(0);
08721 umask(my_umask);
08722 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
08723 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
08724 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
08725 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
08726 if (res)
08727 return(res);
08728
08729 if ((res=load_config())) {
08730 return(res);
08731 }
08732
08733 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
08734
08735
08736 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
08737
08738 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
08739
08740 return res;
08741 }
08742
08743 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
08744 {
08745 int cmd = 0;
08746 char destination[80] = "";
08747 int retries = 0;
08748
08749 if (!num) {
08750 if (option_verbose > 2)
08751 ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
08752 while (retries < 3 && cmd != 't') {
08753 destination[1] = '\0';
08754 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
08755 if (!cmd)
08756 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
08757 if (!cmd)
08758 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
08759 if (!cmd) {
08760 cmd = ast_waitfordigit(chan, 6000);
08761 if (cmd)
08762 destination[0] = cmd;
08763 }
08764 if (!cmd) {
08765 retries++;
08766 } else {
08767
08768 if (cmd < 0)
08769 return 0;
08770 if (cmd == '*') {
08771 if (option_verbose > 2)
08772 ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
08773 return 0;
08774 }
08775 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
08776 retries++;
08777 else
08778 cmd = 't';
08779 }
08780 }
08781 if (retries >= 3) {
08782 return 0;
08783 }
08784
08785 } else {
08786 if (option_verbose > 2)
08787 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
08788 ast_copy_string(destination, num, sizeof(destination));
08789 }
08790
08791 if (!ast_strlen_zero(destination)) {
08792 if (destination[strlen(destination) -1 ] == '*')
08793 return 0;
08794 if (option_verbose > 2)
08795 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
08796 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
08797 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
08798 chan->priority = 0;
08799 return 9;
08800 }
08801 return 0;
08802 }
08803
08804 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)
08805 {
08806 int res = 0;
08807 char filename[PATH_MAX];
08808 struct ast_config *msg_cfg = NULL;
08809 const char *origtime, *context;
08810 char *cid, *name, *num;
08811 int retries = 0;
08812
08813 vms->starting = 0;
08814 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08815
08816
08817 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
08818 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
08819 RETRIEVE(vms->curdir, vms->curmsg, vmu);
08820 msg_cfg = ast_config_load(filename);
08821 DISPOSE(vms->curdir, vms->curmsg);
08822 if (!msg_cfg) {
08823 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
08824 return 0;
08825 }
08826
08827 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
08828 ast_config_destroy(msg_cfg);
08829 return 0;
08830 }
08831
08832 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
08833
08834 context = ast_variable_retrieve(msg_cfg, "message", "context");
08835 if (!strncasecmp("macro",context,5))
08836 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
08837 switch (option) {
08838 case 3:
08839 if (!res)
08840 res = play_message_datetime(chan, vmu, origtime, filename);
08841 if (!res)
08842 res = play_message_callerid(chan, vms, cid, context, 0);
08843
08844 res = 't';
08845 break;
08846
08847 case 2:
08848
08849 if (ast_strlen_zero(cid))
08850 break;
08851
08852 ast_callerid_parse(cid, &name, &num);
08853 while ((res > -1) && (res != 't')) {
08854 switch (res) {
08855 case '1':
08856 if (num) {
08857
08858 res = dialout(chan, vmu, num, vmu->callback);
08859 if (res) {
08860 ast_config_destroy(msg_cfg);
08861 return 9;
08862 }
08863 } else {
08864 res = '2';
08865 }
08866 break;
08867
08868 case '2':
08869
08870 if (!ast_strlen_zero(vmu->dialout)) {
08871 res = dialout(chan, vmu, NULL, vmu->dialout);
08872 if (res) {
08873 ast_config_destroy(msg_cfg);
08874 return 9;
08875 }
08876 } else {
08877 if (option_verbose > 2)
08878 ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
08879 res = ast_play_and_wait(chan, "vm-sorry");
08880 }
08881 ast_config_destroy(msg_cfg);
08882 return res;
08883 case '*':
08884 res = 't';
08885 break;
08886 case '3':
08887 case '4':
08888 case '5':
08889 case '6':
08890 case '7':
08891 case '8':
08892 case '9':
08893 case '0':
08894
08895 res = ast_play_and_wait(chan, "vm-sorry");
08896 retries++;
08897 break;
08898 default:
08899 if (num) {
08900 if (option_verbose > 2)
08901 ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
08902 res = ast_play_and_wait(chan, "vm-num-i-have");
08903 if (!res)
08904 res = play_message_callerid(chan, vms, num, vmu->context, 1);
08905 if (!res)
08906 res = ast_play_and_wait(chan, "vm-tocallnum");
08907
08908 if (!ast_strlen_zero(vmu->dialout)) {
08909 if (!res)
08910 res = ast_play_and_wait(chan, "vm-calldiffnum");
08911 }
08912 } else {
08913 res = ast_play_and_wait(chan, "vm-nonumber");
08914 if (!ast_strlen_zero(vmu->dialout)) {
08915 if (!res)
08916 res = ast_play_and_wait(chan, "vm-toenternumber");
08917 }
08918 }
08919 if (!res)
08920 res = ast_play_and_wait(chan, "vm-star-cancel");
08921 if (!res)
08922 res = ast_waitfordigit(chan, 6000);
08923 if (!res) {
08924 retries++;
08925 if (retries > 3)
08926 res = 't';
08927 }
08928 break;
08929
08930 }
08931 if (res == 't')
08932 res = 0;
08933 else if (res == '*')
08934 res = -1;
08935 }
08936 break;
08937
08938 case 1:
08939
08940 if (ast_strlen_zero(cid))
08941 break;
08942
08943 ast_callerid_parse(cid, &name, &num);
08944 if (!num) {
08945 if (option_verbose > 2)
08946 ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
08947 if (!res)
08948 res = ast_play_and_wait(chan, "vm-nonumber");
08949 ast_config_destroy(msg_cfg);
08950 return res;
08951 } else {
08952 struct ast_vm_user vmu2;
08953 if (find_user(&vmu2, vmu->context, num)) {
08954 struct leave_vm_options leave_options;
08955 char mailbox[AST_MAX_EXTENSION * 2 + 2];
08956 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
08957
08958 if (option_verbose > 2)
08959 ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
08960
08961 memset(&leave_options, 0, sizeof(leave_options));
08962 leave_options.record_gain = record_gain;
08963 res = leave_voicemail(chan, mailbox, &leave_options);
08964 if (!res)
08965 res = 't';
08966 ast_config_destroy(msg_cfg);
08967 return res;
08968 } else {
08969
08970 if (option_verbose > 2)
08971 ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
08972 ast_play_and_wait(chan, "vm-nobox");
08973 res = 't';
08974 ast_config_destroy(msg_cfg);
08975 return res;
08976 }
08977 }
08978 res = 0;
08979
08980 break;
08981 }
08982
08983 #ifndef IMAP_STORAGE
08984 ast_config_destroy(msg_cfg);
08985
08986 if (!res) {
08987 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08988 vms->heard[msg] = 1;
08989 res = wait_file(chan, vms, vms->fn);
08990 }
08991 #endif
08992 return res;
08993 }
08994
08995 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
08996 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
08997 signed char record_gain, struct vm_state *vms)
08998 {
08999
09000 int res = 0;
09001 int cmd = 0;
09002 int max_attempts = 3;
09003 int attempts = 0;
09004 int recorded = 0;
09005 int message_exists = 0;
09006 signed char zero_gain = 0;
09007 char tempfile[PATH_MAX];
09008 char *acceptdtmf = "#";
09009 char *canceldtmf = "";
09010
09011
09012
09013
09014 if (duration == NULL) {
09015 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
09016 return -1;
09017 }
09018
09019 if (!outsidecaller)
09020 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
09021 else
09022 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
09023
09024 cmd = '3';
09025
09026 while ((cmd >= 0) && (cmd != 't')) {
09027 switch (cmd) {
09028 case '1':
09029 if (!message_exists) {
09030
09031 cmd = '3';
09032 break;
09033 } else {
09034
09035 if (option_verbose > 2)
09036 ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
09037 if (!outsidecaller)
09038 ast_filerename(tempfile, recordfile, NULL);
09039 ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
09040 if (!outsidecaller) {
09041 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
09042 DISPOSE(recordfile, -1);
09043 }
09044 cmd = 't';
09045 return res;
09046 }
09047 case '2':
09048
09049 if (option_verbose > 2)
09050 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
09051 cmd = ast_stream_and_wait(chan, tempfile, chan->language, AST_DIGIT_ANY);
09052 break;
09053 case '3':
09054 message_exists = 0;
09055
09056 if (recorded == 1) {
09057 if (option_verbose > 2)
09058 ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
09059 } else {
09060 if (option_verbose > 2)
09061 ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
09062 }
09063 if (recorded && outsidecaller) {
09064 cmd = ast_play_and_wait(chan, INTRO);
09065 cmd = ast_play_and_wait(chan, "beep");
09066 }
09067 recorded = 1;
09068
09069 if (record_gain)
09070 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
09071 if (ast_test_flag(vmu, VM_OPERATOR))
09072 canceldtmf = "0";
09073 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
09074 if (record_gain)
09075 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
09076 if (cmd == -1) {
09077
09078 if (!outsidecaller) {
09079
09080 ast_filedelete(tempfile, NULL);
09081 }
09082 return cmd;
09083 }
09084 if (cmd == '0') {
09085 break;
09086 } else if (cmd == '*') {
09087 break;
09088 }
09089 #if 0
09090 else if (vmu->review && (*duration < 5)) {
09091
09092 if (option_verbose > 2)
09093 ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
09094 cmd = ast_play_and_wait(chan, "vm-tooshort");
09095 cmd = ast_filedelete(tempfile, NULL);
09096 break;
09097 }
09098 else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
09099
09100 if (option_verbose > 2)
09101 ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
09102 cmd = ast_filedelete(tempfile, NULL);
09103 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
09104 if (!cmd)
09105 cmd = ast_play_and_wait(chan, "vm-speakup");
09106 break;
09107 }
09108 #endif
09109 else {
09110
09111 message_exists = 1;
09112 cmd = 0;
09113 }
09114 break;
09115 case '4':
09116 case '5':
09117 case '6':
09118 case '7':
09119 case '8':
09120 case '9':
09121 case '*':
09122 case '#':
09123 cmd = ast_play_and_wait(chan, "vm-sorry");
09124 break;
09125 #if 0
09126
09127
09128 case '*':
09129
09130 cmd = ast_play_and_wait(chan, "vm-deleted");
09131 cmd = ast_filedelete(tempfile, NULL);
09132 if (outsidecaller) {
09133 res = vm_exec(chan, NULL);
09134 return res;
09135 }
09136 else
09137 return 1;
09138 #endif
09139 case '0':
09140 if (!ast_test_flag(vmu, VM_OPERATOR)) {
09141 cmd = ast_play_and_wait(chan, "vm-sorry");
09142 break;
09143 }
09144 if (message_exists || recorded) {
09145 cmd = ast_play_and_wait(chan, "vm-saveoper");
09146 if (!cmd)
09147 cmd = ast_waitfordigit(chan, 3000);
09148 if (cmd == '1') {
09149 ast_play_and_wait(chan, "vm-msgsaved");
09150 cmd = '0';
09151 } else {
09152 ast_play_and_wait(chan, "vm-deleted");
09153 DELETE(recordfile, -1, recordfile, vmu);
09154 cmd = '0';
09155 }
09156 }
09157 return cmd;
09158 default:
09159
09160
09161
09162 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
09163 return cmd;
09164 if (message_exists) {
09165 cmd = ast_play_and_wait(chan, "vm-review");
09166 }
09167 else {
09168 cmd = ast_play_and_wait(chan, "vm-torerecord");
09169 if (!cmd)
09170 cmd = ast_waitfordigit(chan, 600);
09171 }
09172
09173 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
09174 cmd = ast_play_and_wait(chan, "vm-reachoper");
09175 if (!cmd)
09176 cmd = ast_waitfordigit(chan, 600);
09177 }
09178 #if 0
09179 if (!cmd)
09180 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
09181 #endif
09182 if (!cmd)
09183 cmd = ast_waitfordigit(chan, 6000);
09184 if (!cmd) {
09185 attempts++;
09186 }
09187 if (attempts > max_attempts) {
09188 cmd = 't';
09189 }
09190 }
09191 }
09192 if (outsidecaller)
09193 ast_play_and_wait(chan, "vm-goodbye");
09194 if (cmd == 't')
09195 cmd = 0;
09196 return cmd;
09197 }
09198
09199
09200
09201
09202
09203 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
09204 .load = load_module,
09205 .unload = unload_module,
09206 .reload = reload,
09207 );