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: 316707 $")
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 #include "asterisk/astobj2.h"
00106 #ifdef ODBC_STORAGE
00107 #include "asterisk/res_odbc.h"
00108 #endif
00109
00110 #ifdef IMAP_STORAGE
00111 #include "asterisk/threadstorage.h"
00112
00113 AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
00114 static char imaptemp[1024];
00115 static char imapserver[48];
00116 static char imapport[8];
00117 static char imapflags[128];
00118 static char imapfolder[64];
00119 static char authuser[32];
00120 static char authpassword[42];
00121 static int imapversion = 1;
00122
00123 static int expungeonhangup = 1;
00124 static char delimiter = '\0';
00125 static const long DEFAULT_IMAP_TCP_TIMEOUT = 60L;
00126
00127 struct vm_state;
00128 struct ast_vm_user;
00129
00130 AST_THREADSTORAGE(ts_vmstate, ts_vmstate_init);
00131
00132 static int init_mailstream (struct vm_state *vms, int box);
00133 static void write_file (char *filename, char *buffer, unsigned long len);
00134
00135 static char *get_header_by_tag(char *header, char *tag);
00136 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00137 static char *get_user_by_mailbox(char *mailbox);
00138 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
00139 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00140 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00141 static void vmstate_insert(struct vm_state *vms);
00142 static void vmstate_delete(struct vm_state *vms);
00143 static void set_update(MAILSTREAM * stream);
00144 static void init_vm_state(struct vm_state *vms);
00145 static void copy_msgArray(struct vm_state *dst, struct vm_state *src);
00146 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00147 static void get_mailbox_delimiter(MAILSTREAM *stream);
00148 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00149 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00150 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);
00151 static void check_quota(struct vm_state *vms, char *mailbox);
00152 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
00153 struct vmstate {
00154 struct vm_state *vms;
00155 struct vmstate *next;
00156 };
00157 AST_MUTEX_DEFINE_STATIC(vmstate_lock);
00158 static struct vmstate *vmstates = NULL;
00159 #endif
00160
00161 #define SMDI_MWI_WAIT_TIMEOUT 1000
00162
00163 #define COMMAND_TIMEOUT 5000
00164
00165 #define VOICEMAIL_DIR_MODE 0777
00166 #define VOICEMAIL_FILE_MODE 0666
00167 #define CHUNKSIZE 65536
00168
00169 #define VOICEMAIL_CONFIG "voicemail.conf"
00170 #define ASTERISK_USERNAME "asterisk"
00171
00172
00173
00174 #define SENDMAIL "/usr/sbin/sendmail -t"
00175
00176 #define INTRO "vm-intro"
00177
00178 #define MAXMSG 100
00179 #ifndef IMAP_STORAGE
00180 #define MAXMSGLIMIT 9999
00181 #else
00182 #define MAXMSGLIMIT 255
00183 #endif
00184
00185 #define BASEMAXINLINE 256
00186 #define BASELINELEN 72
00187 #define BASEMAXINLINE 256
00188 #ifdef IMAP_STORAGE
00189 #define ENDL "\r\n"
00190 #else
00191 #define ENDL "\n"
00192 #endif
00193
00194 #define MAX_DATETIME_FORMAT 512
00195 #define MAX_NUM_CID_CONTEXTS 10
00196
00197 #define VM_REVIEW (1 << 0)
00198 #define VM_OPERATOR (1 << 1)
00199 #define VM_SAYCID (1 << 2)
00200 #define VM_SVMAIL (1 << 3)
00201 #define VM_ENVELOPE (1 << 4)
00202 #define VM_SAYDURATION (1 << 5)
00203 #define VM_SKIPAFTERCMD (1 << 6)
00204 #define VM_FORCENAME (1 << 7)
00205 #define VM_FORCEGREET (1 << 8)
00206 #define VM_PBXSKIP (1 << 9)
00207 #define VM_DIRECFORWARD (1 << 10)
00208 #define VM_ATTACH (1 << 11)
00209 #define VM_DELETE (1 << 12)
00210 #define VM_ALLOCED (1 << 13)
00211 #define VM_SEARCH (1 << 14)
00212 #define VM_TEMPGREETWARN (1 << 15)
00213 #define ERROR_LOCK_PATH -100
00214 #define ERROR_MAILBOX_FULL -200
00215 #define OPERATOR_EXIT 300
00216
00217
00218 enum {
00219 OPT_SILENT = (1 << 0),
00220 OPT_BUSY_GREETING = (1 << 1),
00221 OPT_UNAVAIL_GREETING = (1 << 2),
00222 OPT_RECORDGAIN = (1 << 3),
00223 OPT_PREPEND_MAILBOX = (1 << 4),
00224 OPT_PRIORITY_JUMP = (1 << 5),
00225 OPT_AUTOPLAY = (1 << 6),
00226 } vm_option_flags;
00227
00228 enum {
00229 OPT_ARG_RECORDGAIN = 0,
00230 OPT_ARG_PLAYFOLDER = 1,
00231
00232 OPT_ARG_ARRAY_SIZE = 2,
00233 } vm_option_args;
00234
00235 AST_APP_OPTIONS(vm_app_options, {
00236 AST_APP_OPTION('s', OPT_SILENT),
00237 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00238 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00239 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00240 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00241 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00242 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00243 });
00244
00245 static int load_config(void);
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 struct baseio {
00329 int iocp;
00330 int iolen;
00331 int linelength;
00332 int ateof;
00333 unsigned char iobuf[BASEMAXINLINE];
00334 };
00335
00336
00337 struct ast_vm_user {
00338 char context[AST_MAX_CONTEXT];
00339 char mailbox[AST_MAX_EXTENSION];
00340 char password[80];
00341 char fullname[80];
00342 char email[80];
00343 char pager[80];
00344 char serveremail[80];
00345 char mailcmd[160];
00346 char language[MAX_LANGUAGE];
00347 char zonetag[80];
00348 char callback[80];
00349 char dialout[80];
00350 char uniqueid[80];
00351 char exit[80];
00352 char attachfmt[20];
00353 unsigned int flags;
00354 int saydurationm;
00355 int maxmsg;
00356 #ifdef IMAP_STORAGE
00357 char imapuser[80];
00358 char imappassword[80];
00359 char imapvmshareid[80];
00360 int imapversion;
00361 #endif
00362 double volgain;
00363 AST_LIST_ENTRY(ast_vm_user) list;
00364 };
00365
00366 struct vm_zone {
00367 AST_LIST_ENTRY(vm_zone) list;
00368 char name[80];
00369 char timezone[80];
00370 char msg_format[512];
00371 };
00372
00373 struct vm_state {
00374 char curbox[80];
00375 char username[80];
00376 char context[80];
00377 char curdir[PATH_MAX];
00378 char vmbox[PATH_MAX];
00379 char fn[PATH_MAX];
00380 char fn2[PATH_MAX];
00381 int *deleted;
00382 int *heard;
00383 int dh_arraysize;
00384 int curmsg;
00385 int lastmsg;
00386 int newmessages;
00387 int oldmessages;
00388 int starting;
00389 int repeats;
00390 #ifdef IMAP_STORAGE
00391 ast_mutex_t lock;
00392 int updated;
00393 long msgArray[256];
00394 MAILSTREAM *mailstream;
00395 int vmArrayIndex;
00396 char imapuser[80];
00397 int imapversion;
00398 int interactive;
00399 unsigned int quota_limit;
00400 unsigned int quota_usage;
00401 struct vm_state *persist_vms;
00402 #endif
00403 };
00404 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);
00405 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00406 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00407 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00408 signed char record_gain, struct vm_state *vms);
00409 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00410 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00411 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
00412 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *folder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00413 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00414 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00415 #endif
00416 static void apply_options(struct ast_vm_user *vmu, const char *options);
00417
00418 struct ao2_container *inprocess_container;
00419
00420 struct inprocess {
00421 int count;
00422 char *context;
00423 char mailbox[0];
00424 };
00425
00426 static int inprocess_hash_fn(const void *obj, const int flags)
00427 {
00428 const struct inprocess *i = obj;
00429 return atoi(i->mailbox);
00430 }
00431
00432 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00433 {
00434 struct inprocess *i = obj, *j = arg;
00435 if (strcmp(i->mailbox, j->mailbox)) {
00436 return 0;
00437 }
00438 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00439 }
00440
00441 static int inprocess_count(const char *context, const char *mailbox, int delta)
00442 {
00443 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00444 arg->context = arg->mailbox + strlen(mailbox) + 1;
00445 strcpy(arg->mailbox, mailbox);
00446 strcpy(arg->context, context);
00447 ao2_lock(inprocess_container);
00448 if ((i = ao2_find(inprocess_container, arg, 0))) {
00449 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00450 ao2_unlock(inprocess_container);
00451 ao2_ref(i, -1);
00452 return ret;
00453 }
00454 if (delta < 0) {
00455 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00456 }
00457 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00458 ao2_unlock(inprocess_container);
00459 return 0;
00460 }
00461 i->context = i->mailbox + strlen(mailbox) + 1;
00462 strcpy(i->mailbox, mailbox);
00463 strcpy(i->context, context);
00464 i->count = delta;
00465 ao2_link(inprocess_container, i);
00466 ao2_unlock(inprocess_container);
00467 ao2_ref(i, -1);
00468 return 0;
00469 }
00470
00471 #ifdef ODBC_STORAGE
00472 static char odbc_database[80];
00473 static char odbc_table[80];
00474 #define RETRIEVE(a,b,c) retrieve_file(a,b)
00475 #define DISPOSE(a,b) remove_file(a,b)
00476 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00477 #define EXISTS(a,b,c,d) (message_exists(a,b))
00478 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00479 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00480 #define DELETE(a,b,c,d) (delete_file(a,b))
00481 #else
00482 #ifdef IMAP_STORAGE
00483 #define RETRIEVE(a,b,c) imap_retrieve_file(a,b,c)
00484 #define DISPOSE(a,b) remove_file(a,b)
00485 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00486 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00487 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00488 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00489 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00490 #else
00491 #define RETRIEVE(a,b,c)
00492 #define DISPOSE(a,b)
00493 #define STORE(a,b,c,d,e,f,g,h,i)
00494 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00495 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00496 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00497 #define DELETE(a,b,c,d) (vm_delete(c))
00498 #endif
00499 #endif
00500
00501 static char VM_SPOOL_DIR[PATH_MAX];
00502
00503 static char ext_pass_cmd[128];
00504
00505 static int my_umask;
00506
00507 #if ODBC_STORAGE
00508 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00509 #elif IMAP_STORAGE
00510 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00511 #else
00512 #define tdesc "Comedian Mail (Voicemail System)"
00513 #endif
00514
00515 static char userscontext[AST_MAX_EXTENSION] = "default";
00516
00517 static char *addesc = "Comedian Mail";
00518
00519 static char *synopsis_vm =
00520 "Leave a Voicemail message";
00521
00522 static char *descrip_vm =
00523 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
00524 "application allows the calling party to leave a message for the specified\n"
00525 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00526 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00527 "specified mailbox does not exist.\n"
00528 " The Voicemail application will exit if any of the following DTMF digits are\n"
00529 "received:\n"
00530 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00531 " * - Jump to the 'a' extension in the current dialplan context.\n"
00532 " This application will set the following channel variable upon completion:\n"
00533 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00534 " application. The possible values are:\n"
00535 " SUCCESS | USEREXIT | FAILED\n\n"
00536 " Options:\n"
00537 " b - Play the 'busy' greeting to the calling party.\n"
00538 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00539 " message. The units are whole-number decibels (dB).\n"
00540 " Only works on supported technologies, which is Zap only.\n"
00541 " s - Skip the playback of instructions for leaving a message to the\n"
00542 " calling party.\n"
00543 " u - Play the 'unavailable' greeting.\n"
00544 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
00545 " error occurs.\n";
00546
00547 static char *synopsis_vmain =
00548 "Check Voicemail messages";
00549
00550 static char *descrip_vmain =
00551 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
00552 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00553 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00554 "calling party will be prompted to enter one. If a context is not specified,\n"
00555 "the 'default' context will be used.\n\n"
00556 " Options:\n"
00557 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00558 " is entered by the caller.\n"
00559 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00560 " message. The units are whole-number decibels (dB).\n"
00561 " s - Skip checking the passcode for the mailbox.\n"
00562 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00563 " Defaults to INBOX\n";
00564
00565 static char *synopsis_vm_box_exists =
00566 "Check to see if Voicemail mailbox exists";
00567
00568 static char *descrip_vm_box_exists =
00569 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
00570 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00571 "will be used.\n"
00572 " This application will set the following channel variable upon completion:\n"
00573 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00574 " MailboxExists application. Possible values include:\n"
00575 " SUCCESS | FAILED\n\n"
00576 " Options:\n"
00577 " j - Jump to priority n+101 if the mailbox is found.\n";
00578
00579 static char *synopsis_vmauthenticate =
00580 "Authenticate with Voicemail passwords";
00581
00582 static char *descrip_vmauthenticate =
00583 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
00584 "same way as the Authenticate application, but the passwords are taken from\n"
00585 "voicemail.conf.\n"
00586 " If the mailbox is specified, only that mailbox's password will be considered\n"
00587 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00588 "be set with the authenticated mailbox.\n\n"
00589 " Options:\n"
00590 " s - Skip playing the initial prompts.\n";
00591
00592
00593 static char *app = "VoiceMail";
00594
00595
00596 static char *app2 = "VoiceMailMain";
00597
00598 static char *app3 = "MailboxExists";
00599 static char *app4 = "VMAuthenticate";
00600
00601 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00602 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00603 static char zonetag[80];
00604 static int maxsilence;
00605 static int maxmsg;
00606 static int silencethreshold = 128;
00607 static char serveremail[80];
00608 static char mailcmd[160];
00609 static char externnotify[160];
00610 static struct ast_smdi_interface *smdi_iface = NULL;
00611 static char vmfmts[80];
00612 static double volgain;
00613 static int vmminmessage;
00614 static int vmmaxmessage;
00615 static int maxgreet;
00616 static int skipms;
00617 static int maxlogins;
00618
00619 static struct ast_flags globalflags = {0};
00620
00621 static int saydurationminfo;
00622
00623 static char dialcontext[AST_MAX_CONTEXT];
00624 static char callcontext[AST_MAX_CONTEXT];
00625 static char exitcontext[AST_MAX_CONTEXT];
00626
00627 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00628
00629
00630 static char *emailbody = NULL;
00631 static char *emailsubject = NULL;
00632 static char *pagerbody = NULL;
00633 static char *pagersubject = NULL;
00634 static char fromstring[100];
00635 static char pagerfromstring[100];
00636 static char emailtitle[100];
00637 static char charset[32] = "ISO-8859-1";
00638
00639 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00640 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00641 static int adsiver = 1;
00642 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00643
00644
00645
00646
00647
00648
00649
00650
00651 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00652 {
00653 char *bufptr = buf;
00654 for (; *input; input++) {
00655 if (*input < 32) {
00656 continue;
00657 }
00658 *bufptr++ = *input;
00659 if (bufptr == buf + buflen - 1) {
00660 break;
00661 }
00662 }
00663 *bufptr = '\0';
00664 return buf;
00665 }
00666
00667 static void populate_defaults(struct ast_vm_user *vmu)
00668 {
00669 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00670 if (saydurationminfo)
00671 vmu->saydurationm = saydurationminfo;
00672 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00673 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00674 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00675 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00676 if (maxmsg)
00677 vmu->maxmsg = maxmsg;
00678 vmu->volgain = volgain;
00679 }
00680
00681 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00682 {
00683 int x;
00684 if (!strcasecmp(var, "attach")) {
00685 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00686 } else if (!strcasecmp(var, "attachfmt")) {
00687 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00688 } else if (!strcasecmp(var, "serveremail")) {
00689 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00690 } else if (!strcasecmp(var, "language")) {
00691 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00692 } else if (!strcasecmp(var, "tz")) {
00693 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00694 #ifdef IMAP_STORAGE
00695 } else if (!strcasecmp(var, "imapuser")) {
00696 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00697 vmu->imapversion = imapversion;
00698 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00699 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00700 vmu->imapversion = imapversion;
00701 } else if (!strcasecmp(var, "imapvmshareid")) {
00702 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00703 vmu->imapversion = imapversion;
00704 #endif
00705 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00706 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00707 } else if (!strcasecmp(var, "saycid")){
00708 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00709 } else if (!strcasecmp(var,"sendvoicemail")){
00710 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00711 } else if (!strcasecmp(var, "review")){
00712 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00713 } else if (!strcasecmp(var, "tempgreetwarn")){
00714 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00715 } else if (!strcasecmp(var, "operator")){
00716 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00717 } else if (!strcasecmp(var, "envelope")){
00718 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00719 } else if (!strcasecmp(var, "sayduration")){
00720 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00721 } else if (!strcasecmp(var, "saydurationm")){
00722 if (sscanf(value, "%30d", &x) == 1) {
00723 vmu->saydurationm = x;
00724 } else {
00725 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00726 }
00727 } else if (!strcasecmp(var, "forcename")){
00728 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00729 } else if (!strcasecmp(var, "forcegreetings")){
00730 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00731 } else if (!strcasecmp(var, "callback")) {
00732 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00733 } else if (!strcasecmp(var, "dialout")) {
00734 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00735 } else if (!strcasecmp(var, "exitcontext")) {
00736 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00737 } else if (!strcasecmp(var, "maxmsg")) {
00738 vmu->maxmsg = atoi(value);
00739 if (vmu->maxmsg <= 0) {
00740 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
00741 vmu->maxmsg = MAXMSG;
00742 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00743 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00744 vmu->maxmsg = MAXMSGLIMIT;
00745 }
00746 } else if (!strcasecmp(var, "volgain")) {
00747 sscanf(value, "%30lf", &vmu->volgain);
00748 } else if (!strcasecmp(var, "options")) {
00749 apply_options(vmu, value);
00750 }
00751 }
00752
00753 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00754 {
00755 int res = -1;
00756 if (!strcmp(vmu->password, password)) {
00757
00758 res = 0;
00759 } else if (!ast_strlen_zero(vmu->uniqueid)) {
00760 if (ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL) > 0) {
00761 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00762 res = 0;
00763 }
00764 }
00765 return res;
00766 }
00767
00768 static void apply_options(struct ast_vm_user *vmu, const char *options)
00769 {
00770 char *stringp;
00771 char *s;
00772 char *var, *value;
00773 stringp = ast_strdupa(options);
00774 while ((s = strsep(&stringp, "|"))) {
00775 value = s;
00776 if ((var = strsep(&value, "=")) && value) {
00777 apply_option(vmu, var, value);
00778 }
00779 }
00780 }
00781
00782 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00783 {
00784 struct ast_variable *tmp;
00785 tmp = var;
00786 while (tmp) {
00787 if (!strcasecmp(tmp->name, "vmsecret")) {
00788 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00789 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00790 if (ast_strlen_zero(retval->password))
00791 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00792 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00793 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00794 } else if (!strcasecmp(tmp->name, "pager")) {
00795 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00796 } else if (!strcasecmp(tmp->name, "email")) {
00797 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00798 } else if (!strcasecmp(tmp->name, "fullname")) {
00799 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00800 } else if (!strcasecmp(tmp->name, "context")) {
00801 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00802 #ifdef IMAP_STORAGE
00803 } else if (!strcasecmp(tmp->name, "imapuser")) {
00804 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00805 retval->imapversion = imapversion;
00806 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
00807 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00808 retval->imapversion = imapversion;
00809 } else if (!strcasecmp(tmp->name, "imapvmshareid")) {
00810 ast_copy_string(retval->imapvmshareid, tmp->value, sizeof(retval->imapvmshareid));
00811 retval->imapversion = imapversion;
00812 #endif
00813 } else
00814 apply_option(retval, tmp->name, tmp->value);
00815 tmp = tmp->next;
00816 }
00817 }
00818
00819 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00820 {
00821 struct ast_variable *var;
00822 struct ast_vm_user *retval;
00823
00824 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00825 if (!ivm)
00826 ast_set_flag(retval, VM_ALLOCED);
00827 else
00828 memset(retval, 0, sizeof(*retval));
00829 if (mailbox)
00830 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00831 populate_defaults(retval);
00832 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00833 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00834 else
00835 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00836 if (var) {
00837 apply_options_full(retval, var);
00838 ast_variables_destroy(var);
00839 } else {
00840 if (!ivm)
00841 free(retval);
00842 retval = NULL;
00843 }
00844 }
00845 return retval;
00846 }
00847
00848 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00849 {
00850
00851 struct ast_vm_user *vmu=NULL, *cur;
00852 AST_LIST_LOCK(&users);
00853
00854 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00855 context = "default";
00856
00857 AST_LIST_TRAVERSE(&users, cur, list) {
00858 #ifdef IMAP_STORAGE
00859 if (cur->imapversion != imapversion) {
00860 continue;
00861 }
00862 #endif
00863 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00864 break;
00865 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00866 break;
00867 }
00868 if (cur) {
00869
00870 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00871 memcpy(vmu, cur, sizeof(*vmu));
00872 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00873 AST_LIST_NEXT(vmu, list) = NULL;
00874 }
00875 } else
00876 vmu = find_user_realtime(ivm, context, mailbox);
00877 AST_LIST_UNLOCK(&users);
00878 return vmu;
00879 }
00880
00881 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00882 {
00883
00884 struct ast_vm_user *cur;
00885 int res = -1;
00886 AST_LIST_LOCK(&users);
00887 AST_LIST_TRAVERSE(&users, cur, list) {
00888 if ((!context || !strcasecmp(context, cur->context)) &&
00889 (!strcasecmp(mailbox, cur->mailbox)))
00890 break;
00891 }
00892 if (cur) {
00893 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00894 res = 0;
00895 }
00896 AST_LIST_UNLOCK(&users);
00897 return res;
00898 }
00899
00900 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00901 {
00902 struct ast_config *cfg=NULL;
00903 struct ast_variable *var=NULL;
00904 struct ast_category *cat=NULL;
00905 char *category=NULL, *value=NULL, *new=NULL;
00906 const char *tmp=NULL;
00907
00908 if (!change_password_realtime(vmu, newpassword))
00909 return;
00910
00911
00912 if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
00913 while ((category = ast_category_browse(cfg, category))) {
00914 if (!strcasecmp(category, vmu->context)) {
00915 tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
00916 if (!tmp) {
00917 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00918 break;
00919 }
00920 value = strstr(tmp,",");
00921 if (!value) {
00922 new = alloca(strlen(newpassword)+1);
00923 sprintf(new, "%s", newpassword);
00924 } else {
00925 new = alloca((strlen(value)+strlen(newpassword)+1));
00926 sprintf(new,"%s%s", newpassword, value);
00927 }
00928 if (!(cat = ast_category_get(cfg, category))) {
00929 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00930 break;
00931 }
00932 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00933 }
00934 }
00935
00936 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00937 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00938 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
00939 }
00940 category = NULL;
00941 var = NULL;
00942
00943
00944 if ((cfg = ast_config_load_with_comments("users.conf"))) {
00945 if (option_debug > 3)
00946 ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
00947 while ((category = ast_category_browse(cfg, category))) {
00948 if (option_debug > 3)
00949 ast_log(LOG_DEBUG, "users.conf: %s\n", category);
00950 if (!strcasecmp(category, vmu->mailbox)) {
00951 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
00952 if (option_debug > 3)
00953 ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
00954 var = ast_variable_new("vmsecret", newpassword);
00955 }
00956 new = alloca(strlen(newpassword)+1);
00957 sprintf(new, "%s", newpassword);
00958 if (!(cat = ast_category_get(cfg, category))) {
00959 if (option_debug > 3)
00960 ast_log(LOG_DEBUG, "failed to get category!\n");
00961 break;
00962 }
00963 if (!var)
00964 ast_variable_update(cat, "vmsecret", new, NULL, 0);
00965 else
00966 ast_variable_append(cat, var);
00967 }
00968 }
00969
00970 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00971 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00972 config_text_file_save("users.conf", cfg, "AppVoicemail");
00973 }
00974 }
00975
00976 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
00977 {
00978 char buf[255];
00979 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
00980 if (!ast_safe_system(buf)) {
00981 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00982
00983 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00984 }
00985 }
00986
00987 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
00988 {
00989 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
00990 }
00991
00992 static int make_file(char *dest, const int len, const char *dir, const int num)
00993 {
00994 return snprintf(dest, len, "%s/msg%04d", dir, num);
00995 }
00996
00997
00998 static FILE *vm_mkftemp(char *template)
00999 {
01000 FILE *p = NULL;
01001 int pfd = mkstemp(template);
01002 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01003 if (pfd > -1) {
01004 p = fdopen(pfd, "w+");
01005 if (!p) {
01006 close(pfd);
01007 pfd = -1;
01008 }
01009 }
01010 return p;
01011 }
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01022 {
01023 mode_t mode = VOICEMAIL_DIR_MODE;
01024
01025 if (!ast_strlen_zero(context)) {
01026 make_dir(dest, len, context, "", "");
01027 if (mkdir(dest, mode) && errno != EEXIST) {
01028 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01029 return -1;
01030 }
01031 }
01032 if (!ast_strlen_zero(ext)) {
01033 make_dir(dest, len, context, ext, "");
01034 if (mkdir(dest, mode) && errno != EEXIST) {
01035 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01036 return -1;
01037 }
01038 }
01039 if (!ast_strlen_zero(folder)) {
01040 make_dir(dest, len, context, ext, folder);
01041 if (mkdir(dest, mode) && errno != EEXIST) {
01042 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
01043 return -1;
01044 }
01045 }
01046 return 0;
01047 }
01048
01049 static char *mbox(int id)
01050 {
01051 static char *msgs[] = {
01052 "INBOX",
01053 "Old",
01054 "Work",
01055 "Family",
01056 "Friends",
01057 "Cust1",
01058 "Cust2",
01059 "Cust3",
01060 "Cust4",
01061 "Cust5",
01062 };
01063 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp";
01064 }
01065
01066 static void free_user(struct ast_vm_user *vmu)
01067 {
01068 if (ast_test_flag(vmu, VM_ALLOCED))
01069 free(vmu);
01070 }
01071
01072 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01073
01074 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01075 if (!vms->dh_arraysize) {
01076
01077 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01078 return -1;
01079 }
01080 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01081 return -1;
01082 }
01083 vms->dh_arraysize = arraysize;
01084 } else if (vms->dh_arraysize < arraysize) {
01085 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01086 return -1;
01087 }
01088 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01089 return -1;
01090 }
01091 memset(vms->deleted, 0, arraysize * sizeof(int));
01092 memset(vms->heard, 0, arraysize * sizeof(int));
01093 vms->dh_arraysize = arraysize;
01094 }
01095
01096 return 0;
01097 }
01098
01099
01100
01101 #ifdef IMAP_STORAGE
01102 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01103 {
01104 char arg[10];
01105 struct vm_state *vms;
01106 unsigned long messageNum;
01107
01108
01109 if (msgnum < 0) {
01110 ast_filedelete(file, NULL);
01111 return;
01112 }
01113
01114 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01115 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);
01116 return;
01117 }
01118
01119
01120
01121 messageNum = vms->msgArray[msgnum];
01122 if (messageNum == 0) {
01123 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01124 return;
01125 }
01126 if (option_debug > 2)
01127 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01128
01129 snprintf (arg, sizeof(arg), "%lu",messageNum);
01130 ast_mutex_lock(&vms->lock);
01131 mail_setflag (vms->mailstream,arg,"\\DELETED");
01132 mail_expunge(vms->mailstream);
01133 ast_mutex_unlock(&vms->lock);
01134 }
01135
01136 static int imap_retrieve_file(const char *dir, const int msgnum, const struct ast_vm_user *vmu)
01137 {
01138 BODY *body;
01139 char *header_content;
01140 char *attachedfilefmt;
01141 const char *cid_num;
01142 const char *cid_name;
01143 const char *duration;
01144 const char *context;
01145 const char *category;
01146 const char *origtime;
01147 struct vm_state *vms;
01148 char text_file[PATH_MAX];
01149 FILE *text_file_ptr;
01150
01151
01152
01153
01154 if (msgnum < 0) {
01155 return 0;
01156 }
01157
01158
01159
01160
01161 if(!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01162
01163
01164
01165
01166
01167
01168
01169 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01170 return -1;
01171 }
01172
01173 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01174
01175
01176 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01177 return 0;
01178 }
01179
01180 if (option_debug > 2)
01181 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01182 if (vms->msgArray[msgnum] == 0) {
01183 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01184 return -1;
01185 }
01186
01187
01188 ast_mutex_lock(&vms->lock);
01189 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01190 ast_mutex_unlock(&vms->lock);
01191
01192 if (ast_strlen_zero(header_content)) {
01193 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01194 return -1;
01195 }
01196
01197 ast_mutex_lock(&vms->lock);
01198 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01199 ast_mutex_unlock(&vms->lock);
01200
01201
01202 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01203 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01204 } else {
01205 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01206 return -1;
01207 }
01208
01209
01210
01211 strsep(&attachedfilefmt, ".");
01212 if (!attachedfilefmt) {
01213 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01214 return -1;
01215 }
01216
01217 save_body(body, vms, "2", attachedfilefmt);
01218
01219
01220 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01221
01222 if (!(text_file_ptr = fopen(text_file, "w"))) {
01223 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01224 }
01225
01226 fprintf(text_file_ptr, "%s\n", "[message]");
01227
01228 cid_name = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:");
01229 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(cid_name, ""));
01230 cid_num = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
01231 fprintf(text_file_ptr, "<%s>\n", S_OR(cid_num, ""));
01232 context = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
01233 fprintf(text_file_ptr, "context=%s\n", S_OR(context, ""));
01234 origtime = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
01235 fprintf(text_file_ptr, "origtime=%s\n", S_OR(origtime, ""));
01236 duration = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
01237 fprintf(text_file_ptr, "duration=%s\n", S_OR(origtime, ""));
01238 category = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
01239 fprintf(text_file_ptr, "category=%s\n", S_OR(category, ""));
01240
01241 fclose(text_file_ptr);
01242 return 0;
01243 }
01244
01245 static int folder_int(const char *folder)
01246 {
01247
01248 if (!folder)
01249 return 0;
01250 if (!strcasecmp(folder, "INBOX"))
01251 return 0;
01252 else if (!strcasecmp(folder, "Old"))
01253 return 1;
01254 else if (!strcasecmp(folder, "Work"))
01255 return 2;
01256 else if (!strcasecmp(folder, "Family"))
01257 return 3;
01258 else if (!strcasecmp(folder, "Friends"))
01259 return 4;
01260 else if (!strcasecmp(folder, "Cust1"))
01261 return 5;
01262 else if (!strcasecmp(folder, "Cust2"))
01263 return 6;
01264 else if (!strcasecmp(folder, "Cust3"))
01265 return 7;
01266 else if (!strcasecmp(folder, "Cust4"))
01267 return 8;
01268 else if (!strcasecmp(folder, "Cust5"))
01269 return 9;
01270 else
01271 return 0;
01272 }
01273
01274 static int messagecount(const char *context, const char *mailbox, const char *folder)
01275 {
01276 SEARCHPGM *pgm;
01277 SEARCHHEADER *hdr;
01278
01279 struct ast_vm_user *vmu, vmus;
01280 struct vm_state *vms_p;
01281 int ret = 0;
01282 int fold = folder_int(folder);
01283
01284 if (ast_strlen_zero(mailbox))
01285 return 0;
01286
01287
01288
01289 vmu = find_user(&vmus, context, mailbox);
01290 if (!vmu) {
01291 ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
01292 return -1;
01293 } else {
01294
01295 if (vmu->imapuser[0] == '\0') {
01296 ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
01297 return -1;
01298 }
01299 }
01300
01301
01302 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01303 if (!vms_p) {
01304 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01305 }
01306 if (vms_p) {
01307 if (option_debug > 2)
01308 ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
01309 if (fold == 0) {
01310 return vms_p->newmessages;
01311 }
01312 if (fold == 1) {
01313 return vms_p->oldmessages;
01314 }
01315 }
01316
01317
01318 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01319 if (!vms_p) {
01320 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01321 }
01322
01323 if (!vms_p) {
01324 if (!(vms_p = create_vm_state_from_user(vmu))) {
01325 ast_log(LOG_WARNING, "Unable to allocate space for new vm_state!\n");
01326 return -1;
01327 }
01328 }
01329 ret = init_mailstream(vms_p, fold);
01330 if (!vms_p->mailstream) {
01331 ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
01332 return -1;
01333 }
01334 if (ret == 0) {
01335 ast_mutex_lock(&vms_p->lock);
01336 pgm = mail_newsearchpgm ();
01337 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01338 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01339 pgm->header = hdr;
01340 if (fold != 1) {
01341 pgm->unseen = 1;
01342 pgm->seen = 0;
01343 }
01344
01345
01346
01347 else {
01348 pgm->unseen = 0;
01349 pgm->seen = 1;
01350 }
01351 pgm->undeleted = 1;
01352 pgm->deleted = 0;
01353
01354 vms_p->vmArrayIndex = 0;
01355 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01356 if (fold == 0)
01357 vms_p->newmessages = vms_p->vmArrayIndex;
01358 if (fold == 1)
01359 vms_p->oldmessages = vms_p->vmArrayIndex;
01360
01361 mail_free_searchpgm(&pgm);
01362 ast_mutex_unlock(&vms_p->lock);
01363 vms_p->updated = 0;
01364 return vms_p->vmArrayIndex;
01365 } else {
01366 ast_mutex_lock(&vms_p->lock);
01367 mail_ping(vms_p->mailstream);
01368 ast_mutex_unlock(&vms_p->lock);
01369 }
01370 return 0;
01371 }
01372
01373 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
01374 {
01375
01376 check_quota(vms, imapfolder);
01377 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
01378 if (option_debug)
01379 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
01380 ast_play_and_wait(chan, "vm-mailboxfull");
01381 return -1;
01382 }
01383
01384
01385 if (option_debug > 2)
01386 ast_log(LOG_DEBUG, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
01387 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
01388 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
01389 ast_play_and_wait(chan, "vm-mailboxfull");
01390 inprocess_count(vmu->mailbox, vmu->context, -1);
01391 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
01392 return -1;
01393 }
01394 return 0;
01395 }
01396
01397 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)
01398 {
01399 char *myserveremail = serveremail;
01400 char fn[PATH_MAX];
01401 char mailbox[256];
01402 char *stringp;
01403 FILE *p=NULL;
01404 char tmp[80] = "/tmp/astmail-XXXXXX";
01405 long len;
01406 void *buf;
01407 int tempcopy = 0;
01408 STRING str;
01409 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
01410
01411
01412 if (msgnum < 0)
01413 return 0;
01414
01415 if (imap_check_limits(chan, vms, vmu, msgcount)) {
01416 return -1;
01417 }
01418
01419
01420 fmt = ast_strdupa(fmt);
01421 stringp = fmt;
01422 strsep(&stringp, "|");
01423
01424 if (!ast_strlen_zero(vmu->serveremail))
01425 myserveremail = vmu->serveremail;
01426
01427 make_file(fn, sizeof(fn), dir, msgnum);
01428
01429 if (ast_strlen_zero(vmu->email)) {
01430
01431
01432
01433
01434 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01435 tempcopy = 1;
01436 }
01437
01438 if (!strcmp(fmt, "wav49"))
01439 fmt = "WAV";
01440 if (option_debug > 2)
01441 ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
01442
01443
01444 if ((p = vm_mkftemp(tmp)) == NULL) {
01445 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01446 if (tempcopy)
01447 *(vmu->email) = '\0';
01448 return -1;
01449 } else {
01450 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, vms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
01451
01452 len = ftell(p);
01453 rewind(p);
01454 if ((buf = ast_malloc(len+1)) == NIL) {
01455 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
01456 fclose(p);
01457 return -1;
01458 }
01459 if (fread(buf, len, 1, p) != 1) {
01460 ast_log(LOG_WARNING, "Short read: %s\n", strerror(errno));
01461 }
01462 ((char *)buf)[len] = '\0';
01463 INIT(&str, mail_string, buf, len);
01464 init_mailstream(vms, 0);
01465 imap_mailbox_name(mailbox, sizeof(mailbox), vms, 0, 1);
01466 ast_mutex_lock(&vms->lock);
01467 if (!mail_append(vms->mailstream, mailbox, &str))
01468 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01469 ast_mutex_unlock(&vms->lock);
01470 fclose(p);
01471 unlink(tmp);
01472 ast_free(buf);
01473 if (option_debug > 2)
01474 ast_log(LOG_DEBUG, "%s stored\n", fn);
01475
01476
01477
01478 messagecount(vmu->context, vmu->mailbox, "INBOX");
01479 }
01480 if (tempcopy)
01481 *(vmu->email) = '\0';
01482 inprocess_count(vmu->mailbox, vmu->context, -1);
01483 return 0;
01484
01485 }
01486
01487 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01488 {
01489 char tmp[PATH_MAX] = "";
01490 char *mailboxnc;
01491 char *context;
01492 char *mb;
01493 char *cur;
01494 if (newmsgs)
01495 *newmsgs = 0;
01496 if (oldmsgs)
01497 *oldmsgs = 0;
01498
01499 if (option_debug > 2)
01500 ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context);
01501
01502 if (ast_strlen_zero(mailbox_context))
01503 return 0;
01504
01505 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01506 context = strchr(tmp, '@');
01507 if (strchr(mailbox_context, ',')) {
01508 int tmpnew, tmpold;
01509 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01510 mb = tmp;
01511 while ((cur = strsep(&mb, ", "))) {
01512 if (!ast_strlen_zero(cur)) {
01513 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01514 return -1;
01515 else {
01516 if (newmsgs)
01517 *newmsgs += tmpnew;
01518 if (oldmsgs)
01519 *oldmsgs += tmpold;
01520 }
01521 }
01522 }
01523 return 0;
01524 }
01525 if (context) {
01526 *context = '\0';
01527 mailboxnc = tmp;
01528 context++;
01529 } else {
01530 context = "default";
01531 mailboxnc = (char *)mailbox_context;
01532 }
01533 if (newmsgs) {
01534 if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0)
01535 return -1;
01536 }
01537 if (oldmsgs) {
01538 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01539 return -1;
01540 }
01541 return 0;
01542 }
01543
01544
01545 static int has_voicemail(const char *mailbox, const char *folder)
01546 {
01547 char tmp[256], *tmp2, *mbox, *context;
01548 ast_copy_string(tmp, mailbox, sizeof(tmp));
01549 tmp2 = tmp;
01550 if (strchr(tmp2, ',')) {
01551 while ((mbox = strsep(&tmp2, ","))) {
01552 if (!ast_strlen_zero(mbox)) {
01553 if (has_voicemail(mbox, folder))
01554 return 1;
01555 }
01556 }
01557 }
01558 if ((context= strchr(tmp, '@')))
01559 *context++ = '\0';
01560 else
01561 context = "default";
01562 return messagecount(context, tmp, folder) ? 1 : 0;
01563 }
01564
01565 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)
01566 {
01567 struct vm_state *sendvms = NULL, *destvms = NULL;
01568 char messagestring[10];
01569 if (msgnum >= recip->maxmsg) {
01570 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01571 return -1;
01572 }
01573 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01574 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01575 return -1;
01576 }
01577 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01578 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01579 return -1;
01580 }
01581 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01582 ast_mutex_lock(&sendvms->lock);
01583 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
01584 ast_mutex_unlock(&sendvms->lock);
01585 return 0;
01586 }
01587 ast_mutex_unlock(&sendvms->lock);
01588 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01589 return -1;
01590 }
01591
01592 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01593 {
01594 char tmp[256], *t = tmp;
01595 size_t left = sizeof(tmp);
01596
01597 if (box == 1) {
01598 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
01599 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1));
01600 } else {
01601 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01602 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
01603 }
01604
01605
01606 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
01607
01608
01609 if (!ast_strlen_zero(authuser))
01610 ast_build_string(&t, &left, "/authuser=%s", authuser);
01611
01612
01613 if (!ast_strlen_zero(imapflags))
01614 ast_build_string(&t, &left, "/%s", imapflags);
01615
01616
01617 #if 1
01618 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
01619 #else
01620 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
01621 #endif
01622
01623 if (box == 0 || box == 1)
01624 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
01625 else
01626 snprintf(spec, len, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
01627 }
01628
01629 static int init_mailstream(struct vm_state *vms, int box)
01630 {
01631 MAILSTREAM *stream = NIL;
01632 long debug;
01633 char tmp[256];
01634
01635 if (!vms) {
01636 ast_log (LOG_ERROR,"vm_state is NULL!\n");
01637 return -1;
01638 }
01639 if (option_debug > 2)
01640 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
01641 if (vms->mailstream == NIL || !vms->mailstream) {
01642 if (option_debug)
01643 ast_log (LOG_DEBUG,"mailstream not set.\n");
01644 } else {
01645 stream = vms->mailstream;
01646 }
01647
01648 debug = NIL;
01649
01650 if (delimiter == '\0') {
01651 char *cp;
01652 #ifdef USE_SYSTEM_IMAP
01653 #include <imap/linkage.c>
01654 #elif defined(USE_SYSTEM_CCLIENT)
01655 #include <c-client/linkage.c>
01656 #else
01657 #include "linkage.c"
01658 #endif
01659
01660 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
01661 ast_mutex_lock(&vms->lock);
01662 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01663 ast_mutex_unlock(&vms->lock);
01664 if (stream == NIL) {
01665 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
01666 return -1;
01667 }
01668 get_mailbox_delimiter(stream);
01669
01670 for (cp = imapfolder; *cp; cp++)
01671 if (*cp == '/')
01672 *cp = delimiter;
01673 }
01674
01675 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
01676 if (option_debug > 2)
01677 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
01678 ast_mutex_lock(&vms->lock);
01679 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01680 ast_mutex_unlock(&vms->lock);
01681 if (vms->mailstream == NIL) {
01682 return -1;
01683 } else {
01684 return 0;
01685 }
01686 }
01687
01688 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
01689 {
01690 SEARCHPGM *pgm;
01691 SEARCHHEADER *hdr;
01692 int ret;
01693
01694 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
01695 vms->imapversion = vmu->imapversion;
01696
01697 if (option_debug > 2)
01698 ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
01699 ret = init_mailstream(vms, box);
01700 if (ret != 0 || !vms->mailstream) {
01701 ast_log (LOG_ERROR,"Could not initialize mailstream\n");
01702 return -1;
01703 }
01704
01705 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
01706
01707
01708 if (box == 0) {
01709 if (option_debug > 2)
01710 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
01711 check_quota(vms,(char *)mbox(box));
01712 }
01713
01714 ast_mutex_lock(&vms->lock);
01715 pgm = mail_newsearchpgm();
01716
01717
01718 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
01719 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
01720 pgm->header = hdr;
01721 pgm->deleted = 0;
01722 pgm->undeleted = 1;
01723
01724
01725 if (box == 0) {
01726 pgm->unseen = 1;
01727 pgm->seen = 0;
01728 } else if (box == 1) {
01729 pgm->seen = 1;
01730 pgm->unseen = 0;
01731 }
01732
01733 vms->vmArrayIndex = 0;
01734 if (option_debug > 2)
01735 ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
01736 mail_search_full (vms->mailstream, NULL, pgm, NIL);
01737
01738 vms->lastmsg = vms->vmArrayIndex - 1;
01739
01740
01741
01742
01743 if (box == 0 && !vms->dh_arraysize) {
01744 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
01745 }
01746 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
01747 ast_mutex_unlock(&vms->lock);
01748 return -1;
01749 }
01750
01751 mail_free_searchpgm(&pgm);
01752 ast_mutex_unlock(&vms->lock);
01753 return 0;
01754 }
01755
01756 static void write_file(char *filename, char *buffer, unsigned long len)
01757 {
01758 FILE *output;
01759
01760 output = fopen (filename, "w");
01761 if (fwrite (buffer, len, 1, output) != 1) {
01762 ast_log(LOG_WARNING, "Short write: %s\n", strerror(errno));
01763 }
01764 fclose (output);
01765 }
01766
01767 void mm_searched(MAILSTREAM *stream, unsigned long number)
01768 {
01769 struct vm_state *vms;
01770 char *mailbox;
01771 char *user;
01772 mailbox = stream->mailbox;
01773 user = get_user_by_mailbox(mailbox);
01774 vms = get_vm_state_by_imapuser(user,2);
01775 if (!vms) {
01776 vms = get_vm_state_by_imapuser(user, 0);
01777 }
01778 if (vms) {
01779 if (option_debug > 2)
01780 ast_log (LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number,vms->vmArrayIndex,vms->interactive);
01781 vms->msgArray[vms->vmArrayIndex++] = number;
01782 } else {
01783 ast_log (LOG_ERROR, "No state found.\n");
01784 }
01785 }
01786
01787 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
01788 {
01789 struct ast_variable *var;
01790 struct ast_vm_user *vmu;
01791
01792 vmu = ast_calloc(1, sizeof *vmu);
01793 if (!vmu)
01794 return NULL;
01795 ast_set_flag(vmu, VM_ALLOCED);
01796 populate_defaults(vmu);
01797
01798 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
01799 if (var) {
01800 apply_options_full(vmu, var);
01801 ast_variables_destroy(var);
01802 return vmu;
01803 } else {
01804 free(vmu);
01805 return NULL;
01806 }
01807 }
01808
01809
01810
01811 void mm_exists(MAILSTREAM * stream, unsigned long number)
01812 {
01813
01814 if (option_debug > 3)
01815 ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
01816 if (number == 0) return;
01817 set_update(stream);
01818 }
01819
01820
01821 void mm_expunged(MAILSTREAM * stream, unsigned long number)
01822 {
01823
01824 if (option_debug > 3)
01825 ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
01826 if (number == 0) return;
01827 set_update(stream);
01828 }
01829
01830
01831 void mm_flags(MAILSTREAM * stream, unsigned long number)
01832 {
01833
01834 if (option_debug > 3)
01835 ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
01836 if (number == 0) return;
01837 set_update(stream);
01838 }
01839
01840
01841 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
01842 {
01843 mm_log (string, errflg);
01844 }
01845
01846
01847 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
01848 {
01849 if (delimiter == '\0') {
01850 delimiter = delim;
01851 }
01852 if (option_debug > 4) {
01853 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
01854 if (attributes & LATT_NOINFERIORS)
01855 ast_log(LOG_DEBUG, "no inferiors\n");
01856 if (attributes & LATT_NOSELECT)
01857 ast_log(LOG_DEBUG, "no select\n");
01858 if (attributes & LATT_MARKED)
01859 ast_log(LOG_DEBUG, "marked\n");
01860 if (attributes & LATT_UNMARKED)
01861 ast_log(LOG_DEBUG, "unmarked\n");
01862 }
01863 }
01864
01865
01866 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
01867 {
01868 if (option_debug > 4) {
01869 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
01870 if (attributes & LATT_NOINFERIORS)
01871 ast_log(LOG_DEBUG, "no inferiors\n");
01872 if (attributes & LATT_NOSELECT)
01873 ast_log(LOG_DEBUG, "no select\n");
01874 if (attributes & LATT_MARKED)
01875 ast_log(LOG_DEBUG, "marked\n");
01876 if (attributes & LATT_UNMARKED)
01877 ast_log(LOG_DEBUG, "unmarked\n");
01878 }
01879 }
01880
01881
01882 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
01883 {
01884 ast_log (LOG_NOTICE," Mailbox %s", mailbox);
01885 if (status->flags & SA_MESSAGES)
01886 ast_log (LOG_NOTICE,", %lu messages", status->messages);
01887 if (status->flags & SA_RECENT)
01888 ast_log (LOG_NOTICE,", %lu recent", status->recent);
01889 if (status->flags & SA_UNSEEN)
01890 ast_log (LOG_NOTICE,", %lu unseen", status->unseen);
01891 if (status->flags & SA_UIDVALIDITY)
01892 ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity);
01893 if (status->flags & SA_UIDNEXT)
01894 ast_log (LOG_NOTICE,", %lu next UID", status->uidnext);
01895 ast_log (LOG_NOTICE,"\n");
01896 }
01897
01898
01899 void mm_log(char *string, long errflg)
01900 {
01901 switch ((short) errflg) {
01902 case NIL:
01903 if (option_debug)
01904 ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
01905 break;
01906 case PARSE:
01907 case WARN:
01908 ast_log (LOG_WARNING,"IMAP Warning: %s\n", string);
01909 break;
01910 case ERROR:
01911 ast_log (LOG_ERROR,"IMAP Error: %s\n", string);
01912 break;
01913 }
01914 }
01915
01916
01917 void mm_dlog(char *string)
01918 {
01919 ast_log (LOG_NOTICE, "%s\n", string);
01920 }
01921
01922
01923 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
01924 {
01925 struct ast_vm_user *vmu;
01926
01927 if (option_debug > 3)
01928 ast_log(LOG_DEBUG, "Entering callback mm_login\n");
01929
01930 ast_copy_string(user, mb->user, MAILTMPLEN);
01931
01932
01933 if (!ast_strlen_zero(authpassword)) {
01934 ast_copy_string(pwd, authpassword, MAILTMPLEN);
01935 } else {
01936 AST_LIST_TRAVERSE(&users, vmu, list) {
01937 if (!strcasecmp(mb->user, vmu->imapuser)) {
01938 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01939 break;
01940 }
01941 }
01942 if (!vmu) {
01943 if ((vmu = find_user_realtime_imapuser(mb->user))) {
01944 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01945 free_user(vmu);
01946 }
01947 }
01948 }
01949 }
01950
01951
01952 void mm_critical(MAILSTREAM * stream)
01953 {
01954 }
01955
01956
01957 void mm_nocritical(MAILSTREAM * stream)
01958 {
01959 }
01960
01961
01962 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
01963 {
01964 kill (getpid (), SIGSTOP);
01965 return NIL;
01966 }
01967
01968
01969 void mm_fatal(char *string)
01970 {
01971 ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string);
01972 }
01973
01974
01975 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
01976 {
01977 struct vm_state *vms;
01978 char *mailbox;
01979 char *user;
01980 unsigned long usage = 0;
01981 unsigned long limit = 0;
01982
01983 while (pquota) {
01984 usage = pquota->usage;
01985 limit = pquota->limit;
01986 pquota = pquota->next;
01987 }
01988
01989 mailbox = stream->mailbox;
01990 user = get_user_by_mailbox(mailbox);
01991 vms = get_vm_state_by_imapuser(user,2);
01992 if (!vms) {
01993 vms = get_vm_state_by_imapuser(user, 0);
01994 }
01995 if (vms) {
01996 if (option_debug > 2)
01997 ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
01998 vms->quota_usage = usage;
01999 vms->quota_limit = limit;
02000 } else {
02001 ast_log (LOG_ERROR, "No state found.\n");
02002 }
02003 }
02004
02005 static char *get_header_by_tag(char *header, char *tag)
02006 {
02007 char *start;
02008 int taglen;
02009 char *eol_pnt;
02010
02011 if (!header || !tag)
02012 return NULL;
02013
02014 taglen = strlen(tag) + 1;
02015 if (taglen < 1)
02016 return NULL;
02017
02018 start = strstr(header, tag);
02019 if (!start)
02020 return NULL;
02021
02022 ast_mutex_lock(&imaptemp_lock);
02023 ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
02024 ast_mutex_unlock(&imaptemp_lock);
02025 if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n')))
02026 *eol_pnt = '\0';
02027 return imaptemp;
02028 }
02029
02030 static char *get_user_by_mailbox(char *mailbox)
02031 {
02032 char *start, *quote;
02033 char *eol_pnt;
02034
02035 if (!mailbox)
02036 return NULL;
02037
02038 start = strstr(mailbox,"/user=");
02039 if (!start)
02040 return NULL;
02041
02042 ast_mutex_lock(&imaptemp_lock);
02043 ast_copy_string(imaptemp, start+6, sizeof(imaptemp));
02044 ast_mutex_unlock(&imaptemp_lock);
02045
02046 quote = strchr(imaptemp,'\"');
02047 if (!quote) {
02048 eol_pnt = strchr(imaptemp,'/');
02049 if (!eol_pnt) {
02050 eol_pnt = strchr(imaptemp,'}');
02051 }
02052 *eol_pnt = '\0';
02053 return imaptemp;
02054 } else {
02055 eol_pnt = strchr(imaptemp+1,'\"');
02056 *eol_pnt = '\0';
02057 return imaptemp+1;
02058 }
02059 }
02060
02061 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02062 {
02063 struct vm_state *vms_p;
02064
02065 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02066 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02067 return vms_p;
02068 }
02069 if (option_debug > 4)
02070 ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02071 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02072 return NULL;
02073 ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
02074 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02075 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02076 vms_p->mailstream = NIL;
02077 vms_p->imapversion = vmu->imapversion;
02078 if (option_debug > 4)
02079 ast_log(LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02080 vms_p->updated = 1;
02081
02082 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02083 init_vm_state(vms_p);
02084 vmstate_insert(vms_p);
02085 return vms_p;
02086 }
02087
02088 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
02089 {
02090 struct vmstate *vlist = NULL;
02091
02092 if (interactive) {
02093 struct vm_state *vms;
02094 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02095 vms = pthread_getspecific(ts_vmstate.key);
02096 return vms;
02097 }
02098
02099 ast_mutex_lock(&vmstate_lock);
02100 vlist = vmstates;
02101 while (vlist) {
02102 if (vlist->vms && vlist->vms->imapversion == imapversion) {
02103 if (vlist->vms->imapuser) {
02104 if (!strcmp(vlist->vms->imapuser,user)) {
02105 if (interactive == 2) {
02106 ast_mutex_unlock(&vmstate_lock);
02107 return vlist->vms;
02108 } else if (vlist->vms->interactive == interactive) {
02109 ast_mutex_unlock(&vmstate_lock);
02110 return vlist->vms;
02111 }
02112 }
02113 } else {
02114 if (option_debug > 2)
02115 ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user);
02116 }
02117 } else {
02118 if (option_debug > 2)
02119 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user);
02120 }
02121 vlist = vlist->next;
02122 }
02123 ast_mutex_unlock(&vmstate_lock);
02124 if (option_debug > 2)
02125 ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
02126 return NULL;
02127 }
02128
02129 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02130 {
02131 struct vmstate *vlist = NULL;
02132 const char *local_context = S_OR(context, "default");
02133
02134 if (interactive) {
02135 struct vm_state *vms;
02136 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02137 vms = pthread_getspecific(ts_vmstate.key);
02138 return vms;
02139 }
02140
02141 ast_mutex_lock(&vmstate_lock);
02142 vlist = vmstates;
02143 if (option_debug > 2)
02144 ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
02145 while (vlist) {
02146 if (vlist->vms) {
02147 if (vlist->vms->username && vlist->vms->context && vlist->vms->imapversion == imapversion) {
02148 if (option_debug > 2)
02149 ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive);
02150 if (!strcmp(vlist->vms->username,mailbox) && !(strcmp(vlist->vms->context, local_context))) {
02151 if (option_debug > 2)
02152 ast_log(LOG_DEBUG, " Found it!\n");
02153 ast_mutex_unlock(&vmstate_lock);
02154 return vlist->vms;
02155 }
02156 } else {
02157 if (option_debug > 2)
02158 ast_log(LOG_DEBUG, " error: username or context is NULL for %s\n",mailbox);
02159 }
02160 } else {
02161 if (option_debug > 2)
02162 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox);
02163 }
02164 vlist = vlist->next;
02165 }
02166 ast_mutex_unlock(&vmstate_lock);
02167 if (option_debug > 2)
02168 ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
02169 return NULL;
02170 }
02171
02172 static void vmstate_insert(struct vm_state *vms)
02173 {
02174 struct vmstate *v;
02175 struct vm_state *altvms;
02176
02177
02178
02179
02180 if (vms->interactive == 1) {
02181 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
02182 if (altvms) {
02183 if (option_debug > 2)
02184 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02185 vms->newmessages = altvms->newmessages;
02186 vms->oldmessages = altvms->oldmessages;
02187
02188 copy_msgArray(vms, altvms);
02189 vms->vmArrayIndex = altvms->vmArrayIndex;
02190 vms->lastmsg = altvms->lastmsg;
02191 vms->curmsg = altvms->curmsg;
02192
02193 vms->persist_vms = altvms;
02194
02195 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02196 vms->mailstream = altvms->mailstream;
02197 #else
02198 vms->mailstream = NIL;
02199 #endif
02200 }
02201 return;
02202 }
02203
02204 v = (struct vmstate *)malloc(sizeof(struct vmstate));
02205 if (!v) {
02206 ast_log(LOG_ERROR, "Out of memory\n");
02207 }
02208 if (option_debug > 2)
02209 ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02210 ast_mutex_lock(&vmstate_lock);
02211 v->vms = vms;
02212 v->next = vmstates;
02213 vmstates = v;
02214 ast_mutex_unlock(&vmstate_lock);
02215 }
02216
02217 static void vmstate_delete(struct vm_state *vms)
02218 {
02219 struct vmstate *vc, *vf = NULL, *vl = NULL;
02220 struct vm_state *altvms;
02221
02222
02223
02224 if (vms->interactive == 1) {
02225 altvms = vms->persist_vms;
02226 if (altvms) {
02227 if (option_debug > 2)
02228 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02229 altvms->newmessages = vms->newmessages;
02230 altvms->oldmessages = vms->oldmessages;
02231 altvms->updated = 1;
02232 }
02233 vms->mailstream = mail_close(vms->mailstream);
02234
02235
02236 return;
02237 }
02238
02239 ast_mutex_lock(&vmstate_lock);
02240 vc = vmstates;
02241 if (option_debug > 2)
02242 ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02243 while (vc) {
02244 if (vc->vms == vms) {
02245 vf = vc;
02246 if (vl)
02247 vl->next = vc->next;
02248 else
02249 vmstates = vc->next;
02250 break;
02251 }
02252 vl = vc;
02253 vc = vc->next;
02254 }
02255 if (!vf) {
02256 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02257 } else {
02258 ast_mutex_destroy(&vf->vms->lock);
02259 free(vf);
02260 }
02261 ast_mutex_unlock(&vmstate_lock);
02262 }
02263
02264 static void set_update(MAILSTREAM * stream)
02265 {
02266 struct vm_state *vms;
02267 char *mailbox;
02268 char *user;
02269
02270 mailbox = stream->mailbox;
02271 user = get_user_by_mailbox(mailbox);
02272 vms = get_vm_state_by_imapuser(user, 0);
02273 if (vms) {
02274 if (option_debug > 2)
02275 ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user);
02276 vms->updated = 1;
02277 } else {
02278 if (option_debug > 2)
02279 ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user);
02280 }
02281 }
02282
02283 static void init_vm_state(struct vm_state *vms)
02284 {
02285 int x;
02286 vms->vmArrayIndex = 0;
02287 for (x = 0; x < 256; x++) {
02288 vms->msgArray[x] = 0;
02289 }
02290 ast_mutex_init(&vms->lock);
02291 }
02292
02293 static void copy_msgArray(struct vm_state *dst, struct vm_state *src)
02294 {
02295 int x;
02296 for (x = 0; x<256; x++) {
02297 dst->msgArray[x] = src->msgArray[x];
02298 }
02299 }
02300
02301 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
02302 {
02303 char *body_content;
02304 char *body_decoded;
02305 unsigned long len;
02306 unsigned long newlen;
02307 char filename[256];
02308
02309 if (!body || body == NIL)
02310 return -1;
02311 ast_mutex_lock(&vms->lock);
02312 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02313 ast_mutex_unlock(&vms->lock);
02314 if (body_content != NIL) {
02315 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
02316
02317 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
02318 write_file (filename, (char *) body_decoded, newlen);
02319 }
02320 return 0;
02321 }
02322
02323
02324
02325 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02326 char tmp[50];
02327 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02328 mail_list(stream, tmp, "*");
02329 }
02330
02331
02332 static void check_quota(struct vm_state *vms, char *mailbox) {
02333 ast_mutex_lock(&vms->lock);
02334 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02335 if (option_debug > 2)
02336 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02337 if (vms && vms->mailstream != NULL) {
02338 imap_getquotaroot(vms->mailstream, mailbox);
02339 } else {
02340 ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox);
02341 }
02342 ast_mutex_unlock(&vms->lock);
02343 }
02344 #endif
02345
02346
02347
02348
02349 static int vm_lock_path(const char *path)
02350 {
02351 switch (ast_lock_path(path)) {
02352 case AST_LOCK_TIMEOUT:
02353 return -1;
02354 default:
02355 return 0;
02356 }
02357 }
02358
02359
02360 #ifdef ODBC_STORAGE
02361 struct generic_prepare_struct {
02362 char *sql;
02363 int argc;
02364 char **argv;
02365 };
02366
02367 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02368 {
02369 struct generic_prepare_struct *gps = data;
02370 int res, i;
02371 SQLHSTMT stmt;
02372
02373 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02374 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02375 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02376 return NULL;
02377 }
02378 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02379 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02380 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02381 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02382 return NULL;
02383 }
02384 for (i = 0; i < gps->argc; i++)
02385 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02386
02387 return stmt;
02388 }
02389
02390 static int retrieve_file(char *dir, int msgnum)
02391 {
02392 int x = 0;
02393 int res;
02394 int fd=-1;
02395 size_t fdlen = 0;
02396 void *fdm = MAP_FAILED;
02397 SQLSMALLINT colcount=0;
02398 SQLHSTMT stmt;
02399 char sql[PATH_MAX];
02400 char fmt[80]="";
02401 char *c;
02402 char coltitle[256];
02403 SQLSMALLINT collen;
02404 SQLSMALLINT datatype;
02405 SQLSMALLINT decimaldigits;
02406 SQLSMALLINT nullable;
02407 SQLULEN colsize;
02408 SQLLEN colsize2;
02409 FILE *f=NULL;
02410 char rowdata[80];
02411 char fn[PATH_MAX];
02412 char full_fn[PATH_MAX];
02413 char msgnums[80];
02414 char *argv[] = { dir, msgnums };
02415 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02416
02417 struct odbc_obj *obj;
02418 obj = ast_odbc_request_obj(odbc_database, 0);
02419 if (obj) {
02420 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02421 c = strchr(fmt, '|');
02422 if (c)
02423 *c = '\0';
02424 if (!strcasecmp(fmt, "wav49"))
02425 strcpy(fmt, "WAV");
02426 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02427 if (msgnum > -1)
02428 make_file(fn, sizeof(fn), dir, msgnum);
02429 else
02430 ast_copy_string(fn, dir, sizeof(fn));
02431 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02432
02433 if (!(f = fopen(full_fn, "w+"))) {
02434 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02435 goto yuck;
02436 }
02437
02438 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02439 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02440 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02441 if (!stmt) {
02442 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02443 ast_odbc_release_obj(obj);
02444 goto yuck;
02445 }
02446 res = SQLFetch(stmt);
02447 if (res == SQL_NO_DATA) {
02448 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02449 ast_odbc_release_obj(obj);
02450 goto yuck;
02451 }
02452 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02453 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02454 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02455 ast_odbc_release_obj(obj);
02456 goto yuck;
02457 }
02458 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
02459 if (fd < 0) {
02460 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02461 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02462 ast_odbc_release_obj(obj);
02463 goto yuck;
02464 }
02465 res = SQLNumResultCols(stmt, &colcount);
02466 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02467 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02468 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02469 ast_odbc_release_obj(obj);
02470 goto yuck;
02471 }
02472 if (f)
02473 fprintf(f, "[message]\n");
02474 for (x=0;x<colcount;x++) {
02475 rowdata[0] = '\0';
02476 colsize = 0;
02477 collen = sizeof(coltitle);
02478 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02479 &datatype, &colsize, &decimaldigits, &nullable);
02480 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02481 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02482 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02483 ast_odbc_release_obj(obj);
02484 goto yuck;
02485 }
02486 if (!strcasecmp(coltitle, "recording")) {
02487 off_t offset;
02488 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02489 fdlen = colsize2;
02490 if (fd > -1) {
02491 char tmp[1]="";
02492 lseek(fd, fdlen - 1, SEEK_SET);
02493 if (write(fd, tmp, 1) != 1) {
02494 close(fd);
02495 fd = -1;
02496 continue;
02497 }
02498
02499 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02500 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02501 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02502 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02503 ast_odbc_release_obj(obj);
02504 goto yuck;
02505 } else {
02506 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02507 munmap(fdm, CHUNKSIZE);
02508 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02509 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02510 unlink(full_fn);
02511 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02512 ast_odbc_release_obj(obj);
02513 goto yuck;
02514 }
02515 }
02516 }
02517 if (truncate(full_fn, fdlen) < 0) {
02518 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
02519 }
02520 }
02521 } else {
02522 SQLLEN ind;
02523 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind);
02524 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02525 SQLINTEGER nativeerror = 0;
02526 SQLSMALLINT diagbytes = 0;
02527 unsigned char state[10], diagnostic[256];
02528 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
02529 ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql);
02530 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02531 ast_odbc_release_obj(obj);
02532 goto yuck;
02533 }
02534 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02535 fprintf(f, "%s=%s\n", coltitle, rowdata);
02536 }
02537 }
02538 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02539 ast_odbc_release_obj(obj);
02540 } else
02541 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02542 yuck:
02543 if (f)
02544 fclose(f);
02545 if (fd > -1)
02546 close(fd);
02547 return x - 1;
02548 }
02549
02550 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02551 {
02552 int x = 0;
02553 int res;
02554 SQLHSTMT stmt;
02555 char sql[PATH_MAX];
02556 char rowdata[20];
02557 char *argv[] = { dir };
02558 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02559
02560 struct odbc_obj *obj;
02561 obj = ast_odbc_request_obj(odbc_database, 0);
02562 if (obj) {
02563 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc limit 1", odbc_table);
02564
02565 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02566 if (!stmt) {
02567 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02568 ast_odbc_release_obj(obj);
02569 goto yuck;
02570 }
02571 res = SQLFetch(stmt);
02572 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02573 if (res == SQL_NO_DATA) {
02574 ast_log(LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
02575 } else {
02576 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02577 }
02578
02579 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02580 ast_odbc_release_obj(obj);
02581 goto yuck;
02582 }
02583 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02584 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02585 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02586 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02587 ast_odbc_release_obj(obj);
02588 goto yuck;
02589 }
02590 if (sscanf(rowdata, "%30d", &x) != 1)
02591 ast_log(LOG_WARNING, "Failed to read message index!\n");
02592 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02593 ast_odbc_release_obj(obj);
02594 return x;
02595 } else
02596 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02597 yuck:
02598 return x - 1;
02599 }
02600
02601 static int message_exists(char *dir, int msgnum)
02602 {
02603 int x = 0;
02604 int res;
02605 SQLHSTMT stmt;
02606 char sql[PATH_MAX];
02607 char rowdata[20];
02608 char msgnums[20];
02609 char *argv[] = { dir, msgnums };
02610 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02611
02612 struct odbc_obj *obj;
02613 obj = ast_odbc_request_obj(odbc_database, 0);
02614 if (obj) {
02615 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02616 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02617 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02618 if (!stmt) {
02619 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02620 ast_odbc_release_obj(obj);
02621 goto yuck;
02622 }
02623 res = SQLFetch(stmt);
02624 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02625 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02626 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02627 ast_odbc_release_obj(obj);
02628 goto yuck;
02629 }
02630 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02631 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02632 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02633 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02634 ast_odbc_release_obj(obj);
02635 goto yuck;
02636 }
02637 if (sscanf(rowdata, "%30d", &x) != 1)
02638 ast_log(LOG_WARNING, "Failed to read message count!\n");
02639 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02640 ast_odbc_release_obj(obj);
02641 } else
02642 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02643 yuck:
02644 return x;
02645 }
02646
02647 static int count_messages(struct ast_vm_user *vmu, char *dir)
02648 {
02649 int x = 0;
02650 int res;
02651 SQLHSTMT stmt;
02652 char sql[PATH_MAX];
02653 char rowdata[20];
02654 char *argv[] = { dir };
02655 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02656
02657 struct odbc_obj *obj;
02658 obj = ast_odbc_request_obj(odbc_database, 0);
02659 if (obj) {
02660 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
02661 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02662 if (!stmt) {
02663 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02664 ast_odbc_release_obj(obj);
02665 goto yuck;
02666 }
02667 res = SQLFetch(stmt);
02668 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02669 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02670 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02671 ast_odbc_release_obj(obj);
02672 goto yuck;
02673 }
02674 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02675 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02676 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02677 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02678 ast_odbc_release_obj(obj);
02679 goto yuck;
02680 }
02681 if (sscanf(rowdata, "%30d", &x) != 1)
02682 ast_log(LOG_WARNING, "Failed to read message count!\n");
02683 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02684 ast_odbc_release_obj(obj);
02685 return x;
02686 } else
02687 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02688 yuck:
02689 return x - 1;
02690
02691 }
02692
02693 static void delete_file(char *sdir, int smsg)
02694 {
02695 SQLHSTMT stmt;
02696 char sql[PATH_MAX];
02697 char msgnums[20];
02698 char *argv[] = { sdir, msgnums };
02699 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02700
02701 struct odbc_obj *obj;
02702 obj = ast_odbc_request_obj(odbc_database, 0);
02703 if (obj) {
02704 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02705 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02706 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02707 if (!stmt)
02708 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02709 else
02710 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02711 ast_odbc_release_obj(obj);
02712 } else
02713 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02714 return;
02715 }
02716
02717 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
02718 {
02719 SQLHSTMT stmt;
02720 char sql[512];
02721 char msgnums[20];
02722 char msgnumd[20];
02723 struct odbc_obj *obj;
02724 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
02725 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02726
02727 delete_file(ddir, dmsg);
02728 obj = ast_odbc_request_obj(odbc_database, 0);
02729 if (obj) {
02730 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02731 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02732 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);
02733 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02734 if (!stmt)
02735 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
02736 else
02737 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02738 ast_odbc_release_obj(obj);
02739 } else
02740 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02741 return;
02742 }
02743
02744 struct insert_cb_struct {
02745 char *dir;
02746 char *msgnum;
02747 void *recording;
02748 size_t recordinglen;
02749 SQLLEN indlen;
02750 const char *context;
02751 const char *macrocontext;
02752 const char *callerid;
02753 const char *origtime;
02754 const char *duration;
02755 char *mailboxuser;
02756 char *mailboxcontext;
02757 const char *category;
02758 char *sql;
02759 };
02760
02761 static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd)
02762 {
02763 struct insert_cb_struct *d = vd;
02764 int res;
02765 SQLHSTMT stmt;
02766
02767 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02768 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02769 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02770 return NULL;
02771 }
02772
02773 res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS);
02774 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02775 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql);
02776 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02777 return NULL;
02778 }
02779
02780 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL);
02781 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL);
02782 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen);
02783 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL);
02784 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL);
02785 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL);
02786 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL);
02787 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL);
02788 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL);
02789 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL);
02790 if (!ast_strlen_zero(d->category)) {
02791 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL);
02792 }
02793
02794 return stmt;
02795 }
02796
02797 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
02798 {
02799 int x = 0;
02800 int fd = -1;
02801 void *fdm = MAP_FAILED;
02802 size_t fdlen = -1;
02803 SQLHSTMT stmt;
02804 char sql[PATH_MAX];
02805 char msgnums[20];
02806 char fn[PATH_MAX];
02807 char full_fn[PATH_MAX];
02808 char fmt[80]="";
02809 char *c;
02810 struct insert_cb_struct d = {
02811 .dir = dir,
02812 .msgnum = msgnums,
02813 .context = "",
02814 .macrocontext = "",
02815 .callerid = "",
02816 .origtime = "",
02817 .duration = "",
02818 .mailboxuser = mailboxuser,
02819 .mailboxcontext = mailboxcontext,
02820 .category = "",
02821 .sql = sql
02822 };
02823 struct ast_config *cfg=NULL;
02824 struct odbc_obj *obj;
02825
02826 delete_file(dir, msgnum);
02827 obj = ast_odbc_request_obj(odbc_database, 0);
02828 if (obj) {
02829 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02830 c = strchr(fmt, '|');
02831 if (c)
02832 *c = '\0';
02833 if (!strcasecmp(fmt, "wav49"))
02834 strcpy(fmt, "WAV");
02835 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02836 if (msgnum > -1)
02837 make_file(fn, sizeof(fn), dir, msgnum);
02838 else
02839 ast_copy_string(fn, dir, sizeof(fn));
02840 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02841 cfg = ast_config_load(full_fn);
02842 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02843 fd = open(full_fn, O_RDWR);
02844 if (fd < 0) {
02845 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
02846 ast_odbc_release_obj(obj);
02847 goto yuck;
02848 }
02849 if (cfg) {
02850 d.context = ast_variable_retrieve(cfg, "message", "context");
02851 if (!d.context) d.context = "";
02852 d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
02853 if (!d.macrocontext) d.macrocontext = "";
02854 d.callerid = ast_variable_retrieve(cfg, "message", "callerid");
02855 if (!d.callerid) d.callerid = "";
02856 d.origtime = ast_variable_retrieve(cfg, "message", "origtime");
02857 if (!d.origtime) d.origtime = "";
02858 d.duration = ast_variable_retrieve(cfg, "message", "duration");
02859 if (!d.duration) d.duration = "";
02860 d.category = ast_variable_retrieve(cfg, "message", "category");
02861 if (!d.category) d.category = "";
02862 }
02863 fdlen = lseek(fd, 0, SEEK_END);
02864 lseek(fd, 0, SEEK_SET);
02865 printf("Length is %zd\n", fdlen);
02866 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
02867 if (fdm == MAP_FAILED) {
02868 ast_log(LOG_WARNING, "Memory map failed!\n");
02869 ast_odbc_release_obj(obj);
02870 goto yuck;
02871 }
02872 d.recording = fdm;
02873 d.recordinglen = d.indlen = fdlen;
02874 if (!ast_strlen_zero(d.category))
02875 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
02876 else
02877 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?, ? , ?,?,?,?,?,?,?)",odbc_table);
02878 stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d);
02879 if (stmt) {
02880 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02881 }
02882 ast_odbc_release_obj(obj);
02883 } else
02884 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02885 yuck:
02886 if (cfg)
02887 ast_config_destroy(cfg);
02888 if (fdm != MAP_FAILED)
02889 munmap(fdm, fdlen);
02890 if (fd > -1)
02891 close(fd);
02892 return x;
02893 }
02894
02895 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
02896 {
02897 SQLHSTMT stmt;
02898 char sql[PATH_MAX];
02899 char msgnums[20];
02900 char msgnumd[20];
02901 struct odbc_obj *obj;
02902 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
02903 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02904
02905 delete_file(ddir, dmsg);
02906 obj = ast_odbc_request_obj(odbc_database, 0);
02907 if (obj) {
02908 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02909 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02910 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
02911 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02912 if (!stmt)
02913 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02914 else
02915 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02916 ast_odbc_release_obj(obj);
02917 } else
02918 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02919 return;
02920 }
02921
02922 #else
02923 #ifndef IMAP_STORAGE
02924 static int count_messages(struct ast_vm_user *vmu, char *dir)
02925 {
02926
02927
02928 int vmcount = 0;
02929 DIR *vmdir = NULL;
02930 struct dirent *vment = NULL;
02931
02932 if (vm_lock_path(dir))
02933 return ERROR_LOCK_PATH;
02934
02935 if ((vmdir = opendir(dir))) {
02936 while ((vment = readdir(vmdir))) {
02937 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
02938 vmcount++;
02939 }
02940 closedir(vmdir);
02941 }
02942 ast_unlock_path(dir);
02943
02944 return vmcount;
02945 }
02946
02947 static void rename_file(char *sfn, char *dfn)
02948 {
02949 char stxt[PATH_MAX];
02950 char dtxt[PATH_MAX];
02951 ast_filerename(sfn,dfn,NULL);
02952 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
02953 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
02954 rename(stxt, dtxt);
02955 }
02956 #endif
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
02970 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02971 {
02972 int x;
02973 unsigned char map[MAXMSGLIMIT] = "";
02974 DIR *msgdir;
02975 struct dirent *msgdirent;
02976 int msgdirint;
02977 char extension[4];
02978 int stopcount = 0;
02979
02980
02981
02982
02983
02984 if (!(msgdir = opendir(dir))) {
02985 return -1;
02986 }
02987
02988 while ((msgdirent = readdir(msgdir))) {
02989 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
02990 map[msgdirint] = 1;
02991 stopcount++;
02992 if (option_debug > 3) {
02993 ast_log(LOG_DEBUG, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
02994 }
02995 }
02996 }
02997 closedir(msgdir);
02998
02999 for (x = 0; x < vmu->maxmsg; x++) {
03000 if (map[x] == 1) {
03001 stopcount--;
03002 } else if (map[x] == 0 && !stopcount) {
03003 break;
03004 }
03005 }
03006
03007 return x - 1;
03008 }
03009 #endif
03010 #endif
03011 #if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
03012 static int remove_file(char *dir, int msgnum)
03013 {
03014 char fn[PATH_MAX];
03015 char full_fn[PATH_MAX];
03016 char msgnums[80];
03017
03018 if (msgnum > -1) {
03019 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03020 make_file(fn, sizeof(fn), dir, msgnum);
03021 } else {
03022 #ifndef IMAP_STORAGE
03023 ast_copy_string(fn, dir, sizeof(fn));
03024 #else
03025
03026
03027
03028 return 0;
03029 #endif
03030 }
03031 ast_filedelete(fn, NULL);
03032 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03033 unlink(full_fn);
03034 return 0;
03035 }
03036 #endif
03037
03038 #ifndef IMAP_STORAGE
03039 static int copy(char *infile, char *outfile)
03040 {
03041 int ifd;
03042 int ofd;
03043 int res;
03044 int len;
03045 char buf[4096];
03046
03047 #ifdef HARDLINK_WHEN_POSSIBLE
03048
03049 if (link(infile, outfile)) {
03050 #endif
03051 if ((ifd = open(infile, O_RDONLY)) < 0) {
03052 ast_log(LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03053 return -1;
03054 }
03055 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03056 ast_log(LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03057 close(ifd);
03058 return -1;
03059 }
03060 do {
03061 len = read(ifd, buf, sizeof(buf));
03062 if (len < 0) {
03063 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03064 close(ifd);
03065 close(ofd);
03066 unlink(outfile);
03067 }
03068 if (len) {
03069 res = write(ofd, buf, len);
03070 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03071 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03072 close(ifd);
03073 close(ofd);
03074 unlink(outfile);
03075 }
03076 }
03077 } while (len);
03078 close(ifd);
03079 close(ofd);
03080 return 0;
03081 #ifdef HARDLINK_WHEN_POSSIBLE
03082 } else {
03083
03084 return 0;
03085 }
03086 #endif
03087 }
03088 #endif
03089
03090 #ifndef IMAP_STORAGE
03091 static void copy_plain_file(char *frompath, char *topath)
03092 {
03093 char frompath2[PATH_MAX], topath2[PATH_MAX];
03094 ast_filecopy(frompath, topath, NULL);
03095 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03096 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03097 copy(frompath2, topath2);
03098 }
03099 #endif
03100
03101 #ifndef IMAP_STORAGE
03102 static int vm_delete(char *file)
03103 {
03104 char *txt;
03105 int txtsize = 0;
03106
03107 txtsize = (strlen(file) + 5)*sizeof(char);
03108 txt = alloca(txtsize);
03109
03110
03111
03112 snprintf(txt, txtsize, "%s.txt", file);
03113 unlink(txt);
03114 return ast_filedelete(file, NULL);
03115 }
03116 #endif
03117
03118 static int inbuf(struct baseio *bio, FILE *fi)
03119 {
03120 int l;
03121
03122 if (bio->ateof)
03123 return 0;
03124
03125 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
03126 if (ferror(fi))
03127 return -1;
03128
03129 bio->ateof = 1;
03130 return 0;
03131 }
03132
03133 bio->iolen= l;
03134 bio->iocp= 0;
03135
03136 return 1;
03137 }
03138
03139 static int inchar(struct baseio *bio, FILE *fi)
03140 {
03141 if (bio->iocp>=bio->iolen) {
03142 if (!inbuf(bio, fi))
03143 return EOF;
03144 }
03145
03146 return bio->iobuf[bio->iocp++];
03147 }
03148
03149 static int ochar(struct baseio *bio, int c, FILE *so)
03150 {
03151 if (bio->linelength >= BASELINELEN) {
03152 if (fputs(ENDL, so) == EOF) {
03153 return -1;
03154 }
03155
03156 bio->linelength = 0;
03157 }
03158
03159 if (putc(((unsigned char) c), so) == EOF) {
03160 return -1;
03161 }
03162
03163 bio->linelength++;
03164
03165 return 1;
03166 }
03167
03168 static int base_encode(char *filename, FILE *so)
03169 {
03170 unsigned char dtable[BASEMAXINLINE];
03171 int i,hiteof= 0;
03172 FILE *fi;
03173 struct baseio bio;
03174
03175 memset(&bio, 0, sizeof(bio));
03176 bio.iocp = BASEMAXINLINE;
03177
03178 if (!(fi = fopen(filename, "rb"))) {
03179 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03180 return -1;
03181 }
03182
03183 for (i= 0;i<9;i++) {
03184 dtable[i]= 'A'+i;
03185 dtable[i+9]= 'J'+i;
03186 dtable[26+i]= 'a'+i;
03187 dtable[26+i+9]= 'j'+i;
03188 }
03189 for (i= 0;i<8;i++) {
03190 dtable[i+18]= 'S'+i;
03191 dtable[26+i+18]= 's'+i;
03192 }
03193 for (i= 0;i<10;i++) {
03194 dtable[52+i]= '0'+i;
03195 }
03196 dtable[62]= '+';
03197 dtable[63]= '/';
03198
03199 while (!hiteof){
03200 unsigned char igroup[3],ogroup[4];
03201 int c,n;
03202
03203 igroup[0]= igroup[1]= igroup[2]= 0;
03204
03205 for (n= 0;n<3;n++) {
03206 if ((c = inchar(&bio, fi)) == EOF) {
03207 hiteof= 1;
03208 break;
03209 }
03210
03211 igroup[n]= (unsigned char)c;
03212 }
03213
03214 if (n> 0) {
03215 ogroup[0]= dtable[igroup[0]>>2];
03216 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
03217 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
03218 ogroup[3]= dtable[igroup[2]&0x3F];
03219
03220 if (n<3) {
03221 ogroup[3]= '=';
03222
03223 if (n<2)
03224 ogroup[2]= '=';
03225 }
03226
03227 for (i= 0;i<4;i++)
03228 ochar(&bio, ogroup[i], so);
03229 }
03230 }
03231
03232 fclose(fi);
03233
03234 if (fputs(ENDL, so) == EOF) {
03235 return 0;
03236 }
03237
03238 return 1;
03239 }
03240
03241 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
03242 {
03243 char callerid[256];
03244 char fromdir[256], fromfile[256];
03245 struct ast_config *msg_cfg;
03246 const char *origcallerid, *origtime;
03247 char origcidname[80], origcidnum[80], origdate[80];
03248 int inttime;
03249
03250
03251 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03252 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03253 snprintf(passdata, passdatasize, "%d", msgnum);
03254 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03255 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03256 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03257 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03258 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03259 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03260 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03261 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03262 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03263
03264
03265 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03266 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03267 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03268 strcat(fromfile, ".txt");
03269 }
03270 if (!(msg_cfg = ast_config_load(fromfile))) {
03271 if (option_debug > 0) {
03272 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03273 }
03274 return;
03275 }
03276
03277 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03278 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03279 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03280 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03281 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03282 }
03283
03284 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
03285 time_t ttime = inttime;
03286 struct tm tm;
03287 ast_localtime(&ttime, &tm, NULL);
03288 strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03289 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03290 }
03291 ast_config_destroy(msg_cfg);
03292 }
03293
03294 static char *quote(const char *from, char *to, size_t len)
03295 {
03296 char *ptr = to;
03297 *ptr++ = '"';
03298 for (; ptr < to + len - 1; from++) {
03299 if (*from == '"')
03300 *ptr++ = '\\';
03301 else if (*from == '\0')
03302 break;
03303 *ptr++ = *from;
03304 }
03305 if (ptr < to + len - 1)
03306 *ptr++ = '"';
03307 *ptr = '\0';
03308 return to;
03309 }
03310
03311
03312
03313
03314 static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
03315 {
03316 const struct vm_zone *z = NULL;
03317 time_t t = time(NULL);
03318
03319
03320 if (!ast_strlen_zero(vmu->zonetag)) {
03321
03322 AST_LIST_LOCK(&zones);
03323 AST_LIST_TRAVERSE(&zones, z, list) {
03324 if (!strcmp(z->name, vmu->zonetag))
03325 break;
03326 }
03327 AST_LIST_UNLOCK(&zones);
03328 }
03329 ast_localtime(&t, tm, z ? z->timezone : NULL);
03330 return tm;
03331 }
03332
03333
03334
03335
03336
03337 static int check_mime(const char *str)
03338 {
03339 for (; *str; str++) {
03340 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03341 return 1;
03342 }
03343 }
03344 return 0;
03345 }
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03364 {
03365 char tmp[80];
03366 int first_section = 1;
03367 size_t endlen = 0, tmplen = 0;
03368 *end = '\0';
03369
03370 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03371 for (; *start; start++) {
03372 int need_encoding = 0;
03373 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03374 need_encoding = 1;
03375 }
03376 if ((first_section && need_encoding && preamble + tmplen > 70) ||
03377 (first_section && !need_encoding && preamble + tmplen > 72) ||
03378 (!first_section && need_encoding && tmplen > 70) ||
03379 (!first_section && !need_encoding && tmplen > 72)) {
03380
03381 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
03382 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03383 first_section = 0;
03384 }
03385 if (need_encoding && *start == ' ') {
03386 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
03387 } else if (need_encoding) {
03388 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
03389 } else {
03390 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
03391 }
03392 }
03393 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
03394 return end;
03395 }
03396
03397 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
03398 {
03399 char date[256];
03400 char host[MAXHOSTNAMELEN] = "";
03401 char who[256];
03402 char bound[256];
03403 char fname[256];
03404 char dur[256];
03405 char tmpcmd[256];
03406 char enc_cidnum[256] = "", enc_cidname[256] = "";
03407 struct tm tm;
03408 char *passdata = NULL, *passdata2;
03409 size_t len_passdata = 0, len_passdata2, tmplen;
03410
03411
03412 len_passdata2 = strlen(vmu->fullname);
03413 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
03414 len_passdata2 = tmplen;
03415 }
03416 if ((tmplen = strlen(emailtitle)) > len_passdata2) {
03417 len_passdata2 = tmplen;
03418 }
03419 if ((tmplen = strlen(fromstring)) > len_passdata2) {
03420 len_passdata2 = tmplen;
03421 }
03422 len_passdata2 = len_passdata2 * 3 + 200;
03423 passdata2 = alloca(len_passdata2);
03424
03425 if (cidnum) {
03426 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
03427 }
03428 if (cidname) {
03429 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
03430 }
03431 gethostname(host, sizeof(host) - 1);
03432 if (strchr(srcemail, '@'))
03433 ast_copy_string(who, srcemail, sizeof(who));
03434 else {
03435 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03436 }
03437 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03438 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03439 fprintf(p, "Date: %s" ENDL, date);
03440
03441
03442 strftime(date, sizeof(date), emaildateformat, &tm);
03443
03444 if (*fromstring) {
03445 struct ast_channel *ast;
03446 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03447 char *ptr;
03448 memset(passdata2, 0, len_passdata2);
03449 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category);
03450 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
03451 len_passdata = strlen(passdata2) * 3 + 300;
03452 passdata = alloca(len_passdata);
03453 if (check_mime(passdata2)) {
03454 int first_line = 1;
03455 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
03456 while ((ptr = strchr(passdata, ' '))) {
03457 *ptr = '\0';
03458 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
03459 first_line = 0;
03460 passdata = ptr + 1;
03461 }
03462 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
03463 } else {
03464 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
03465 }
03466 ast_channel_free(ast);
03467 } else
03468 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03469 } else
03470 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03471
03472 if (check_mime(vmu->fullname)) {
03473 int first_line = 1;
03474 char *ptr;
03475 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
03476 while ((ptr = strchr(passdata2, ' '))) {
03477 *ptr = '\0';
03478 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
03479 first_line = 0;
03480 passdata2 = ptr + 1;
03481 }
03482 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
03483 } else {
03484 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
03485 }
03486 if (emailsubject) {
03487 struct ast_channel *ast;
03488 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03489 int vmlen = strlen(emailsubject) * 3 + 200;
03490
03491 if (vmlen > len_passdata) {
03492 passdata = alloca(vmlen);
03493 len_passdata = vmlen;
03494 }
03495
03496 memset(passdata, 0, len_passdata);
03497 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category);
03498 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
03499 if (check_mime(passdata)) {
03500 int first_line = 1;
03501 char *ptr;
03502 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
03503 while ((ptr = strchr(passdata2, ' '))) {
03504 *ptr = '\0';
03505 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03506 first_line = 0;
03507 passdata2 = ptr + 1;
03508 }
03509 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03510 } else {
03511 fprintf(p, "Subject: %s" ENDL, passdata);
03512 }
03513 ast_channel_free(ast);
03514 } else {
03515 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03516 }
03517 } else if (*emailtitle) {
03518 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
03519 fprintf(p, ENDL) ;
03520 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
03521 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03522 } else {
03523 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03524 }
03525 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
03526 if (imap) {
03527
03528 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
03529
03530 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
03531 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
03532 #ifdef IMAP_STORAGE
03533 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
03534 #else
03535 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
03536 #endif
03537 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
03538 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
03539 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
03540 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
03541 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
03542 if (!ast_strlen_zero(category)) {
03543 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
03544 }
03545 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
03546 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
03547 }
03548 if (!ast_strlen_zero(cidnum)) {
03549 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
03550 }
03551 if (!ast_strlen_zero(cidname)) {
03552 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
03553 }
03554 fprintf(p, "MIME-Version: 1.0" ENDL);
03555 if (attach_user_voicemail) {
03556
03557 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
03558
03559 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
03560 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
03561 fprintf(p, "--%s" ENDL, bound);
03562 }
03563 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
03564 if (emailbody) {
03565 struct ast_channel *ast;
03566 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03567 char *passdata;
03568 int vmlen = strlen(emailbody)*3 + 200;
03569 if ((passdata = alloca(vmlen))) {
03570 memset(passdata, 0, vmlen);
03571 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03572 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
03573 #ifdef IMAP_STORAGE
03574 {
03575
03576 char *line = passdata, *next;
03577 do {
03578
03579 if ((next = strchr(line, '\n'))) {
03580 *next++ = '\0';
03581 }
03582 fprintf(p, "%s" ENDL, line);
03583 line = next;
03584 } while (!ast_strlen_zero(line));
03585 }
03586 #else
03587 fprintf(p, "%s" ENDL, passdata);
03588 #endif
03589 } else
03590 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03591 ast_channel_free(ast);
03592 } else
03593 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03594 } else {
03595 if (strcmp(vmu->mailbox, mailbox)) {
03596
03597 struct ast_config *msg_cfg;
03598 const char *v;
03599 int inttime;
03600 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
03601
03602 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03603 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
03604 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03605 strcat(fromfile, ".txt");
03606 }
03607 if ((msg_cfg = ast_config_load(fromfile))) {
03608 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03609 ast_copy_string(origcallerid, v, sizeof(origcallerid));
03610 }
03611
03612
03613
03614 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
03615 time_t ttime = inttime;
03616 struct tm tm;
03617 ast_localtime(&ttime, &tm, NULL);
03618 strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03619 }
03620 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
03621 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
03622 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
03623 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
03624 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
03625 date, origcallerid, origdate);
03626 ast_config_destroy(msg_cfg);
03627 } else {
03628 goto plain_message;
03629 }
03630 } else {
03631 plain_message:
03632 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
03633 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
03634 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
03635 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
03636 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
03637 }
03638 }
03639 if (attach_user_voicemail) {
03640
03641 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03642 char tmpdir[256], newtmp[256];
03643 int tmpfd = -1;
03644 int soxstatus = 0;
03645
03646 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03647 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03648 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03649 tmpfd = mkstemp(newtmp);
03650 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03651 if (option_debug > 2)
03652 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
03653 if (tmpfd > -1) {
03654 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03655 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03656 attach = newtmp;
03657 if (option_debug > 2) {
03658 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03659 }
03660 } else {
03661 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03662 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03663 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03664 }
03665 }
03666 }
03667 fprintf(p, "--%s" ENDL, bound);
03668 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03669 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03670 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03671 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03672 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03673 base_encode(fname, p);
03674 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03675 if (tmpfd > -1) {
03676 if (soxstatus == 0) {
03677 unlink(fname);
03678 }
03679 close(tmpfd);
03680 unlink(newtmp);
03681 }
03682 }
03683 }
03684
03685 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *fromfolder, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
03686 {
03687 FILE *p=NULL;
03688 char tmp[80] = "/tmp/astmail-XXXXXX";
03689 char tmp2[256];
03690 char *stringp;
03691
03692 if (vmu && ast_strlen_zero(vmu->email)) {
03693 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03694 return(0);
03695 }
03696
03697
03698 format = ast_strdupa(format);
03699 stringp = format;
03700 strsep(&stringp, "|");
03701
03702 if (!strcmp(format, "wav49"))
03703 format = "WAV";
03704 if (option_debug > 2)
03705 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));
03706
03707
03708 if ((p = vm_mkftemp(tmp)) == NULL) {
03709 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03710 return -1;
03711 } else {
03712 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03713 fclose(p);
03714 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03715 ast_safe_system(tmp2);
03716 if (option_debug > 2)
03717 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03718 }
03719 return 0;
03720 }
03721
03722 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category)
03723 {
03724 char date[256];
03725 char host[MAXHOSTNAMELEN] = "";
03726 char who[256];
03727 char dur[PATH_MAX];
03728 char tmp[80] = "/tmp/astmail-XXXXXX";
03729 char tmp2[PATH_MAX];
03730 struct tm tm;
03731 FILE *p;
03732
03733 if ((p = vm_mkftemp(tmp)) == NULL) {
03734 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03735 return -1;
03736 } else {
03737 gethostname(host, sizeof(host)-1);
03738 if (strchr(srcemail, '@'))
03739 ast_copy_string(who, srcemail, sizeof(who));
03740 else {
03741 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03742 }
03743 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03744 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03745 fprintf(p, "Date: %s\n", date);
03746
03747 if (*pagerfromstring) {
03748 struct ast_channel *ast;
03749 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03750 char *passdata;
03751 int vmlen = strlen(fromstring)*3 + 200;
03752 if ((passdata = alloca(vmlen))) {
03753 memset(passdata, 0, vmlen);
03754 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03755 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03756 fprintf(p, "From: %s <%s>\n", passdata, who);
03757 } else
03758 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03759 ast_channel_free(ast);
03760 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03761 } else
03762 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03763 fprintf(p, "To: %s\n", pager);
03764 if (pagersubject) {
03765 struct ast_channel *ast;
03766 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03767 char *passdata;
03768 int vmlen = strlen(pagersubject) * 3 + 200;
03769 if ((passdata = alloca(vmlen))) {
03770 memset(passdata, 0, vmlen);
03771 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03772 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03773 fprintf(p, "Subject: %s\n\n", passdata);
03774 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03775 ast_channel_free(ast);
03776 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03777 } else
03778 fprintf(p, "Subject: New VM\n\n");
03779 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03780 if (pagerbody) {
03781 struct ast_channel *ast;
03782 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03783 char *passdata;
03784 int vmlen = strlen(pagerbody)*3 + 200;
03785 if ((passdata = alloca(vmlen))) {
03786 memset(passdata, 0, vmlen);
03787 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03788 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03789 fprintf(p, "%s\n", passdata);
03790 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03791 ast_channel_free(ast);
03792 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03793 } else {
03794 fprintf(p, "New %s long msg in box %s\n"
03795 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03796 }
03797 fclose(p);
03798 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03799 ast_safe_system(tmp2);
03800 if (option_debug > 2)
03801 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
03802 }
03803 return 0;
03804 }
03805
03806 static int get_date(char *s, int len)
03807 {
03808 struct tm tm;
03809 time_t t;
03810
03811 time(&t);
03812
03813 ast_localtime(&t, &tm, NULL);
03814
03815 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
03816 }
03817
03818 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03819 {
03820 int res = -2;
03821
03822 #ifdef ODBC_STORAGE
03823 int success =
03824 #endif
03825 RETRIEVE(filename, -1, vmu);
03826 if (ast_fileexists(filename, NULL, NULL) > 0) {
03827 res = ast_streamfile(chan, filename, chan->language);
03828 if (res > -1)
03829 res = ast_waitstream(chan, ecodes);
03830 #ifdef ODBC_STORAGE
03831 if (success == -1) {
03832
03833 if (option_debug)
03834 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03835 store_file(filename, vmu->mailbox, vmu->context, -1);
03836 }
03837 #endif
03838 }
03839 DISPOSE(filename, -1);
03840
03841 return res;
03842 }
03843
03844 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03845 {
03846 int res;
03847 char fn[PATH_MAX];
03848 char dest[PATH_MAX];
03849
03850 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03851
03852 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
03853 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03854 return -1;
03855 }
03856
03857 res = play_greeting(chan, vmu, fn, ecodes);
03858 if (res == -2) {
03859
03860 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
03861 if (res)
03862 return res;
03863 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03864 }
03865
03866 if (res)
03867 return res;
03868
03869 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
03870 return res;
03871 }
03872
03873 static void free_zone(struct vm_zone *z)
03874 {
03875 free(z);
03876 }
03877
03878 #ifdef ODBC_STORAGE
03879
03880 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03881 {
03882 int x = -1;
03883 int res;
03884 SQLHSTMT stmt;
03885 char sql[PATH_MAX];
03886 char rowdata[20];
03887 char tmp[PATH_MAX] = "";
03888 struct odbc_obj *obj;
03889 char *context;
03890 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03891
03892 if (newmsgs)
03893 *newmsgs = 0;
03894 if (oldmsgs)
03895 *oldmsgs = 0;
03896
03897
03898 if (ast_strlen_zero(mailbox))
03899 return 0;
03900
03901 ast_copy_string(tmp, mailbox, sizeof(tmp));
03902
03903 context = strchr(tmp, '@');
03904 if (context) {
03905 *context = '\0';
03906 context++;
03907 } else
03908 context = "default";
03909
03910 obj = ast_odbc_request_obj(odbc_database, 0);
03911 if (obj) {
03912 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03913 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03914 if (!stmt) {
03915 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03916 ast_odbc_release_obj(obj);
03917 goto yuck;
03918 }
03919 res = SQLFetch(stmt);
03920 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03921 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03922 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03923 ast_odbc_release_obj(obj);
03924 goto yuck;
03925 }
03926 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03927 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03928 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03929 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03930 ast_odbc_release_obj(obj);
03931 goto yuck;
03932 }
03933 *newmsgs = atoi(rowdata);
03934 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03935
03936 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03937 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03938 if (!stmt) {
03939 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03940 ast_odbc_release_obj(obj);
03941 goto yuck;
03942 }
03943 res = SQLFetch(stmt);
03944 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03945 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03946 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03947 ast_odbc_release_obj(obj);
03948 goto yuck;
03949 }
03950 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03951 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03952 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03953 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03954 ast_odbc_release_obj(obj);
03955 goto yuck;
03956 }
03957 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03958 ast_odbc_release_obj(obj);
03959 *oldmsgs = atoi(rowdata);
03960 x = 0;
03961 } else
03962 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03963
03964 yuck:
03965 return x;
03966 }
03967
03968 static int messagecount(const char *context, const char *mailbox, const char *folder)
03969 {
03970 struct odbc_obj *obj = NULL;
03971 int nummsgs = 0;
03972 int res;
03973 SQLHSTMT stmt = NULL;
03974 char sql[PATH_MAX];
03975 char rowdata[20];
03976 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03977 if (!folder)
03978 folder = "INBOX";
03979
03980 if (ast_strlen_zero(mailbox))
03981 return 0;
03982
03983 obj = ast_odbc_request_obj(odbc_database, 0);
03984 if (obj) {
03985 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
03986 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03987 if (!stmt) {
03988 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03989 goto yuck;
03990 }
03991 res = SQLFetch(stmt);
03992 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03993 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03994 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03995 goto yuck;
03996 }
03997 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03998 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03999 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04000 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04001 goto yuck;
04002 }
04003 nummsgs = atoi(rowdata);
04004 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04005 } else
04006 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04007
04008 yuck:
04009 if (obj)
04010 ast_odbc_release_obj(obj);
04011 return nummsgs;
04012 }
04013
04014 static int has_voicemail(const char *mailbox, const char *folder)
04015 {
04016 char tmp[256], *tmp2 = tmp, *mbox, *context;
04017 ast_copy_string(tmp, mailbox, sizeof(tmp));
04018 while ((context = mbox = strsep(&tmp2, ","))) {
04019 strsep(&context, "@");
04020 if (ast_strlen_zero(context))
04021 context = "default";
04022 if (messagecount(context, mbox, folder))
04023 return 1;
04024 }
04025 return 0;
04026 }
04027 #endif
04028 #ifndef IMAP_STORAGE
04029
04030 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)
04031 {
04032 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04033 const char *frombox = mbox(imbox);
04034 int recipmsgnum;
04035 int res = 0;
04036
04037 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04038
04039 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04040
04041 if (!dir)
04042 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04043 else
04044 ast_copy_string(fromdir, dir, sizeof(fromdir));
04045
04046 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04047
04048 if (vm_lock_path(todir))
04049 return ERROR_LOCK_PATH;
04050
04051 recipmsgnum = 0;
04052 do {
04053 make_file(topath, sizeof(topath), todir, recipmsgnum);
04054 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
04055 break;
04056 recipmsgnum++;
04057 } while (recipmsgnum < recip->maxmsg);
04058 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
04059 #ifndef ODBC_STORAGE
04060 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04061 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04062 } else {
04063 #endif
04064
04065
04066
04067 copy_plain_file(frompath, topath);
04068 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL);
04069 vm_delete(topath);
04070 #ifndef ODBC_STORAGE
04071 }
04072 #endif
04073 } else {
04074 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04075 res = -1;
04076 }
04077 ast_unlock_path(todir);
04078 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04079
04080 return res;
04081 }
04082 #endif
04083 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04084 static int messagecount(const char *context, const char *mailbox, const char *folder)
04085 {
04086 return __has_voicemail(context, mailbox, folder, 0);
04087 }
04088
04089
04090 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04091 {
04092 DIR *dir;
04093 struct dirent *de;
04094 char fn[256];
04095 int ret = 0;
04096 if (!folder)
04097 folder = "INBOX";
04098
04099 if (ast_strlen_zero(mailbox))
04100 return 0;
04101 if (!context)
04102 context = "default";
04103 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04104 dir = opendir(fn);
04105 if (!dir)
04106 return 0;
04107 while ((de = readdir(dir))) {
04108 if (!strncasecmp(de->d_name, "msg", 3)) {
04109 if (shortcircuit) {
04110 ret = 1;
04111 break;
04112 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
04113 ret++;
04114 }
04115 }
04116 closedir(dir);
04117 return ret;
04118 }
04119
04120
04121 static int has_voicemail(const char *mailbox, const char *folder)
04122 {
04123 char tmp[256], *tmp2 = tmp, *mbox, *context;
04124 ast_copy_string(tmp, mailbox, sizeof(tmp));
04125 while ((mbox = strsep(&tmp2, ","))) {
04126 if ((context = strchr(mbox, '@')))
04127 *context++ = '\0';
04128 else
04129 context = "default";
04130 if (__has_voicemail(context, mbox, folder, 1))
04131 return 1;
04132 }
04133 return 0;
04134 }
04135
04136
04137 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04138 {
04139 char tmp[256];
04140 char *context;
04141
04142 if (newmsgs)
04143 *newmsgs = 0;
04144 if (oldmsgs)
04145 *oldmsgs = 0;
04146
04147 if (ast_strlen_zero(mailbox))
04148 return 0;
04149 if (strchr(mailbox, ',')) {
04150 int tmpnew, tmpold;
04151 char *mb, *cur;
04152
04153 ast_copy_string(tmp, mailbox, sizeof(tmp));
04154 mb = tmp;
04155 while ((cur = strsep(&mb, ", "))) {
04156 if (!ast_strlen_zero(cur)) {
04157 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04158 return -1;
04159 else {
04160 if (newmsgs)
04161 *newmsgs += tmpnew;
04162 if (oldmsgs)
04163 *oldmsgs += tmpold;
04164 }
04165 }
04166 }
04167 return 0;
04168 }
04169 ast_copy_string(tmp, mailbox, sizeof(tmp));
04170 context = strchr(tmp, '@');
04171 if (context) {
04172 *context = '\0';
04173 context++;
04174 } else
04175 context = "default";
04176 if (newmsgs)
04177 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04178 if (oldmsgs)
04179 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04180 return 0;
04181 }
04182
04183 #endif
04184
04185 static void run_externnotify(char *context, char *extension)
04186 {
04187 char arguments[255];
04188 char ext_context[256] = "";
04189 int newvoicemails = 0, oldvoicemails = 0;
04190 struct ast_smdi_mwi_message *mwi_msg;
04191
04192 if (!ast_strlen_zero(context))
04193 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04194 else
04195 ast_copy_string(ext_context, extension, sizeof(ext_context));
04196
04197 if (!strcasecmp(externnotify, "smdi")) {
04198 if (ast_app_has_voicemail(ext_context, NULL))
04199 ast_smdi_mwi_set(smdi_iface, extension);
04200 else
04201 ast_smdi_mwi_unset(smdi_iface, extension);
04202
04203 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04204 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04205 if (!strncmp(mwi_msg->cause, "INV", 3))
04206 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04207 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04208 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04209 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04210 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04211 } else {
04212 if (option_debug)
04213 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
04214 }
04215 } else if (!ast_strlen_zero(externnotify)) {
04216 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
04217 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04218 } else {
04219 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
04220 if (option_debug)
04221 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
04222 ast_safe_system(arguments);
04223 }
04224 }
04225 }
04226
04227 struct leave_vm_options {
04228 unsigned int flags;
04229 signed char record_gain;
04230 };
04231
04232 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
04233 {
04234 #ifdef IMAP_STORAGE
04235 int newmsgs, oldmsgs;
04236 #endif
04237 struct vm_state *vms = NULL;
04238 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
04239 char callerid[256];
04240 FILE *txt;
04241 char date[50];
04242 int txtdes;
04243 int res = 0;
04244 int msgnum;
04245 int duration = 0;
04246 int ausemacro = 0;
04247 int ousemacro = 0;
04248 int ouseexten = 0;
04249 char dir[PATH_MAX], tmpdir[PATH_MAX];
04250 char dest[PATH_MAX];
04251 char fn[PATH_MAX];
04252 char prefile[PATH_MAX] = "";
04253 char tempfile[PATH_MAX] = "";
04254 char ext_context[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2] = "";
04255 char fmt[80];
04256 char *context;
04257 char ecodes[16] = "#";
04258 char tmp[1324] = "", *tmpptr;
04259 struct ast_vm_user *vmu;
04260 struct ast_vm_user svm;
04261 const char *category = NULL;
04262
04263 if (strlen(ext) > sizeof(tmp) - 1) {
04264 ast_log(LOG_WARNING, "List of extensions is too long (>%ld). Truncating.\n", (long) sizeof(tmp) - 1);
04265 }
04266 ast_copy_string(tmp, ext, sizeof(tmp));
04267 ext = tmp;
04268 context = strchr(tmp, '@');
04269 if (context) {
04270 *context++ = '\0';
04271 tmpptr = strchr(context, '&');
04272 } else {
04273 tmpptr = strchr(ext, '&');
04274 }
04275
04276 if (tmpptr)
04277 *tmpptr++ = '\0';
04278
04279 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04280
04281 if (option_debug > 2)
04282 ast_log(LOG_DEBUG, "Before find_user\n");
04283 if (!(vmu = find_user(&svm, context, ext))) {
04284 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
04285 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
04286 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
04287 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04288 return res;
04289 }
04290
04291 if (strcmp(vmu->context, "default"))
04292 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
04293 else
04294 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
04295 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
04296 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
04297 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
04298 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
04299 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
04300 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
04301 }
04302 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
04303 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
04304 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
04305 return -1;
04306 }
04307 RETRIEVE(tempfile, -1, vmu);
04308 if (ast_fileexists(tempfile, NULL, NULL) > 0)
04309 ast_copy_string(prefile, tempfile, sizeof(prefile));
04310 DISPOSE(tempfile, -1);
04311
04312 #ifndef IMAP_STORAGE
04313 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
04314 #else
04315 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
04316 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
04317 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
04318 }
04319 #endif
04320 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
04321
04322
04323 if (ast_test_flag(vmu, VM_OPERATOR)) {
04324 if (!ast_strlen_zero(vmu->exit)) {
04325 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
04326 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04327 ouseexten = 1;
04328 }
04329 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
04330 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04331 ouseexten = 1;
04332 }
04333 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
04334 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04335 ousemacro = 1;
04336 }
04337 }
04338
04339 if (!ast_strlen_zero(vmu->exit)) {
04340 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
04341 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04342 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
04343 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04344 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
04345 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04346 ausemacro = 1;
04347 }
04348
04349
04350 if (!ast_strlen_zero(prefile)) {
04351 res = play_greeting(chan, vmu, prefile, ecodes);
04352 if (res == -2) {
04353
04354 if (option_debug)
04355 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
04356 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
04357 }
04358 if (res < 0) {
04359 if (option_debug)
04360 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
04361 free_user(vmu);
04362 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04363 return -1;
04364 }
04365 }
04366 if (res == '#') {
04367
04368 ast_set_flag(options, OPT_SILENT);
04369 res = 0;
04370 }
04371 if (!res && !ast_test_flag(options, OPT_SILENT)) {
04372 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
04373 if (res == '#') {
04374 ast_set_flag(options, OPT_SILENT);
04375 res = 0;
04376 }
04377 }
04378 if (res > 0)
04379 ast_stopstream(chan);
04380
04381
04382 if (res == '*') {
04383 chan->exten[0] = 'a';
04384 chan->exten[1] = '\0';
04385 if (!ast_strlen_zero(vmu->exit)) {
04386 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04387 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
04388 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04389 }
04390 chan->priority = 0;
04391 free_user(vmu);
04392 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04393 return 0;
04394 }
04395
04396
04397 if (res == '0') {
04398 transfer:
04399 if (ouseexten || ousemacro) {
04400 chan->exten[0] = 'o';
04401 chan->exten[1] = '\0';
04402 if (!ast_strlen_zero(vmu->exit)) {
04403 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04404 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
04405 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04406 }
04407 ast_play_and_wait(chan, "transfer");
04408 chan->priority = 0;
04409 free_user(vmu);
04410 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04411 }
04412 return OPERATOR_EXIT;
04413 }
04414 if (res < 0) {
04415 free_user(vmu);
04416 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04417 return -1;
04418 }
04419
04420 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04421 if (!ast_strlen_zero(fmt)) {
04422 msgnum = 0;
04423
04424 #ifdef IMAP_STORAGE
04425
04426
04427 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
04428 if (res < 0) {
04429 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
04430 return -1;
04431 }
04432 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
04433
04434
04435 if (!(vms = create_vm_state_from_user(vmu))) {
04436 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
04437 return -1;
04438 }
04439 }
04440 vms->newmessages++;
04441
04442 msgnum = newmsgs + oldmsgs;
04443 if (option_debug > 2)
04444 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
04445 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
04446
04447 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04448
04449 if (imap_check_limits(chan, vms, vmu, msgnum)) {
04450 goto leave_vm_out;
04451 }
04452 #else
04453 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
04454 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04455 if (!res)
04456 res = ast_waitstream(chan, "");
04457 ast_log(LOG_WARNING, "No more messages possible\n");
04458 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04459 inprocess_count(vmu->mailbox, vmu->context, -1);
04460 goto leave_vm_out;
04461 }
04462
04463 #endif
04464 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
04465 txtdes = mkstemp(tmptxtfile);
04466 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
04467 if (txtdes < 0) {
04468 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04469 if (!res)
04470 res = ast_waitstream(chan, "");
04471 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
04472 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04473 inprocess_count(vmu->mailbox, vmu->context, -1);
04474 goto leave_vm_out;
04475 }
04476
04477
04478 if (res >= 0) {
04479
04480 res = ast_stream_and_wait(chan, "beep", chan->language, "");
04481 }
04482
04483
04484 txt = fdopen(txtdes, "w+");
04485 if (txt) {
04486 get_date(date, sizeof(date));
04487 fprintf(txt,
04488 ";\n"
04489 "; Message Information file\n"
04490 ";\n"
04491 "[message]\n"
04492 "origmailbox=%s\n"
04493 "context=%s\n"
04494 "macrocontext=%s\n"
04495 "exten=%s\n"
04496 "priority=%d\n"
04497 "callerchan=%s\n"
04498 "callerid=%s\n"
04499 "origdate=%s\n"
04500 "origtime=%ld\n"
04501 "category=%s\n",
04502 ext,
04503 chan->context,
04504 chan->macrocontext,
04505 chan->exten,
04506 chan->priority,
04507 chan->name,
04508 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
04509 date, (long)time(NULL),
04510 category ? category : "");
04511 } else
04512 ast_log(LOG_WARNING, "Error opening text file for output\n");
04513 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
04514
04515 if (txt) {
04516 if (duration < vmminmessage) {
04517 fclose(txt);
04518 if (option_verbose > 2)
04519 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
04520 ast_filedelete(tmptxtfile, NULL);
04521 unlink(tmptxtfile);
04522 inprocess_count(vmu->mailbox, vmu->context, -1);
04523 } else {
04524 fprintf(txt, "duration=%d\n", duration);
04525 fclose(txt);
04526 if (vm_lock_path(dir)) {
04527 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04528
04529 ast_filedelete(tmptxtfile, NULL);
04530 unlink(tmptxtfile);
04531 inprocess_count(vmu->mailbox, vmu->context, -1);
04532 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04533 if (option_debug)
04534 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
04535 unlink(tmptxtfile);
04536 ast_unlock_path(dir);
04537 inprocess_count(vmu->mailbox, vmu->context, -1);
04538 } else {
04539 #ifndef IMAP_STORAGE
04540 msgnum = last_message_index(vmu, dir) + 1;
04541 #endif
04542 make_file(fn, sizeof(fn), dir, msgnum);
04543
04544
04545 #ifndef IMAP_STORAGE
04546 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04547 #else
04548 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04549 #endif
04550
04551 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04552 ast_filerename(tmptxtfile, fn, NULL);
04553 rename(tmptxtfile, txtfile);
04554 inprocess_count(vmu->mailbox, vmu->context, -1);
04555
04556 ast_unlock_path(dir);
04557
04558
04559
04560 if (ast_fileexists(fn, NULL, NULL) > 0) {
04561 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04562 }
04563
04564
04565 while (tmpptr) {
04566 struct ast_vm_user recipu, *recip;
04567 char *exten, *context;
04568
04569 exten = strsep(&tmpptr, "&");
04570 context = strchr(exten, '@');
04571 if (context) {
04572 *context = '\0';
04573 context++;
04574 }
04575 if ((recip = find_user(&recipu, context, exten))) {
04576 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04577 free_user(recip);
04578 }
04579 }
04580
04581 if (ast_fileexists(fn, NULL, NULL)) {
04582 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04583 DISPOSE(dir, msgnum);
04584 }
04585 }
04586 }
04587 } else {
04588 inprocess_count(vmu->mailbox, vmu->context, -1);
04589 }
04590 if (res == '0') {
04591 goto transfer;
04592 } else if (res > 0 && res != 't')
04593 res = 0;
04594
04595 if (duration < vmminmessage)
04596
04597 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04598 else
04599 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04600 } else
04601 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04602 leave_vm_out:
04603 free_user(vmu);
04604
04605 return res;
04606 }
04607
04608 #if !defined(IMAP_STORAGE)
04609 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
04610 {
04611
04612
04613 int x,dest;
04614 char sfn[PATH_MAX];
04615 char dfn[PATH_MAX];
04616
04617 if (vm_lock_path(dir))
04618 return ERROR_LOCK_PATH;
04619
04620 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
04621 make_file(sfn, sizeof(sfn), dir, x);
04622 if (EXISTS(dir, x, sfn, NULL)) {
04623
04624 if (x != dest) {
04625 make_file(dfn, sizeof(dfn), dir, dest);
04626 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04627 }
04628
04629 dest++;
04630 }
04631 }
04632 ast_unlock_path(dir);
04633
04634 return dest;
04635 }
04636 #endif
04637
04638 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04639 {
04640 int d;
04641 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
04642 return d;
04643 }
04644
04645 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04646 {
04647 #ifdef IMAP_STORAGE
04648
04649
04650 char sequence[10];
04651
04652 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04653 if (option_debug > 2)
04654 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
04655 ast_mutex_lock(&vms->lock);
04656 if (box == 1) {
04657 mail_setflag(vms->mailstream, sequence, "\\Seen");
04658 } else if (box == 0) {
04659 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04660 }
04661 if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1)) {
04662 ast_mutex_unlock(&vms->lock);
04663 return 0;
04664 } else {
04665 int res = !mail_copy(vms->mailstream,sequence,(char *) mbox(box));
04666 ast_mutex_unlock(&vms->lock);
04667 return res;
04668 }
04669 #else
04670 char *dir = vms->curdir;
04671 char *username = vms->username;
04672 char *context = vmu->context;
04673 char sfn[PATH_MAX];
04674 char dfn[PATH_MAX];
04675 char ddir[PATH_MAX];
04676 const char *dbox = mbox(box);
04677 int x;
04678 make_file(sfn, sizeof(sfn), dir, msg);
04679 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04680
04681 if (vm_lock_path(ddir))
04682 return ERROR_LOCK_PATH;
04683
04684 for (x = 0; x < vmu->maxmsg; x++) {
04685 make_file(dfn, sizeof(dfn), ddir, x);
04686 if (!EXISTS(ddir, x, dfn, NULL))
04687 break;
04688 }
04689 if (x >= vmu->maxmsg) {
04690 ast_unlock_path(ddir);
04691 return ERROR_MAILBOX_FULL;
04692 }
04693 if (strcmp(sfn, dfn)) {
04694 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04695 }
04696 ast_unlock_path(ddir);
04697 #endif
04698 return 0;
04699 }
04700
04701 static int adsi_logo(unsigned char *buf)
04702 {
04703 int bytes = 0;
04704 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04705 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04706 return bytes;
04707 }
04708
04709 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04710 {
04711 unsigned char buf[256];
04712 int bytes=0;
04713 int x;
04714 char num[5];
04715
04716 *useadsi = 0;
04717 bytes += ast_adsi_data_mode(buf + bytes);
04718 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04719
04720 bytes = 0;
04721 bytes += adsi_logo(buf);
04722 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04723 #ifdef DISPLAY
04724 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04725 #endif
04726 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04727 bytes += ast_adsi_data_mode(buf + bytes);
04728 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04729
04730 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04731 bytes = 0;
04732 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04733 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04734 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04735 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04736 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04737 return 0;
04738 }
04739
04740 #ifdef DISPLAY
04741
04742 bytes = 0;
04743 bytes += ast_adsi_logo(buf);
04744 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04745 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04746 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04747 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04748 #endif
04749 bytes = 0;
04750 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04751 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04752 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04753 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04754 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04755 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04756 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04757
04758 #ifdef DISPLAY
04759
04760 bytes = 0;
04761 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04762 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04763
04764 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04765 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04766 #endif
04767
04768 bytes = 0;
04769
04770 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04771 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04772 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04773 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04774 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04775 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04776 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04777
04778 #ifdef DISPLAY
04779
04780 bytes = 0;
04781 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04782 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04783 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04784 #endif
04785
04786 bytes = 0;
04787 for (x=0;x<5;x++) {
04788 snprintf(num, sizeof(num), "%d", x);
04789 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04790 }
04791 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04792 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04793
04794 #ifdef DISPLAY
04795
04796 bytes = 0;
04797 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04798 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04799 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04800 #endif
04801
04802 if (ast_adsi_end_download(chan)) {
04803 bytes = 0;
04804 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04805 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04806 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04807 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04808 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04809 return 0;
04810 }
04811 bytes = 0;
04812 bytes += ast_adsi_download_disconnect(buf + bytes);
04813 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04814 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04815
04816 if (option_debug)
04817 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
04818
04819 #ifdef DISPLAY
04820
04821 bytes = 0;
04822 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04823 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04824 #endif
04825 if (option_debug)
04826 ast_log(LOG_DEBUG, "Restarting session...\n");
04827
04828 bytes = 0;
04829
04830 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04831 *useadsi = 1;
04832 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04833 } else
04834 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04835
04836 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04837 return 0;
04838 }
04839
04840 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04841 {
04842 int x;
04843 if (!ast_adsi_available(chan))
04844 return;
04845 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04846 if (x < 0)
04847 return;
04848 if (!x) {
04849 if (adsi_load_vmail(chan, useadsi)) {
04850 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04851 return;
04852 }
04853 } else
04854 *useadsi = 1;
04855 }
04856
04857 static void adsi_login(struct ast_channel *chan)
04858 {
04859 unsigned char buf[256];
04860 int bytes=0;
04861 unsigned char keys[8];
04862 int x;
04863 if (!ast_adsi_available(chan))
04864 return;
04865
04866 for (x=0;x<8;x++)
04867 keys[x] = 0;
04868
04869 keys[3] = ADSI_KEY_APPS + 3;
04870
04871 bytes += adsi_logo(buf + bytes);
04872 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04873 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04874 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04875 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04876 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
04877 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
04878 bytes += ast_adsi_set_keys(buf + bytes, keys);
04879 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04880 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04881 }
04882
04883 static void adsi_password(struct ast_channel *chan)
04884 {
04885 unsigned char buf[256];
04886 int bytes=0;
04887 unsigned char keys[8];
04888 int x;
04889 if (!ast_adsi_available(chan))
04890 return;
04891
04892 for (x=0;x<8;x++)
04893 keys[x] = 0;
04894
04895 keys[3] = ADSI_KEY_APPS + 3;
04896
04897 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04898 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
04899 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
04900 bytes += ast_adsi_set_keys(buf + bytes, keys);
04901 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04902 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04903 }
04904
04905 static void adsi_folders(struct ast_channel *chan, int start, char *label)
04906 {
04907 unsigned char buf[256];
04908 int bytes=0;
04909 unsigned char keys[8];
04910 int x,y;
04911
04912 if (!ast_adsi_available(chan))
04913 return;
04914
04915 for (x=0;x<5;x++) {
04916 y = ADSI_KEY_APPS + 12 + start + x;
04917 if (y > ADSI_KEY_APPS + 12 + 4)
04918 y = 0;
04919 keys[x] = ADSI_KEY_SKT | y;
04920 }
04921 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
04922 keys[6] = 0;
04923 keys[7] = 0;
04924
04925 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
04926 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
04927 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04928 bytes += ast_adsi_set_keys(buf + bytes, keys);
04929 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04930
04931 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04932 }
04933
04934 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
04935 {
04936 int bytes=0;
04937 unsigned char buf[256];
04938 char buf1[256], buf2[256];
04939 char fn2[PATH_MAX];
04940
04941 char cid[256]="";
04942 char *val;
04943 char *name, *num;
04944 char datetime[21]="";
04945 FILE *f;
04946
04947 unsigned char keys[8];
04948
04949 int x;
04950
04951 if (!ast_adsi_available(chan))
04952 return;
04953
04954
04955 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
04956 f = fopen(fn2, "r");
04957 if (f) {
04958 while (!feof(f)) {
04959 if (!fgets((char *)buf, sizeof(buf), f)) {
04960 continue;
04961 }
04962 if (!feof(f)) {
04963 char *stringp=NULL;
04964 stringp = (char *)buf;
04965 strsep(&stringp, "=");
04966 val = strsep(&stringp, "=");
04967 if (!ast_strlen_zero(val)) {
04968 if (!strcmp((char *)buf, "callerid"))
04969 ast_copy_string(cid, val, sizeof(cid));
04970 if (!strcmp((char *)buf, "origdate"))
04971 ast_copy_string(datetime, val, sizeof(datetime));
04972 }
04973 }
04974 }
04975 fclose(f);
04976 }
04977
04978 for (x=0;x<5;x++)
04979 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
04980 keys[6] = 0x0;
04981 keys[7] = 0x0;
04982
04983 if (!vms->curmsg) {
04984
04985 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04986 }
04987 if (vms->curmsg >= vms->lastmsg) {
04988
04989 if (vms->curmsg) {
04990
04991 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04992 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04993
04994 } else {
04995
04996 keys[3] = 1;
04997 }
04998 }
04999
05000 if (!ast_strlen_zero(cid)) {
05001 ast_callerid_parse(cid, &name, &num);
05002 if (!name)
05003 name = num;
05004 } else
05005 name = "Unknown Caller";
05006
05007
05008
05009 if (vms->deleted[vms->curmsg])
05010 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05011
05012
05013 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05014 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05015 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05016 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05017
05018 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05019 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05020 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05021 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05022 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05023 bytes += ast_adsi_set_keys(buf + bytes, keys);
05024 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05025
05026 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05027 }
05028
05029 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05030 {
05031 int bytes=0;
05032 unsigned char buf[256];
05033 unsigned char keys[8];
05034
05035 int x;
05036
05037 if (!ast_adsi_available(chan))
05038 return;
05039
05040
05041 for (x=0;x<5;x++)
05042 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05043
05044 keys[6] = 0x0;
05045 keys[7] = 0x0;
05046
05047 if (!vms->curmsg) {
05048
05049 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05050 }
05051 if (vms->curmsg >= vms->lastmsg) {
05052
05053 if (vms->curmsg) {
05054
05055 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05056 } else {
05057
05058 keys[3] = 1;
05059 }
05060 }
05061
05062
05063 if (vms->deleted[vms->curmsg])
05064 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05065
05066
05067 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05068 bytes += ast_adsi_set_keys(buf + bytes, keys);
05069 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05070
05071 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05072 }
05073
05074 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05075 {
05076 unsigned char buf[256] = "";
05077 char buf1[256] = "", buf2[256] = "";
05078 int bytes=0;
05079 unsigned char keys[8];
05080 int x;
05081
05082 char *newm = (vms->newmessages == 1) ? "message" : "messages";
05083 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
05084 if (!ast_adsi_available(chan))
05085 return;
05086 if (vms->newmessages) {
05087 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
05088 if (vms->oldmessages) {
05089 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
05090 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
05091 } else {
05092 snprintf(buf2, sizeof(buf2), "%s.", newm);
05093 }
05094 } else if (vms->oldmessages) {
05095 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
05096 snprintf(buf2, sizeof(buf2), "%s.", oldm);
05097 } else {
05098 strcpy(buf1, "You have no messages.");
05099 buf2[0] = ' ';
05100 buf2[1] = '\0';
05101 }
05102 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05103 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05104 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05105
05106 for (x=0;x<6;x++)
05107 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05108 keys[6] = 0;
05109 keys[7] = 0;
05110
05111
05112 if (vms->lastmsg < 0)
05113 keys[0] = 1;
05114 bytes += ast_adsi_set_keys(buf + bytes, keys);
05115
05116 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05117
05118 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05119 }
05120
05121 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
05122 {
05123 unsigned char buf[256] = "";
05124 char buf1[256] = "", buf2[256] = "";
05125 int bytes=0;
05126 unsigned char keys[8];
05127 int x;
05128
05129 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
05130
05131 if (!ast_adsi_available(chan))
05132 return;
05133
05134
05135 for (x=0;x<6;x++)
05136 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05137
05138 keys[6] = 0;
05139 keys[7] = 0;
05140
05141 if ((vms->lastmsg + 1) < 1)
05142 keys[0] = 0;
05143
05144 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
05145 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
05146
05147 if (vms->lastmsg + 1)
05148 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
05149 else
05150 strcpy(buf2, "no messages.");
05151 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05152 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05153 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
05154 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05155 bytes += ast_adsi_set_keys(buf + bytes, keys);
05156
05157 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05158
05159 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05160
05161 }
05162
05163
05164
05165
05166
05167
05168
05169
05170
05171
05172
05173
05174
05175
05176
05177 static void adsi_goodbye(struct ast_channel *chan)
05178 {
05179 unsigned char buf[256];
05180 int bytes=0;
05181
05182 if (!ast_adsi_available(chan))
05183 return;
05184 bytes += adsi_logo(buf + bytes);
05185 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
05186 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
05187 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05188 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05189
05190 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05191 }
05192
05193
05194
05195
05196
05197 static int get_folder(struct ast_channel *chan, int start)
05198 {
05199 int x;
05200 int d;
05201 char fn[PATH_MAX];
05202 d = ast_play_and_wait(chan, "vm-press");
05203 if (d)
05204 return d;
05205 for (x = start; x< 5; x++) {
05206 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
05207 return d;
05208 d = ast_play_and_wait(chan, "vm-for");
05209 if (d)
05210 return d;
05211 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
05212 d = vm_play_folder_name(chan, fn);
05213 if (d)
05214 return d;
05215 d = ast_waitfordigit(chan, 500);
05216 if (d)
05217 return d;
05218 }
05219 d = ast_play_and_wait(chan, "vm-tocancel");
05220 if (d)
05221 return d;
05222 d = ast_waitfordigit(chan, 4000);
05223 return d;
05224 }
05225
05226 static int get_folder2(struct ast_channel *chan, char *fn, int start)
05227 {
05228 int res = 0;
05229 int loops = 0;
05230 res = ast_play_and_wait(chan, fn);
05231 while (((res < '0') || (res > '9')) &&
05232 (res != '#') && (res >= 0) &&
05233 loops < 4) {
05234 res = get_folder(chan, 0);
05235 loops++;
05236 }
05237 if (loops == 4) {
05238 return '#';
05239 }
05240 return res;
05241 }
05242
05243 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
05244 char *context, signed char record_gain, long *duration, struct vm_state *vms)
05245 {
05246 int cmd = 0;
05247 int retries = 0, prepend_duration = 0, already_recorded = 0;
05248 signed char zero_gain = 0;
05249 struct ast_config *msg_cfg;
05250 const char *duration_cstr;
05251 char msgfile[PATH_MAX], backup[PATH_MAX];
05252 char textfile[PATH_MAX];
05253 char backup_textfile[PATH_MAX];
05254 struct ast_category *msg_cat;
05255 char duration_str[12] = "";
05256
05257 ast_log(LOG_NOTICE, "curdir=%s\n", curdir);
05258
05259 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
05260 strcpy(textfile, msgfile);
05261 strcpy(backup, msgfile);
05262 strcpy(backup_textfile, msgfile);
05263 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05264 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05265 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05266
05267 if (!(msg_cfg = ast_config_load(textfile))) {
05268 return -1;
05269 }
05270
05271 *duration = 0;
05272 if ((duration_cstr = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
05273 *duration = atoi(duration_cstr);
05274 }
05275
05276 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
05277 if (cmd)
05278 retries = 0;
05279 switch (cmd) {
05280 case '1':
05281
05282 {
05283 prepend_duration = 0;
05284
05285
05286 #ifndef IMAP_STORAGE
05287 if (already_recorded) {
05288 ast_filecopy(backup, msgfile, NULL);
05289 copy(textfile, backup_textfile);
05290 } else {
05291 ast_filecopy(msgfile, backup, NULL);
05292 copy(textfile, backup_textfile);
05293 }
05294 #endif
05295 already_recorded = 1;
05296
05297 if (record_gain)
05298 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
05299
05300 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
05301 if (cmd == 'S') {
05302 ast_filerename(backup, msgfile, NULL);
05303 }
05304
05305 if (record_gain)
05306 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
05307
05308 if (prepend_duration) {
05309 prepend_duration += *duration;
05310 }
05311
05312 break;
05313 }
05314 case '2':
05315 cmd = 't';
05316 break;
05317 case '*':
05318 cmd = '*';
05319 break;
05320 default:
05321 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
05322
05323 if (!cmd)
05324 cmd = ast_play_and_wait(chan,"vm-starmain");
05325
05326 if (!cmd)
05327 cmd = ast_waitfordigit(chan,6000);
05328 if (!cmd)
05329 retries++;
05330 if (retries > 3)
05331 cmd = 't';
05332 }
05333 }
05334
05335 if (already_recorded && cmd == -1) {
05336
05337 ast_filerename(backup, msgfile, NULL);
05338 if (duration_cstr) {
05339 ast_copy_string(duration_str, duration_cstr, sizeof(duration_str));
05340 }
05341 } else if (prepend_duration) {
05342 *duration = prepend_duration;
05343 snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration);
05344 }
05345
05346 msg_cat = ast_category_get(msg_cfg, "message");
05347 if (!ast_strlen_zero(duration_str) && !ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
05348 config_text_file_save(textfile, msg_cfg, "app_voicemail");
05349 }
05350 ast_config_destroy(msg_cfg);
05351
05352 if (cmd == 't' || cmd == 'S')
05353 cmd = 0;
05354 return cmd;
05355 }
05356
05357 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
05358 {
05359 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
05360 int newmsgs = 0, oldmsgs = 0;
05361 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
05362
05363 #ifndef IMAP_STORAGE
05364 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
05365 #else
05366 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
05367 #endif
05368 make_file(fn, sizeof(fn), todir, msgnum);
05369 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
05370
05371 if (!ast_strlen_zero(vmu->attachfmt)) {
05372 if (strstr(fmt, vmu->attachfmt)) {
05373 fmt = vmu->attachfmt;
05374 } else {
05375 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);
05376 }
05377 }
05378
05379
05380 fmt = ast_strdupa(fmt);
05381 stringp = fmt;
05382 strsep(&stringp, "|");
05383
05384 if (!ast_strlen_zero(vmu->email)) {
05385 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
05386 char *myserveremail = serveremail;
05387 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
05388 if (!ast_strlen_zero(vmu->serveremail))
05389 myserveremail = vmu->serveremail;
05390
05391 if (attach_user_voicemail)
05392 RETRIEVE(todir, msgnum, vmu);
05393
05394
05395 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
05396
05397 if (attach_user_voicemail)
05398 DISPOSE(todir, msgnum);
05399 }
05400
05401 if (!ast_strlen_zero(vmu->pager)) {
05402 char *myserveremail = serveremail;
05403 if (!ast_strlen_zero(vmu->serveremail))
05404 myserveremail = vmu->serveremail;
05405 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category);
05406 }
05407
05408 if (ast_test_flag(vmu, VM_DELETE)) {
05409 DELETE(todir, msgnum, fn, vmu);
05410 }
05411
05412
05413 if (ast_app_has_voicemail(ext_context, NULL)) {
05414 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
05415 }
05416 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);
05417 run_externnotify(vmu->context, vmu->mailbox);
05418 return 0;
05419 }
05420
05421 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain)
05422 {
05423 #ifdef IMAP_STORAGE
05424 int todircount=0;
05425 struct vm_state *dstvms;
05426 #else
05427 char textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
05428 #endif
05429 char username[70]="";
05430 int res = 0, cmd = 0;
05431 struct ast_vm_user *receiver = NULL, *vmtmp;
05432 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
05433 char *stringp;
05434 const char *s;
05435 int saved_messages = 0;
05436 int valid_extensions = 0;
05437 char *dir;
05438 int curmsg;
05439 int prompt_played = 0;
05440
05441 if (vms == NULL) return -1;
05442 dir = vms->curdir;
05443 curmsg = vms->curmsg;
05444
05445 while (!res && !valid_extensions) {
05446 int use_directory = 0;
05447 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
05448 int done = 0;
05449 int retries = 0;
05450 cmd=0;
05451 while ((cmd >= 0) && !done ){
05452 if (cmd)
05453 retries = 0;
05454 switch (cmd) {
05455 case '1':
05456 use_directory = 0;
05457 done = 1;
05458 break;
05459 case '2':
05460 use_directory = 1;
05461 done=1;
05462 break;
05463 case '*':
05464 cmd = 't';
05465 done = 1;
05466 break;
05467 default:
05468
05469 cmd = ast_play_and_wait(chan,"vm-forward");
05470 if (!cmd)
05471 cmd = ast_waitfordigit(chan,3000);
05472 if (!cmd)
05473 retries++;
05474 if (retries > 3)
05475 {
05476 cmd = 't';
05477 done = 1;
05478 }
05479
05480 }
05481 }
05482 if (cmd < 0 || cmd == 't')
05483 break;
05484 }
05485
05486 if (use_directory) {
05487
05488
05489 char old_context[sizeof(chan->context)];
05490 char old_exten[sizeof(chan->exten)];
05491 int old_priority;
05492 struct ast_app* app;
05493
05494
05495 app = pbx_findapp("Directory");
05496 if (app) {
05497 char vmcontext[256];
05498
05499 memcpy(old_context, chan->context, sizeof(chan->context));
05500 memcpy(old_exten, chan->exten, sizeof(chan->exten));
05501 old_priority = chan->priority;
05502
05503
05504 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
05505 res = pbx_exec(chan, app, vmcontext);
05506
05507 ast_copy_string(username, chan->exten, sizeof(username));
05508
05509
05510 memcpy(chan->context, old_context, sizeof(chan->context));
05511 memcpy(chan->exten, old_exten, sizeof(chan->exten));
05512 chan->priority = old_priority;
05513
05514 } else {
05515 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
05516 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
05517 }
05518 } else {
05519
05520 res = ast_streamfile(chan, "vm-extension", chan->language);
05521 prompt_played++;
05522 if (res || prompt_played > 4)
05523 break;
05524 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
05525 break;
05526 }
05527
05528
05529 if (ast_strlen_zero(username))
05530 continue;
05531 stringp = username;
05532 s = strsep(&stringp, "*");
05533
05534 valid_extensions = 1;
05535 while (s) {
05536
05537 if ((is_new_message == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
05538 int oldmsgs;
05539 int newmsgs;
05540 int capacity;
05541 if (inboxcount(s, &newmsgs, &oldmsgs)) {
05542 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
05543
05544 res = ast_play_and_wait(chan, "pbx-invalid");
05545 valid_extensions = 0;
05546 break;
05547 }
05548 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
05549 if ((newmsgs + oldmsgs) >= capacity) {
05550 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
05551 res = ast_play_and_wait(chan, "vm-mailboxfull");
05552 valid_extensions = 0;
05553 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05554 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05555 free_user(vmtmp);
05556 }
05557 inprocess_count(receiver->mailbox, receiver->context, -1);
05558 break;
05559 }
05560 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
05561 } else {
05562 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
05563
05564 res = ast_play_and_wait(chan, "pbx-invalid");
05565 valid_extensions = 0;
05566 break;
05567 }
05568 s = strsep(&stringp, "*");
05569 }
05570
05571 if (valid_extensions)
05572 break;
05573 }
05574
05575 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
05576 return res;
05577 if (is_new_message == 1) {
05578 struct leave_vm_options leave_options;
05579 char mailbox[AST_MAX_EXTENSION * 2 + 2];
05580
05581 if (context)
05582 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
05583 else
05584 ast_copy_string(mailbox, username, sizeof(mailbox));
05585
05586
05587 memset(&leave_options, 0, sizeof(leave_options));
05588 leave_options.record_gain = record_gain;
05589 cmd = leave_voicemail(chan, mailbox, &leave_options);
05590 } else {
05591
05592 long duration = 0;
05593 struct vm_state vmstmp;
05594 #ifndef IMAP_STORAGE
05595 char msgfile[PATH_MAX];
05596 #endif
05597 int copy_msg_result = 0;
05598
05599 memcpy(&vmstmp, vms, sizeof(vmstmp));
05600
05601 RETRIEVE(dir, curmsg, sender);
05602
05603 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05604 if (!cmd) {
05605 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05606 #ifdef IMAP_STORAGE
05607 char *myserveremail;
05608 int attach_user_voicemail;
05609
05610 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
05611 if (!dstvms) {
05612 dstvms = create_vm_state_from_user(vmtmp);
05613 }
05614 if (dstvms) {
05615 init_mailstream(dstvms, 0);
05616 if (!dstvms->mailstream) {
05617 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
05618 } else {
05619 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05620 run_externnotify(vmtmp->context, vmtmp->mailbox);
05621 }
05622 } else {
05623 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
05624 }
05625 myserveremail = serveremail;
05626 if (!ast_strlen_zero(vmtmp->serveremail))
05627 myserveremail = vmtmp->serveremail;
05628 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05629
05630 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
05631 #else
05632 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir);
05633 #endif
05634 saved_messages++;
05635 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05636 AST_LIST_REMOVE_CURRENT(&extensions, list);
05637 free_user(vmtmp);
05638 if (res)
05639 break;
05640 }
05641 AST_LIST_TRAVERSE_SAFE_END;
05642 if (saved_messages > 0 && !copy_msg_result) {
05643
05644
05645
05646
05647
05648
05649
05650
05651 res = ast_play_and_wait(chan, "vm-msgsaved");
05652 }
05653 #ifndef IMAP_STORAGE
05654 else {
05655
05656 res = ast_play_and_wait(chan, "vm-mailboxfull");
05657 }
05658
05659 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05660 strcpy(textfile, msgfile);
05661 strcpy(backup, msgfile);
05662 strcpy(backup_textfile, msgfile);
05663 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05664 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05665 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05666 if (ast_fileexists(backup, NULL, NULL) > 0) {
05667 ast_filerename(backup, msgfile, NULL);
05668 rename(backup_textfile, textfile);
05669 }
05670 #endif
05671 }
05672 DISPOSE(dir, curmsg);
05673 #ifndef IMAP_STORAGE
05674 if (cmd) {
05675 make_file(msgfile, sizeof(msgfile), dir, curmsg);
05676 strcpy(textfile, msgfile);
05677 strcpy(backup_textfile, msgfile);
05678 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05679 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
05680 rename(backup_textfile, textfile);
05681 }
05682 #endif
05683 }
05684
05685
05686 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05687 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
05688 free_user(vmtmp);
05689 }
05690 return res ? res : cmd;
05691 }
05692
05693 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05694 {
05695 int res;
05696 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
05697 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05698 return res;
05699 }
05700
05701 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05702 {
05703 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
05704 }
05705
05706 static int play_message_category(struct ast_channel *chan, const char *category)
05707 {
05708 int res = 0;
05709
05710 if (!ast_strlen_zero(category))
05711 res = ast_play_and_wait(chan, category);
05712
05713 if (res) {
05714 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05715 res = 0;
05716 }
05717
05718 return res;
05719 }
05720
05721 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05722 {
05723 int res = 0;
05724 struct vm_zone *the_zone = NULL;
05725 time_t t;
05726
05727 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05728 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05729 return 0;
05730 }
05731
05732
05733 if (!ast_strlen_zero(vmu->zonetag)) {
05734
05735 struct vm_zone *z;
05736 AST_LIST_LOCK(&zones);
05737 AST_LIST_TRAVERSE(&zones, z, list) {
05738 if (!strcmp(z->name, vmu->zonetag)) {
05739 the_zone = z;
05740 break;
05741 }
05742 }
05743 AST_LIST_UNLOCK(&zones);
05744 }
05745
05746
05747 #if 0
05748
05749 ast_localtime(&t, &time_now, NULL);
05750 tv_now = ast_tvnow();
05751 tnow = tv_now.tv_sec;
05752 ast_localtime(&tnow, &time_then, NULL);
05753
05754
05755 if (time_now.tm_year == time_then.tm_year)
05756 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
05757 else
05758 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05759 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05760
05761
05762 #endif
05763 if (the_zone) {
05764 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05765 } else if (!strncasecmp(chan->language, "de", 2)) {
05766 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05767 } else if (!strncasecmp(chan->language, "gr", 2)) {
05768 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05769 } else if (!strncasecmp(chan->language, "he", 2)) {
05770 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'at2' kM", NULL);
05771 } else if (!strncasecmp(chan->language, "it", 2)) {
05772 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);
05773 } else if (!strncasecmp(chan->language, "nl", 2)) {
05774 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05775 } else if (!strncasecmp(chan->language, "no", 2)) {
05776 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05777 } else if (!strncasecmp(chan->language, "pl", 2)) {
05778 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05779 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
05780 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);
05781 } else if (!strncasecmp(chan->language, "se", 2)) {
05782 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05783 } else {
05784 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05785 }
05786 #if 0
05787 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05788 #endif
05789 return res;
05790 }
05791
05792
05793
05794 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05795 {
05796 int res = 0;
05797 int i;
05798 char *callerid, *name;
05799 char prefile[PATH_MAX] = "";
05800
05801
05802
05803
05804 if ((cid == NULL)||(context == NULL))
05805 return res;
05806
05807
05808 if (option_debug > 2)
05809 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05810 ast_callerid_parse(cid, &name, &callerid);
05811 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05812
05813
05814 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
05815 if (option_debug > 2)
05816 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05817 if ((strcmp(cidinternalcontexts[i], context) == 0))
05818 break;
05819 }
05820 if (i != MAX_NUM_CID_CONTEXTS){
05821 if (!res) {
05822 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05823 if (!ast_strlen_zero(prefile)) {
05824
05825 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05826 if (option_verbose > 2)
05827 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05828 if (!callback)
05829 res = wait_file2(chan, vms, "vm-from");
05830 res = ast_stream_and_wait(chan, prefile, chan->language, "");
05831 } else {
05832 if (option_verbose > 2)
05833 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
05834
05835 if (!callback)
05836 res = wait_file2(chan, vms, "vm-from-extension");
05837 res = ast_say_digit_str(chan, callerid, "", chan->language);
05838 }
05839 }
05840 }
05841 }
05842
05843 else if (!res){
05844 if (option_debug > 2)
05845 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
05846
05847 if (!callback)
05848 res = wait_file2(chan, vms, "vm-from-phonenumber");
05849 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05850 }
05851 } else {
05852
05853 if (option_debug)
05854 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
05855
05856 res = wait_file2(chan, vms, "vm-unknown-caller");
05857 }
05858 return res;
05859 }
05860
05861 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05862 {
05863 int res = 0;
05864 int durationm;
05865 int durations;
05866
05867 if (duration == NULL)
05868 return res;
05869
05870
05871 durations=atoi(duration);
05872 durationm=(durations / 60);
05873
05874 if (option_debug > 2)
05875 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05876
05877 if ((!res) && (durationm >= minduration)) {
05878 res = wait_file2(chan, vms, "vm-duration");
05879
05880
05881 if (!strncasecmp(chan->language, "pl", 2)) {
05882 div_t num = div(durationm, 10);
05883
05884 if (durationm == 1) {
05885 res = ast_play_and_wait(chan, "digits/1z");
05886 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05887 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05888 if (num.rem == 2) {
05889 if (!num.quot) {
05890 res = ast_play_and_wait(chan, "digits/2-ie");
05891 } else {
05892 res = say_and_wait(chan, durationm - 2 , chan->language);
05893 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05894 }
05895 } else {
05896 res = say_and_wait(chan, durationm, chan->language);
05897 }
05898 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05899 } else {
05900 res = say_and_wait(chan, durationm, chan->language);
05901 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05902 }
05903
05904 } else {
05905 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05906 res = wait_file2(chan, vms, "vm-minutes");
05907 }
05908 }
05909 return res;
05910 }
05911
05912 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05913 {
05914 int res = 0;
05915 char filename[256], *cid;
05916 const char *origtime, *context, *category, *duration;
05917 struct ast_config *msg_cfg;
05918
05919 vms->starting = 0;
05920 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05921 adsi_message(chan, vms);
05922
05923 if (!strncasecmp(chan->language, "he", 2)) {
05924
05925
05926
05927
05928 if (!vms->curmsg) {
05929 res = wait_file2(chan, vms, "vm-message");
05930 res = wait_file2(chan, vms, "vm-first");
05931 } else if (vms->curmsg == vms->lastmsg) {
05932 res = wait_file2(chan, vms, "vm-message");
05933 res = wait_file2(chan, vms, "vm-last");
05934 } else {
05935 res = wait_file2(chan, vms, "vm-message");
05936 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05937 ast_log(LOG_DEBUG, "curmsg: %d\n", vms->curmsg);
05938 ast_log(LOG_DEBUG, "lagmsg: %d\n", vms->lastmsg);
05939 if (!res) {
05940 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
05941 }
05942 }
05943 }
05944
05945 } else if (!strncasecmp(chan->language, "pl", 2)) {
05946 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05947 int ten, one;
05948 char nextmsg[256];
05949 ten = (vms->curmsg + 1) / 10;
05950 one = (vms->curmsg + 1) % 10;
05951
05952 if (vms->curmsg < 20) {
05953 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
05954 res = wait_file2(chan, vms, nextmsg);
05955 } else {
05956 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
05957 res = wait_file2(chan, vms, nextmsg);
05958 if (one > 0) {
05959 if (!res) {
05960 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
05961 res = wait_file2(chan, vms, nextmsg);
05962 }
05963 }
05964 }
05965 }
05966 if (!res)
05967 res = wait_file2(chan, vms, "vm-message");
05968
05969 } else if (!strncasecmp(chan->language, "se", 2)) {
05970 if (!vms->curmsg)
05971 res = wait_file2(chan, vms, "vm-first");
05972 else if (vms->curmsg == vms->lastmsg)
05973 res = wait_file2(chan, vms, "vm-last");
05974 res = wait_file2(chan, vms, "vm-meddelandet");
05975 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05976 if (!res)
05977 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
05978 }
05979
05980
05981
05982
05983
05984 } else {
05985 if (!vms->curmsg)
05986 res = wait_file2(chan, vms, "vm-first");
05987 else if (vms->curmsg == vms->lastmsg)
05988 res = wait_file2(chan, vms, "vm-last");
05989 res = wait_file2(chan, vms, "vm-message");
05990 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05991 if (!res)
05992 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
05993 }
05994 }
05995
05996
05997 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
05998 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
05999 RETRIEVE(vms->curdir, vms->curmsg, vmu);
06000 msg_cfg = ast_config_load(filename);
06001 if (!msg_cfg) {
06002 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06003 return 0;
06004 }
06005
06006 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
06007 ast_log(LOG_WARNING, "No origtime?!\n");
06008 DISPOSE(vms->curdir, vms->curmsg);
06009 ast_config_destroy(msg_cfg);
06010 return 0;
06011 }
06012
06013 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
06014 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
06015 category = ast_variable_retrieve(msg_cfg, "message", "category");
06016
06017 context = ast_variable_retrieve(msg_cfg, "message", "context");
06018 if (!strncasecmp("macro",context,5))
06019 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
06020 if (!res)
06021 res = play_message_category(chan, category);
06022 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
06023 res = play_message_datetime(chan, vmu, origtime, filename);
06024 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
06025 res = play_message_callerid(chan, vms, cid, context, 0);
06026 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
06027 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
06028
06029 if (res == '1')
06030 res = 0;
06031 ast_config_destroy(msg_cfg);
06032
06033 if (!res) {
06034 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06035 vms->heard[vms->curmsg] = 1;
06036 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
06037 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
06038 res = 0;
06039 }
06040 }
06041 DISPOSE(vms->curdir, vms->curmsg);
06042 return res;
06043 }
06044
06045 #ifndef IMAP_STORAGE
06046 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
06047 {
06048 int count_msg, last_msg;
06049
06050 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
06051
06052
06053
06054
06055 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
06056
06057
06058 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
06059
06060
06061 count_msg = count_messages(vmu, vms->curdir);
06062 if (count_msg < 0)
06063 return count_msg;
06064 else
06065 vms->lastmsg = count_msg - 1;
06066
06067 if (vm_allocate_dh(vms, vmu, count_msg)) {
06068 return -1;
06069 }
06070
06071
06072
06073
06074
06075
06076
06077
06078
06079 last_msg = last_message_index(vmu, vms->curdir);
06080
06081 if (last_msg < -1) {
06082 return last_msg;
06083 } else if (vms->lastmsg != last_msg) {
06084 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
06085 resequence_mailbox(vmu, vms->curdir, count_msg);
06086 }
06087
06088 return 0;
06089 }
06090 #endif
06091
06092 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
06093 {
06094 int x = 0;
06095 #ifndef IMAP_STORAGE
06096 int last_msg_index;
06097 int res = 0, nummsg;
06098 #endif
06099
06100 if (vms->lastmsg <= -1)
06101 goto done;
06102
06103 vms->curmsg = -1;
06104 #ifndef IMAP_STORAGE
06105
06106 if (vm_lock_path(vms->curdir))
06107 return ERROR_LOCK_PATH;
06108
06109 last_msg_index = last_message_index(vmu, vms->curdir);
06110 if (last_msg_index != vms->lastmsg) {
06111 ast_log(LOG_NOTICE, "%d messages arrived while mailbox was open\n", last_msg_index - vms->lastmsg);
06112 }
06113
06114
06115 for (x = 0; x < last_msg_index + 1; x++) {
06116 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
06117
06118 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06119 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
06120 break;
06121 vms->curmsg++;
06122 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06123 if (strcmp(vms->fn, vms->fn2)) {
06124 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
06125 }
06126 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
06127
06128 res = save_to_folder(vmu, vms, x, 1);
06129 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
06130
06131 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
06132 vms->deleted[x] = 0;
06133 vms->heard[x] = 0;
06134 --x;
06135 }
06136 }
06137 }
06138
06139
06140 nummsg = x - 1;
06141 for (x = vms->curmsg + 1; x <= nummsg; x++) {
06142 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06143 if (EXISTS(vms->curdir, x, vms->fn, NULL))
06144 DELETE(vms->curdir, x, vms->fn, vmu);
06145 }
06146 ast_unlock_path(vms->curdir);
06147 #else
06148 if (vms->deleted) {
06149
06150
06151 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
06152 if (vms->deleted[x]) {
06153 if (option_debug > 2) {
06154 ast_log(LOG_DEBUG, "IMAP delete of %d\n", x);
06155 }
06156 DELETE(vms->curdir, x, vms->fn, vmu);
06157 }
06158 }
06159 }
06160 #endif
06161
06162 done:
06163 if (vms->deleted)
06164 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
06165 if (vms->heard)
06166 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
06167
06168 return 0;
06169 }
06170
06171
06172
06173
06174
06175
06176
06177 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
06178 {
06179 int cmd;
06180 char *buf;
06181
06182 buf = alloca(strlen(mbox)+2);
06183 strcpy(buf, mbox);
06184 strcat(buf,"s");
06185
06186 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
06187 cmd = ast_play_and_wait(chan, buf);
06188 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06189 } else {
06190 cmd = ast_play_and_wait(chan, "vm-messages");
06191 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06192 }
06193 }
06194
06195 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
06196 {
06197 int cmd;
06198
06199 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
06200 if (!strcasecmp(mbox, "vm-INBOX"))
06201 cmd = ast_play_and_wait(chan, "vm-new-e");
06202 else
06203 cmd = ast_play_and_wait(chan, "vm-old-e");
06204 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06205 } else {
06206 cmd = ast_play_and_wait(chan, "vm-messages");
06207 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06208 }
06209 }
06210
06211 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
06212 {
06213 int cmd;
06214
06215 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
06216 cmd = ast_play_and_wait(chan, "vm-messages");
06217 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06218 } else {
06219 cmd = ast_play_and_wait(chan, mbox);
06220 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06221 }
06222 }
06223
06224 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
06225 {
06226 int cmd;
06227
06228 if ( !strncasecmp(chan->language, "it", 2) ||
06229 !strncasecmp(chan->language, "es", 2) ||
06230 !strncasecmp(chan->language, "pt", 2)) {
06231 cmd = ast_play_and_wait(chan, "vm-messages");
06232 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06233 } else if (!strncasecmp(chan->language, "gr", 2)) {
06234 return vm_play_folder_name_gr(chan, mbox);
06235 } else if (!strncasecmp(chan->language, "pl", 2)) {
06236 return vm_play_folder_name_pl(chan, mbox);
06237 } else if (!strncasecmp(chan->language, "ua", 2)) {
06238 return vm_play_folder_name_ua(chan, mbox);
06239 } else if (!strncasecmp(chan->language, "he", 2)) {
06240 cmd = ast_play_and_wait(chan, mbox);
06241 return cmd;
06242 } else {
06243 cmd = ast_play_and_wait(chan, mbox);
06244 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06245 }
06246 }
06247
06248
06249
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
06261 {
06262 int res = 0;
06263
06264 if (vms->newmessages) {
06265 res = ast_play_and_wait(chan, "vm-youhave");
06266 if (!res)
06267 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
06268 if (!res) {
06269 if ((vms->newmessages == 1)) {
06270 res = ast_play_and_wait(chan, "vm-INBOX");
06271 if (!res)
06272 res = ast_play_and_wait(chan, "vm-message");
06273 } else {
06274 res = ast_play_and_wait(chan, "vm-INBOXs");
06275 if (!res)
06276 res = ast_play_and_wait(chan, "vm-messages");
06277 }
06278 }
06279 } else if (vms->oldmessages){
06280 res = ast_play_and_wait(chan, "vm-youhave");
06281 if (!res)
06282 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
06283 if ((vms->oldmessages == 1)){
06284 res = ast_play_and_wait(chan, "vm-Old");
06285 if (!res)
06286 res = ast_play_and_wait(chan, "vm-message");
06287 } else {
06288 res = ast_play_and_wait(chan, "vm-Olds");
06289 if (!res)
06290 res = ast_play_and_wait(chan, "vm-messages");
06291 }
06292 } else if (!vms->oldmessages && !vms->newmessages)
06293 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
06294 return res;
06295 }
06296
06297
06298 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
06299 {
06300 int res;
06301
06302
06303 res = ast_play_and_wait(chan, "vm-youhave");
06304 if (!res) {
06305 if (vms->newmessages) {
06306 res = say_and_wait(chan, vms->newmessages, chan->language);
06307 if (!res)
06308 res = ast_play_and_wait(chan, "vm-INBOX");
06309 if (vms->oldmessages && !res)
06310 res = ast_play_and_wait(chan, "vm-and");
06311 else if (!res) {
06312 if ((vms->newmessages == 1))
06313 res = ast_play_and_wait(chan, "vm-message");
06314 else
06315 res = ast_play_and_wait(chan, "vm-messages");
06316 }
06317
06318 }
06319 if (!res && vms->oldmessages) {
06320 res = say_and_wait(chan, vms->oldmessages, chan->language);
06321 if (!res)
06322 res = ast_play_and_wait(chan, "vm-Old");
06323 if (!res) {
06324 if (vms->oldmessages == 1)
06325 res = ast_play_and_wait(chan, "vm-message");
06326 else
06327 res = ast_play_and_wait(chan, "vm-messages");
06328 }
06329 }
06330 if (!res) {
06331 if (!vms->oldmessages && !vms->newmessages) {
06332 res = ast_play_and_wait(chan, "vm-no");
06333 if (!res)
06334 res = ast_play_and_wait(chan, "vm-messages");
06335 }
06336 }
06337 }
06338 return res;
06339 }
06340
06341
06342
06343
06344
06345
06346
06347
06348
06349
06350
06351
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369
06370
06371
06372
06373
06374
06375
06376
06377
06378
06379
06380
06381
06382
06383
06384
06385
06386
06387
06388
06389
06390
06391
06392
06393
06394
06395
06396
06397
06398 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
06399 {
06400 int res;
06401 int lastnum = 0;
06402
06403 res = ast_play_and_wait(chan, "vm-youhave");
06404
06405 if (!res && vms->newmessages) {
06406 lastnum = vms->newmessages;
06407
06408 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06409 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
06410 }
06411
06412 if (!res && vms->oldmessages) {
06413 res = ast_play_and_wait(chan, "vm-and");
06414 }
06415 }
06416
06417 if (!res && vms->oldmessages) {
06418 lastnum = vms->oldmessages;
06419
06420 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06421 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
06422 }
06423 }
06424
06425 if (!res) {
06426 if (lastnum == 0) {
06427 res = ast_play_and_wait(chan, "vm-no");
06428 }
06429 if (!res) {
06430 res = ast_say_counted_noun(chan, lastnum, "vm-message");
06431 }
06432 }
06433
06434 return res;
06435 }
06436
06437
06438 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
06439 {
06440 int res=0;
06441
06442
06443 if (!res) {
06444 if ((vms->newmessages) || (vms->oldmessages)) {
06445 res = ast_play_and_wait(chan, "vm-youhave");
06446 }
06447
06448
06449
06450
06451
06452 if (vms->newmessages) {
06453 if (!res) {
06454 if (vms->newmessages == 1) {
06455 res = ast_play_and_wait(chan, "vm-INBOX1");
06456 } else {
06457 if (vms->newmessages == 2) {
06458 res = ast_play_and_wait(chan, "vm-shtei");
06459 } else {
06460 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06461 }
06462 res = ast_play_and_wait(chan, "vm-INBOX");
06463 }
06464 }
06465 if (vms->oldmessages && !res) {
06466 res = ast_play_and_wait(chan, "vm-and");
06467 if (vms->oldmessages == 1) {
06468 res = ast_play_and_wait(chan, "vm-Old1");
06469 } else {
06470 if (vms->oldmessages == 2) {
06471 res = ast_play_and_wait(chan, "vm-shtei");
06472 } else {
06473 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06474 }
06475 res = ast_play_and_wait(chan, "vm-Old");
06476 }
06477 }
06478 }
06479 if (!res && vms->oldmessages && !vms->newmessages) {
06480 if (!res) {
06481 if (vms->oldmessages == 1) {
06482 res = ast_play_and_wait(chan, "vm-Old1");
06483 } else {
06484 if (vms->oldmessages == 2) {
06485 res = ast_play_and_wait(chan, "vm-shtei");
06486 } else {
06487 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06488 }
06489 res = ast_play_and_wait(chan, "vm-Old");
06490 }
06491 }
06492 }
06493 if (!res) {
06494 if (!vms->oldmessages && !vms->newmessages) {
06495 if (!res) {
06496 res = ast_play_and_wait(chan, "vm-nomessages");
06497 }
06498 }
06499 }
06500 }
06501 return res;
06502 }
06503
06504
06505
06506 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
06507 {
06508
06509 int res;
06510 if (!vms->oldmessages && !vms->newmessages)
06511 res = ast_play_and_wait(chan, "vm-no") ||
06512 ast_play_and_wait(chan, "vm-message");
06513 else
06514 res = ast_play_and_wait(chan, "vm-youhave");
06515 if (!res && vms->newmessages) {
06516 res = (vms->newmessages == 1) ?
06517 ast_play_and_wait(chan, "digits/un") ||
06518 ast_play_and_wait(chan, "vm-nuovo") ||
06519 ast_play_and_wait(chan, "vm-message") :
06520
06521 say_and_wait(chan, vms->newmessages, chan->language) ||
06522 ast_play_and_wait(chan, "vm-nuovi") ||
06523 ast_play_and_wait(chan, "vm-messages");
06524 if (!res && vms->oldmessages)
06525 res = ast_play_and_wait(chan, "vm-and");
06526 }
06527 if (!res && vms->oldmessages) {
06528 res = (vms->oldmessages == 1) ?
06529 ast_play_and_wait(chan, "digits/un") ||
06530 ast_play_and_wait(chan, "vm-vecchio") ||
06531 ast_play_and_wait(chan, "vm-message") :
06532
06533 say_and_wait(chan, vms->oldmessages, chan->language) ||
06534 ast_play_and_wait(chan, "vm-vecchi") ||
06535 ast_play_and_wait(chan, "vm-messages");
06536 }
06537 return res;
06538 }
06539
06540
06541 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
06542 {
06543
06544 int res;
06545 div_t num;
06546
06547 if (!vms->oldmessages && !vms->newmessages) {
06548 res = ast_play_and_wait(chan, "vm-no");
06549 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06550 return res;
06551 } else {
06552 res = ast_play_and_wait(chan, "vm-youhave");
06553 }
06554
06555 if (vms->newmessages) {
06556 num = div(vms->newmessages, 10);
06557 if (vms->newmessages == 1) {
06558 res = ast_play_and_wait(chan, "digits/1-a");
06559 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
06560 res = res ? res : ast_play_and_wait(chan, "vm-message");
06561 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06562 if (num.rem == 2) {
06563 if (!num.quot) {
06564 res = ast_play_and_wait(chan, "digits/2-ie");
06565 } else {
06566 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
06567 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06568 }
06569 } else {
06570 res = say_and_wait(chan, vms->newmessages, chan->language);
06571 }
06572 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
06573 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06574 } else {
06575 res = say_and_wait(chan, vms->newmessages, chan->language);
06576 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
06577 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06578 }
06579 if (!res && vms->oldmessages)
06580 res = ast_play_and_wait(chan, "vm-and");
06581 }
06582 if (!res && vms->oldmessages) {
06583 num = div(vms->oldmessages, 10);
06584 if (vms->oldmessages == 1) {
06585 res = ast_play_and_wait(chan, "digits/1-a");
06586 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
06587 res = res ? res : ast_play_and_wait(chan, "vm-message");
06588 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06589 if (num.rem == 2) {
06590 if (!num.quot) {
06591 res = ast_play_and_wait(chan, "digits/2-ie");
06592 } else {
06593 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
06594 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06595 }
06596 } else {
06597 res = say_and_wait(chan, vms->oldmessages, chan->language);
06598 }
06599 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
06600 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06601 } else {
06602 res = say_and_wait(chan, vms->oldmessages, chan->language);
06603 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
06604 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06605 }
06606 }
06607
06608 return res;
06609 }
06610
06611
06612 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
06613 {
06614
06615 int res;
06616
06617 res = ast_play_and_wait(chan, "vm-youhave");
06618 if (res)
06619 return res;
06620
06621 if (!vms->oldmessages && !vms->newmessages) {
06622 res = ast_play_and_wait(chan, "vm-no");
06623 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06624 return res;
06625 }
06626
06627 if (vms->newmessages) {
06628 if ((vms->newmessages == 1)) {
06629 res = ast_play_and_wait(chan, "digits/ett");
06630 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
06631 res = res ? res : ast_play_and_wait(chan, "vm-message");
06632 } else {
06633 res = say_and_wait(chan, vms->newmessages, chan->language);
06634 res = res ? res : ast_play_and_wait(chan, "vm-nya");
06635 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06636 }
06637 if (!res && vms->oldmessages)
06638 res = ast_play_and_wait(chan, "vm-and");
06639 }
06640 if (!res && vms->oldmessages) {
06641 if (vms->oldmessages == 1) {
06642 res = ast_play_and_wait(chan, "digits/ett");
06643 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
06644 res = res ? res : ast_play_and_wait(chan, "vm-message");
06645 } else {
06646 res = say_and_wait(chan, vms->oldmessages, chan->language);
06647 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
06648 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06649 }
06650 }
06651
06652 return res;
06653 }
06654
06655
06656 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
06657 {
06658
06659 int res;
06660
06661 res = ast_play_and_wait(chan, "vm-youhave");
06662 if (res)
06663 return res;
06664
06665 if (!vms->oldmessages && !vms->newmessages) {
06666 res = ast_play_and_wait(chan, "vm-no");
06667 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06668 return res;
06669 }
06670
06671 if (vms->newmessages) {
06672 if ((vms->newmessages == 1)) {
06673 res = ast_play_and_wait(chan, "digits/1");
06674 res = res ? res : ast_play_and_wait(chan, "vm-ny");
06675 res = res ? res : ast_play_and_wait(chan, "vm-message");
06676 } else {
06677 res = say_and_wait(chan, vms->newmessages, chan->language);
06678 res = res ? res : ast_play_and_wait(chan, "vm-nye");
06679 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06680 }
06681 if (!res && vms->oldmessages)
06682 res = ast_play_and_wait(chan, "vm-and");
06683 }
06684 if (!res && vms->oldmessages) {
06685 if (vms->oldmessages == 1) {
06686 res = ast_play_and_wait(chan, "digits/1");
06687 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
06688 res = res ? res : ast_play_and_wait(chan, "vm-message");
06689 } else {
06690 res = say_and_wait(chan, vms->oldmessages, chan->language);
06691 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
06692 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06693 }
06694 }
06695
06696 return res;
06697 }
06698
06699
06700 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
06701 {
06702
06703 int res;
06704 res = ast_play_and_wait(chan, "vm-youhave");
06705 if (!res) {
06706 if (vms->newmessages) {
06707 if ((vms->newmessages == 1))
06708 res = ast_play_and_wait(chan, "digits/1F");
06709 else
06710 res = say_and_wait(chan, vms->newmessages, chan->language);
06711 if (!res)
06712 res = ast_play_and_wait(chan, "vm-INBOX");
06713 if (vms->oldmessages && !res)
06714 res = ast_play_and_wait(chan, "vm-and");
06715 else if (!res) {
06716 if ((vms->newmessages == 1))
06717 res = ast_play_and_wait(chan, "vm-message");
06718 else
06719 res = ast_play_and_wait(chan, "vm-messages");
06720 }
06721
06722 }
06723 if (!res && vms->oldmessages) {
06724 if (vms->oldmessages == 1)
06725 res = ast_play_and_wait(chan, "digits/1F");
06726 else
06727 res = say_and_wait(chan, vms->oldmessages, chan->language);
06728 if (!res)
06729 res = ast_play_and_wait(chan, "vm-Old");
06730 if (!res) {
06731 if (vms->oldmessages == 1)
06732 res = ast_play_and_wait(chan, "vm-message");
06733 else
06734 res = ast_play_and_wait(chan, "vm-messages");
06735 }
06736 }
06737 if (!res) {
06738 if (!vms->oldmessages && !vms->newmessages) {
06739 res = ast_play_and_wait(chan, "vm-no");
06740 if (!res)
06741 res = ast_play_and_wait(chan, "vm-messages");
06742 }
06743 }
06744 }
06745 return res;
06746 }
06747
06748
06749 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
06750 {
06751
06752 int res;
06753 if (!vms->oldmessages && !vms->newmessages) {
06754 res = ast_play_and_wait(chan, "vm-youhaveno");
06755 if (!res)
06756 res = ast_play_and_wait(chan, "vm-messages");
06757 } else {
06758 res = ast_play_and_wait(chan, "vm-youhave");
06759 }
06760 if (!res) {
06761 if (vms->newmessages) {
06762 if (!res) {
06763 if ((vms->newmessages == 1)) {
06764 res = ast_play_and_wait(chan, "digits/1M");
06765 if (!res)
06766 res = ast_play_and_wait(chan, "vm-message");
06767 if (!res)
06768 res = ast_play_and_wait(chan, "vm-INBOXs");
06769 } else {
06770 res = say_and_wait(chan, vms->newmessages, chan->language);
06771 if (!res)
06772 res = ast_play_and_wait(chan, "vm-messages");
06773 if (!res)
06774 res = ast_play_and_wait(chan, "vm-INBOX");
06775 }
06776 }
06777 if (vms->oldmessages && !res)
06778 res = ast_play_and_wait(chan, "vm-and");
06779 }
06780 if (vms->oldmessages) {
06781 if (!res) {
06782 if (vms->oldmessages == 1) {
06783 res = ast_play_and_wait(chan, "digits/1M");
06784 if (!res)
06785 res = ast_play_and_wait(chan, "vm-message");
06786 if (!res)
06787 res = ast_play_and_wait(chan, "vm-Olds");
06788 } else {
06789 res = say_and_wait(chan, vms->oldmessages, chan->language);
06790 if (!res)
06791 res = ast_play_and_wait(chan, "vm-messages");
06792 if (!res)
06793 res = ast_play_and_wait(chan, "vm-Old");
06794 }
06795 }
06796 }
06797 }
06798 return res;
06799 }
06800
06801
06802 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
06803
06804 int res;
06805 if (!vms->oldmessages && !vms->newmessages) {
06806 res = ast_play_and_wait(chan, "vm-nomessages");
06807 return res;
06808 }
06809 else {
06810 res = ast_play_and_wait(chan, "vm-youhave");
06811 }
06812 if (vms->newmessages) {
06813 if (!res)
06814 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06815 if ((vms->newmessages == 1)) {
06816 if (!res)
06817 res = ast_play_and_wait(chan, "vm-message");
06818 if (!res)
06819 res = ast_play_and_wait(chan, "vm-INBOXs");
06820 }
06821 else {
06822 if (!res)
06823 res = ast_play_and_wait(chan, "vm-messages");
06824 if (!res)
06825 res = ast_play_and_wait(chan, "vm-INBOX");
06826 }
06827 if (vms->oldmessages && !res)
06828 res = ast_play_and_wait(chan, "vm-and");
06829 }
06830 if (vms->oldmessages) {
06831 if (!res)
06832 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06833 if (vms->oldmessages == 1) {
06834 if (!res)
06835 res = ast_play_and_wait(chan, "vm-message");
06836 if (!res)
06837 res = ast_play_and_wait(chan, "vm-Olds");
06838 }
06839 else {
06840 if (!res)
06841 res = ast_play_and_wait(chan, "vm-messages");
06842 if (!res)
06843 res = ast_play_and_wait(chan, "vm-Old");
06844 }
06845 }
06846 return res;
06847 }
06848
06849
06850 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
06851 {
06852
06853 int res;
06854 res = ast_play_and_wait(chan, "vm-youhave");
06855 if (!res) {
06856 if (vms->newmessages) {
06857 res = say_and_wait(chan, vms->newmessages, chan->language);
06858 if (!res)
06859 res = ast_play_and_wait(chan, "vm-INBOX");
06860 if (vms->oldmessages && !res)
06861 res = ast_play_and_wait(chan, "vm-and");
06862 else if (!res) {
06863 if ((vms->newmessages == 1))
06864 res = ast_play_and_wait(chan, "vm-message");
06865 else
06866 res = ast_play_and_wait(chan, "vm-messages");
06867 }
06868
06869 }
06870 if (!res && vms->oldmessages) {
06871 res = say_and_wait(chan, vms->oldmessages, chan->language);
06872 if (!res)
06873 res = ast_play_and_wait(chan, "vm-Old");
06874 if (!res) {
06875 if (vms->oldmessages == 1)
06876 res = ast_play_and_wait(chan, "vm-message");
06877 else
06878 res = ast_play_and_wait(chan, "vm-messages");
06879 }
06880 }
06881 if (!res) {
06882 if (!vms->oldmessages && !vms->newmessages) {
06883 res = ast_play_and_wait(chan, "vm-no");
06884 if (!res)
06885 res = ast_play_and_wait(chan, "vm-messages");
06886 }
06887 }
06888 }
06889 return res;
06890 }
06891
06892
06893 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
06894 {
06895
06896 int res;
06897 res = ast_play_and_wait(chan, "vm-youhave");
06898 if (!res) {
06899 if (vms->newmessages) {
06900 res = say_and_wait(chan, vms->newmessages, chan->language);
06901 if (!res) {
06902 if (vms->newmessages == 1)
06903 res = ast_play_and_wait(chan, "vm-INBOXs");
06904 else
06905 res = ast_play_and_wait(chan, "vm-INBOX");
06906 }
06907 if (vms->oldmessages && !res)
06908 res = ast_play_and_wait(chan, "vm-and");
06909 else if (!res) {
06910 if ((vms->newmessages == 1))
06911 res = ast_play_and_wait(chan, "vm-message");
06912 else
06913 res = ast_play_and_wait(chan, "vm-messages");
06914 }
06915
06916 }
06917 if (!res && vms->oldmessages) {
06918 res = say_and_wait(chan, vms->oldmessages, chan->language);
06919 if (!res) {
06920 if (vms->oldmessages == 1)
06921 res = ast_play_and_wait(chan, "vm-Olds");
06922 else
06923 res = ast_play_and_wait(chan, "vm-Old");
06924 }
06925 if (!res) {
06926 if (vms->oldmessages == 1)
06927 res = ast_play_and_wait(chan, "vm-message");
06928 else
06929 res = ast_play_and_wait(chan, "vm-messages");
06930 }
06931 }
06932 if (!res) {
06933 if (!vms->oldmessages && !vms->newmessages) {
06934 res = ast_play_and_wait(chan, "vm-no");
06935 if (!res)
06936 res = ast_play_and_wait(chan, "vm-messages");
06937 }
06938 }
06939 }
06940 return res;
06941 }
06942
06943
06944 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
06945 {
06946
06947 int res;
06948 res = ast_play_and_wait(chan, "vm-youhave");
06949 if (!res) {
06950 if (vms->newmessages) {
06951 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06952 if (!res) {
06953 if ((vms->newmessages == 1)) {
06954 res = ast_play_and_wait(chan, "vm-message");
06955 if (!res)
06956 res = ast_play_and_wait(chan, "vm-INBOXs");
06957 } else {
06958 res = ast_play_and_wait(chan, "vm-messages");
06959 if (!res)
06960 res = ast_play_and_wait(chan, "vm-INBOX");
06961 }
06962 }
06963 if (vms->oldmessages && !res)
06964 res = ast_play_and_wait(chan, "vm-and");
06965 }
06966 if (!res && vms->oldmessages) {
06967 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06968 if (!res) {
06969 if (vms->oldmessages == 1) {
06970 res = ast_play_and_wait(chan, "vm-message");
06971 if (!res)
06972 res = ast_play_and_wait(chan, "vm-Olds");
06973 } else {
06974 res = ast_play_and_wait(chan, "vm-messages");
06975 if (!res)
06976 res = ast_play_and_wait(chan, "vm-Old");
06977 }
06978 }
06979 }
06980 if (!res) {
06981 if (!vms->oldmessages && !vms->newmessages) {
06982 res = ast_play_and_wait(chan, "vm-no");
06983 if (!res)
06984 res = ast_play_and_wait(chan, "vm-messages");
06985 }
06986 }
06987 }
06988 return res;
06989 }
06990
06991
06992
06993
06994
06995
06996
06997
06998
06999
07000
07001
07002
07003
07004
07005
07006
07007 static int vm_intro_cs(struct ast_channel *chan,struct vm_state *vms)
07008 {
07009 int res;
07010 res = ast_play_and_wait(chan, "vm-youhave");
07011 if (!res) {
07012 if (vms->newmessages) {
07013 if (vms->newmessages == 1) {
07014 res = ast_play_and_wait(chan, "digits/jednu");
07015 } else {
07016 res = say_and_wait(chan, vms->newmessages, chan->language);
07017 }
07018 if (!res) {
07019 if ((vms->newmessages == 1))
07020 res = ast_play_and_wait(chan, "vm-novou");
07021 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07022 res = ast_play_and_wait(chan, "vm-nove");
07023 if (vms->newmessages > 4)
07024 res = ast_play_and_wait(chan, "vm-novych");
07025 }
07026 if (vms->oldmessages && !res)
07027 res = ast_play_and_wait(chan, "vm-and");
07028 else if (!res) {
07029 if ((vms->newmessages == 1))
07030 res = ast_play_and_wait(chan, "vm-zpravu");
07031 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07032 res = ast_play_and_wait(chan, "vm-zpravy");
07033 if (vms->newmessages > 4)
07034 res = ast_play_and_wait(chan, "vm-zprav");
07035 }
07036 }
07037 if (!res && vms->oldmessages) {
07038 res = say_and_wait(chan, vms->oldmessages, chan->language);
07039 if (!res) {
07040 if ((vms->oldmessages == 1))
07041 res = ast_play_and_wait(chan, "vm-starou");
07042 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07043 res = ast_play_and_wait(chan, "vm-stare");
07044 if (vms->oldmessages > 4)
07045 res = ast_play_and_wait(chan, "vm-starych");
07046 }
07047 if (!res) {
07048 if ((vms->oldmessages == 1))
07049 res = ast_play_and_wait(chan, "vm-zpravu");
07050 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07051 res = ast_play_and_wait(chan, "vm-zpravy");
07052 if (vms->oldmessages > 4)
07053 res = ast_play_and_wait(chan, "vm-zprav");
07054 }
07055 }
07056 if (!res) {
07057 if (!vms->oldmessages && !vms->newmessages) {
07058 res = ast_play_and_wait(chan, "vm-no");
07059 if (!res)
07060 res = ast_play_and_wait(chan, "vm-zpravy");
07061 }
07062 }
07063 }
07064 return res;
07065 }
07066
07067 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07068 {
07069 char prefile[256];
07070
07071
07072 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07073 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
07074 RETRIEVE(prefile, -1, vmu);
07075 if (ast_fileexists(prefile, NULL, NULL) > 0)
07076 ast_play_and_wait(chan, "vm-tempgreetactive");
07077 DISPOSE(prefile, -1);
07078 }
07079
07080
07081 if (0) {
07082 return 0;
07083 } else if (!strncasecmp(chan->language, "cs", 2)) {
07084 return vm_intro_cs(chan, vms);
07085 } else if (!strncasecmp(chan->language, "cz", 2)) {
07086 static int deprecation_warning = 0;
07087 if (deprecation_warning++ % 10 == 0) {
07088 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
07089 }
07090 return vm_intro_cs(chan, vms);
07091 } else if (!strncasecmp(chan->language, "de", 2)) {
07092 return vm_intro_de(chan, vms);
07093 } else if (!strncasecmp(chan->language, "es", 2)) {
07094 return vm_intro_es(chan, vms);
07095 } else if (!strncasecmp(chan->language, "fr", 2)) {
07096 return vm_intro_fr(chan, vms);
07097 } else if (!strncasecmp(chan->language, "gr", 2)) {
07098 return vm_intro_gr(chan, vms);
07099 } else if (!strncasecmp(chan->language, "he", 2)) {
07100 return vm_intro_he(chan, vms);
07101 } else if (!strncasecmp(chan->language, "it", 2)) {
07102 return vm_intro_it(chan, vms);
07103 } else if (!strncasecmp(chan->language, "nl", 2)) {
07104 return vm_intro_nl(chan, vms);
07105 } else if (!strncasecmp(chan->language, "no", 2)) {
07106 return vm_intro_no(chan, vms);
07107 } else if (!strncasecmp(chan->language, "pl", 2)) {
07108 return vm_intro_pl(chan, vms);
07109 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07110 return vm_intro_pt_BR(chan, vms);
07111 } else if (!strncasecmp(chan->language, "pt", 2)) {
07112 return vm_intro_pt(chan, vms);
07113 } else if (!strncasecmp(chan->language, "ru", 2)) {
07114 return vm_intro_multilang(chan, vms, "n");
07115 } else if (!strncasecmp(chan->language, "se", 2)) {
07116 return vm_intro_se(chan, vms);
07117 } else if (!strncasecmp(chan->language, "ua", 2)) {
07118 return vm_intro_multilang(chan, vms, "n");
07119 } else {
07120 return vm_intro_en(chan, vms);
07121 }
07122 }
07123
07124 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07125 {
07126 int res = 0;
07127
07128 while (!res) {
07129 if (vms->starting) {
07130 if (vms->lastmsg > -1) {
07131 res = ast_play_and_wait(chan, "vm-onefor");
07132 if (!strncasecmp(chan->language, "he", 2)) {
07133 res = ast_play_and_wait(chan, "vm-for");
07134 }
07135 if (!res)
07136 res = vm_play_folder_name(chan, vms->vmbox);
07137 }
07138 if (!res)
07139 res = ast_play_and_wait(chan, "vm-opts");
07140 } else {
07141 if (vms->curmsg)
07142 res = ast_play_and_wait(chan, "vm-prev");
07143 if (!res && !skipadvanced)
07144 res = ast_play_and_wait(chan, "vm-advopts");
07145 if (!res)
07146 res = ast_play_and_wait(chan, "vm-repeat");
07147 if (!res && (vms->curmsg != vms->lastmsg))
07148 res = ast_play_and_wait(chan, "vm-next");
07149 if (!res) {
07150 if (!vms->deleted[vms->curmsg])
07151 res = ast_play_and_wait(chan, "vm-delete");
07152 else
07153 res = ast_play_and_wait(chan, "vm-undelete");
07154 if (!res)
07155 res = ast_play_and_wait(chan, "vm-toforward");
07156 if (!res)
07157 res = ast_play_and_wait(chan, "vm-savemessage");
07158 }
07159 }
07160 if (!res)
07161 res = ast_play_and_wait(chan, "vm-helpexit");
07162 if (!res)
07163 res = ast_waitfordigit(chan, 6000);
07164 if (!res) {
07165 vms->repeats++;
07166 if (vms->repeats > 2) {
07167 res = 't';
07168 }
07169 }
07170 }
07171 return res;
07172 }
07173
07174 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07175 {
07176 int cmd = 0;
07177 int duration = 0;
07178 int tries = 0;
07179 char newpassword[80] = "";
07180 char newpassword2[80] = "";
07181 char prefile[PATH_MAX] = "";
07182 unsigned char buf[256];
07183 int bytes=0;
07184
07185 if (ast_adsi_available(chan)) {
07186 bytes += adsi_logo(buf + bytes);
07187 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
07188 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07189 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07190 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07191 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07192 }
07193
07194
07195
07196 for (;;) {
07197 newpassword[1] = '\0';
07198 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07199 if (cmd == '#')
07200 newpassword[0] = '\0';
07201 if (cmd < 0 || cmd == 't' || cmd == '#')
07202 return cmd;
07203 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
07204 if (cmd < 0 || cmd == 't' || cmd == '#')
07205 return cmd;
07206 newpassword2[1] = '\0';
07207 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07208 if (cmd == '#')
07209 newpassword2[0] = '\0';
07210 if (cmd < 0 || cmd == 't' || cmd == '#')
07211 return cmd;
07212 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
07213 if (cmd < 0 || cmd == 't' || cmd == '#')
07214 return cmd;
07215 if (!strcmp(newpassword, newpassword2))
07216 break;
07217 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07218 cmd = ast_play_and_wait(chan, "vm-mismatch");
07219 if (++tries == 3)
07220 return -1;
07221 if (cmd == 0) {
07222 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07223 }
07224 }
07225 if (ast_strlen_zero(ext_pass_cmd))
07226 vm_change_password(vmu,newpassword);
07227 else
07228 vm_change_password_shell(vmu,newpassword);
07229 if (option_debug > 2)
07230 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07231 cmd = ast_play_and_wait(chan,"vm-passchanged");
07232
07233
07234 if (ast_test_flag(vmu, VM_FORCENAME)) {
07235 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07236 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07237 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07238 if (cmd < 0 || cmd == 't' || cmd == '#')
07239 return cmd;
07240 }
07241 }
07242
07243
07244 if (ast_test_flag(vmu, VM_FORCEGREET)) {
07245 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07246 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07247 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07248 if (cmd < 0 || cmd == 't' || cmd == '#')
07249 return cmd;
07250 }
07251
07252 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07253 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07254 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07255 if (cmd < 0 || cmd == 't' || cmd == '#')
07256 return cmd;
07257 }
07258 }
07259
07260 return cmd;
07261 }
07262
07263 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07264 {
07265 int cmd = 0;
07266 int retries = 0;
07267 int duration = 0;
07268 char newpassword[80] = "";
07269 char newpassword2[80] = "";
07270 char prefile[PATH_MAX] = "";
07271 unsigned char buf[256];
07272 int bytes=0;
07273
07274 if (ast_adsi_available(chan))
07275 {
07276 bytes += adsi_logo(buf + bytes);
07277 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
07278 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07279 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07280 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07281 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07282 }
07283 while ((cmd >= 0) && (cmd != 't')) {
07284 if (cmd)
07285 retries = 0;
07286 switch (cmd) {
07287 case '1':
07288 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07289 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07290 break;
07291 case '2':
07292 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07293 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07294 break;
07295 case '3':
07296 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07297 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07298 break;
07299 case '4':
07300 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
07301 break;
07302 case '5':
07303 if (vmu->password[0] == '-') {
07304 cmd = ast_play_and_wait(chan, "vm-no");
07305 break;
07306 }
07307 newpassword[1] = '\0';
07308 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
07309 if (cmd == '#')
07310 newpassword[0] = '\0';
07311 else {
07312 if (cmd < 0)
07313 break;
07314 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
07315 break;
07316 }
07317 }
07318 newpassword2[1] = '\0';
07319 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
07320 if (cmd == '#')
07321 newpassword2[0] = '\0';
07322 else {
07323 if (cmd < 0)
07324 break;
07325
07326 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
07327 break;
07328 }
07329 }
07330 if (strcmp(newpassword, newpassword2)) {
07331 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07332 cmd = ast_play_and_wait(chan, "vm-mismatch");
07333 if (!cmd) {
07334 cmd = ast_play_and_wait(chan, "vm-pls-try-again");
07335 }
07336 break;
07337 }
07338 if (ast_strlen_zero(ext_pass_cmd))
07339 vm_change_password(vmu,newpassword);
07340 else
07341 vm_change_password_shell(vmu,newpassword);
07342 if (option_debug > 2)
07343 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
07344 cmd = ast_play_and_wait(chan,"vm-passchanged");
07345 break;
07346 case '*':
07347 cmd = 't';
07348 break;
07349 default:
07350 cmd = 0;
07351 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07352 RETRIEVE(prefile, -1, vmu);
07353 if (ast_fileexists(prefile, NULL, NULL))
07354 cmd = ast_play_and_wait(chan, "vm-tmpexists");
07355 DISPOSE(prefile, -1);
07356 if (!cmd)
07357 cmd = ast_play_and_wait(chan, "vm-options");
07358 if (!cmd)
07359 cmd = ast_waitfordigit(chan,6000);
07360 if (!cmd)
07361 retries++;
07362 if (retries > 3)
07363 cmd = 't';
07364 }
07365 }
07366 if (cmd == 't')
07367 cmd = 0;
07368 return cmd;
07369 }
07370
07371 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07372 {
07373 int res;
07374 int cmd = 0;
07375 int retries = 0;
07376 int duration = 0;
07377 char prefile[PATH_MAX] = "";
07378 unsigned char buf[256];
07379 char dest[PATH_MAX];
07380 int bytes = 0;
07381
07382 if (ast_adsi_available(chan)) {
07383 bytes += adsi_logo(buf + bytes);
07384 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
07385 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07386 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07387 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07388 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07389 }
07390
07391 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07392 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
07393 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
07394 return -1;
07395 }
07396 while ((cmd >= 0) && (cmd != 't')) {
07397 if (cmd)
07398 retries = 0;
07399 RETRIEVE(prefile, -1, vmu);
07400 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
07401 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07402 cmd = 't';
07403 } else {
07404 switch (cmd) {
07405 case '1':
07406 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07407 break;
07408 case '2':
07409 DELETE(prefile, -1, prefile, vmu);
07410 ast_play_and_wait(chan, "vm-tempremoved"