app_voicemail.c 137 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Voicemail System (did you ever think it could be so easy?)
  5. *
  6. * Copyright (C) 2003-2004, Digium Inc.
  7. *
  8. * Mark Spencer <markster@digium.com>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <asterisk/lock.h>
  14. #include <asterisk/file.h>
  15. #include <asterisk/logger.h>
  16. #include <asterisk/channel.h>
  17. #include <asterisk/channel_pvt.h>
  18. #include <asterisk/pbx.h>
  19. #include <asterisk/options.h>
  20. #include <asterisk/config.h>
  21. #include <asterisk/say.h>
  22. #include <asterisk/module.h>
  23. #include <asterisk/adsi.h>
  24. #include <asterisk/app.h>
  25. #include <asterisk/manager.h>
  26. #include <asterisk/dsp.h>
  27. #include <asterisk/localtime.h>
  28. #include <asterisk/cli.h>
  29. #include <asterisk/utils.h>
  30. #include <stdlib.h>
  31. #include <errno.h>
  32. #include <unistd.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <sys/time.h>
  37. #include <sys/stat.h>
  38. #include <sys/types.h>
  39. #include <time.h>
  40. #include <dirent.h>
  41. /* we define USESQLVM when we have MySQL or POSTGRES */
  42. #ifdef USEMYSQLVM
  43. #include <mysql/mysql.h>
  44. #define USESQLVM 1
  45. #endif
  46. #ifdef USEPOSTGRESVM
  47. /*
  48. * PostgreSQL routines written by Otmar Lendl <lendl@nic.at>
  49. */
  50. #include <postgresql/libpq-fe.h>
  51. #define USESQLVM 1
  52. #endif
  53. #ifndef USESQLVM
  54. static inline int sql_init(void) { return 0; }
  55. static inline void sql_close(void) { }
  56. #endif
  57. #include "../asterisk.h"
  58. #include "../astconf.h"
  59. #define COMMAND_TIMEOUT 5000
  60. #define VOICEMAIL_CONFIG "voicemail.conf"
  61. #define ASTERISK_USERNAME "asterisk"
  62. /* Default mail command to mail voicemail. Change it with the
  63. mailcmd= command in voicemail.conf */
  64. #define SENDMAIL "/usr/sbin/sendmail -t"
  65. #define INTRO "vm-intro"
  66. #define MAXMSG 100
  67. #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm"
  68. #define BASEMAXINLINE 256
  69. #define BASELINELEN 72
  70. #define BASEMAXINLINE 256
  71. #define eol "\r\n"
  72. #define MAX_DATETIME_FORMAT 512
  73. #define MAX_NUM_CID_CONTEXTS 10
  74. static int load_config(void);
  75. /* Syntaxes supported, not really language codes.
  76. en - English
  77. de - German
  78. es - Spanish
  79. fr - French
  80. nl - Dutch
  81. pt - Portuguese
  82. German requires the following additional soundfile:
  83. 1F einE (feminine)
  84. Spanish requires the following additional soundfile:
  85. 1M un (masculine)
  86. Dutch, Portuguese & Spanish require the following additional soundfiles:
  87. vm-INBOXs singular of 'new'
  88. vm-Olds singular of 'old/heard/read'
  89. NB these are plural:
  90. vm-INBOX nieuwe (nl)
  91. vm-Old oude (nl)
  92. Dutch also uses:
  93. nl-om 'at'?
  94. Spanish also uses:
  95. vm-youhaveno
  96. */
  97. struct baseio {
  98. int iocp;
  99. int iolen;
  100. int linelength;
  101. int ateof;
  102. unsigned char iobuf[BASEMAXINLINE];
  103. };
  104. /* Structure for linked list of users */
  105. struct ast_vm_user {
  106. char context[80]; /* Voicemail context */
  107. char mailbox[80]; /* Mailbox id, unique within vm context */
  108. char password[80]; /* Secret pin code, numbers only */
  109. char fullname[80]; /* Full name, for directory app */
  110. char email[80]; /* E-mail address */
  111. char pager[80]; /* E-mail address to pager (no attachment) */
  112. char serveremail[80]; /* From: Mail address */
  113. char mailcmd[160]; /* Configurable mail command */
  114. char language[MAX_LANGUAGE]; /* Config: Language setting */
  115. char zonetag[80]; /* Time zone */
  116. char callback[80];
  117. char dialout[80];
  118. char exit[80];
  119. int attach;
  120. int delete;
  121. int alloced;
  122. int saycid;
  123. int svmail;
  124. int review;
  125. int operator;
  126. int envelope;
  127. struct ast_vm_user *next;
  128. };
  129. struct vm_zone {
  130. char name[80];
  131. char timezone[80];
  132. char msg_format[512];
  133. struct vm_zone *next;
  134. };
  135. struct vm_state {
  136. char curbox[80];
  137. char username[80];
  138. char curdir[256];
  139. char vmbox[256];
  140. char fn[256];
  141. char fn2[256];
  142. int deleted[MAXMSG];
  143. int heard[MAXMSG];
  144. int curmsg;
  145. int lastmsg;
  146. int newmessages;
  147. int oldmessages;
  148. int starting;
  149. int repeats;
  150. };
  151. static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
  152. static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
  153. static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir);
  154. static int vm_delete(char *file);
  155. static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
  156. static char ext_pass_cmd[128];
  157. static char *tdesc = "Comedian Mail (Voicemail System)";
  158. static char *addesc = "Comedian Mail";
  159. static char *synopsis_vm =
  160. "Leave a voicemail message";
  161. static char *descrip_vm =
  162. " VoiceMail([s|u|b]extension[@context][&extension[@context]][...]): Leaves"
  163. "voicemail for a given extension (must be configured in voicemail.conf).\n"
  164. " If the extension is preceded by \n"
  165. "* 's' then instructions for leaving the message will be skipped.\n"
  166. "* 'u' then the \"unavailable\" message will be played.\n"
  167. " (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.\n"
  168. "* 'b' then the the busy message will be played (that is, busy instead of unavail).\n"
  169. "If the caller presses '0' (zero) during the prompt, the call jumps to\n"
  170. "extension 'o' in the current context.\n"
  171. "If the caller presses '*' during the prompt, the call jumps to\n"
  172. "extension 'a' in the current context.\n"
  173. "If the requested mailbox does not exist, and there exists a priority\n"
  174. "n + 101, then that priority will be taken next.\n"
  175. "When multiple mailboxes are specified, the unavailable or busy message\n"
  176. "will be taken from the first mailbox specified.\n"
  177. "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
  178. "Otherwise, it returns 0.\n";
  179. static char *synopsis_vmain =
  180. "Enter voicemail system";
  181. static char *descrip_vmain =
  182. " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
  183. "for the checking of voicemail. The mailbox can be passed as the option,\n"
  184. "which will stop the voicemail system from prompting the user for the mailbox.\n"
  185. "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
  186. "the mailbox is preceded by 'p' then the supplied mailbox is prepended to the\n"
  187. "user's entry and the resulting string is used as the mailbox number. This is\n"
  188. "useful for virtual hosting of voicemail boxes. If a context is specified,\n"
  189. "logins are considered in that voicemail context only.\n"
  190. "Returns -1 if the user hangs up or 0 otherwise.\n";
  191. static char *synopsis_vm_box_exists =
  192. "Check if vmbox exists";
  193. static char *descrip_vm_box_exists =
  194. " MailboxExists(mailbox[@context]): Conditionally branches to priority n+101\n"
  195. "if the specified voice mailbox exists.\n";
  196. /* Leave a message */
  197. static char *capp = "VoiceMail2";
  198. static char *app = "VoiceMail";
  199. /* Check mail, control, etc */
  200. static char *capp2 = "VoiceMailMain2";
  201. static char *app2 = "VoiceMailMain";
  202. static char *app3 = "MailboxExists";
  203. AST_MUTEX_DEFINE_STATIC(vmlock);
  204. struct ast_vm_user *users;
  205. struct ast_vm_user *usersl;
  206. struct vm_zone *zones = NULL;
  207. struct vm_zone *zonesl = NULL;
  208. static int attach_voicemail;
  209. static int maxsilence;
  210. static int silencethreshold = 128;
  211. static char serveremail[80];
  212. static char mailcmd[160]; /* Configurable mail cmd */
  213. static char externnotify[160];
  214. static char vmfmts[80];
  215. static int vmminmessage;
  216. static int vmmaxmessage;
  217. static int maxgreet;
  218. static int skipms;
  219. static int maxlogins;
  220. static int reviewvm;
  221. static int calloper;
  222. static int saycidinfo;
  223. static int svmailinfo;
  224. static int hearenv;
  225. static int skipaftercmd;
  226. static char dialcontext[80];
  227. static char callcontext[80];
  228. static char exitcontext[80];
  229. static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
  230. static char *emailbody = NULL;
  231. static int pbxskip = 0;
  232. static char *emailsubject = NULL;
  233. static char fromstring[100];
  234. static char pagerfromstring[100];
  235. static char emailtitle[100];
  236. static char charset[32] = "ISO-8859-1";
  237. static char adsifdn[4] = "\x00\x00\x00\x0F";
  238. static char adsisec[4] = "\x9B\xDB\xF7\xAC";
  239. static int adsiver = 1;
  240. STANDARD_LOCAL_USER;
  241. LOCAL_USER_DECL;
  242. static void populate_defaults(struct ast_vm_user *vmu)
  243. {
  244. vmu->attach = -1;
  245. if (reviewvm)
  246. vmu->review = 1;
  247. if (calloper)
  248. vmu->operator = 1;
  249. if (saycidinfo)
  250. vmu->saycid = 1;
  251. if (svmailinfo)
  252. vmu->svmail = 1;
  253. if (hearenv)
  254. vmu->envelope = 1;
  255. if (callcontext)
  256. strncpy(vmu->callback, callcontext, sizeof(vmu->callback) -1);
  257. if (dialcontext)
  258. strncpy(vmu->dialout, dialcontext, sizeof(vmu->dialout) -1);
  259. if (exitcontext)
  260. strncpy(vmu->exit, exitcontext, sizeof(vmu->exit) -1);
  261. }
  262. static void apply_options(struct ast_vm_user *vmu, char *options)
  263. {
  264. /* Destructively Parse options and apply */
  265. char *stringp = ast_strdupa(options);
  266. char *s;
  267. char *var, *value;
  268. while((s = strsep(&stringp, "|"))) {
  269. value = s;
  270. if ((var = strsep(&value, "=")) && value) {
  271. if (!strcasecmp(var, "attach")) {
  272. if (ast_true(value))
  273. vmu->attach = 1;
  274. else
  275. vmu->attach = 0;
  276. } else if (!strcasecmp(var, "serveremail")) {
  277. strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
  278. } else if (!strcasecmp(var, "language")) {
  279. strncpy(vmu->language, value, sizeof(vmu->language) - 1);
  280. } else if (!strcasecmp(var, "tz")) {
  281. strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
  282. } else if (!strcasecmp(var, "delete")) {
  283. vmu->delete = ast_true(value);
  284. } else if (!strcasecmp(var, "saycid")){
  285. if(ast_true(value))
  286. vmu->saycid = 1;
  287. else
  288. vmu->saycid = 0;
  289. } else if (!strcasecmp(var,"sendvoicemail")){
  290. if(ast_true(value))
  291. vmu->svmail =1;
  292. else
  293. vmu->svmail =0;
  294. } else if (!strcasecmp(var, "review")){
  295. if(ast_true(value))
  296. vmu->review = 1;
  297. else
  298. vmu->review = 0;
  299. } else if (!strcasecmp(var, "operator")){
  300. if(ast_true(value))
  301. vmu->operator = 1;
  302. else
  303. vmu->operator = 0;
  304. } else if (!strcasecmp(var, "envelope")){
  305. if(ast_true(value))
  306. vmu->envelope = 1;
  307. else
  308. vmu->envelope = 0;
  309. } else if (!strcasecmp(var, "callback")) {
  310. strncpy(vmu->callback, value, sizeof(vmu->callback) -1);
  311. } else if (!strcasecmp(var, "dialout")) {
  312. strncpy(vmu->dialout, value, sizeof(vmu->dialout) -1);
  313. } else if (!strcasecmp(var, "exitcontext")) {
  314. strncpy(vmu->exit, value, sizeof(vmu->exit) -1);
  315. }
  316. }
  317. }
  318. }
  319. #ifdef USEMYSQLVM
  320. #include "mysql-vm-routines.h"
  321. #endif
  322. #ifdef USEPOSTGRESVM
  323. PGconn *dbhandler;
  324. char dboption[256] = "";
  325. AST_MUTEX_DEFINE_STATIC(postgreslock);
  326. static int sql_init(void)
  327. {
  328. ast_verbose( VERBOSE_PREFIX_3 "Logging into postgres database: %s\n", dboption);
  329. /* fprintf(stderr,"Logging into postgres database: %s\n", dboption); */
  330. dbhandler=PQconnectdb(dboption);
  331. if (PQstatus(dbhandler) == CONNECTION_BAD) {
  332. ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler));
  333. return(-1);
  334. }
  335. /* fprintf(stderr,"postgres login OK\n"); */
  336. return(0);
  337. }
  338. static void sql_close(void)
  339. {
  340. PQfinish(dbhandler);
  341. }
  342. static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
  343. {
  344. PGresult *PGSQLres;
  345. int numFields, i;
  346. char *fname;
  347. char query[240];
  348. char options[160] = "";
  349. struct ast_vm_user *retval;
  350. retval=malloc(sizeof(struct ast_vm_user));
  351. /* fprintf(stderr,"postgres find_user:\n"); */
  352. if (retval) {
  353. memset(retval, 0, sizeof(struct ast_vm_user));
  354. retval->alloced=1;
  355. if (mailbox) {
  356. strncpy(retval->mailbox, mailbox, sizeof(retval->mailbox) - 1);
  357. }
  358. if (context) {
  359. strncpy(retval->context, context, sizeof(retval->context) - 1);
  360. }
  361. else
  362. {
  363. strncpy(retval->context, "default", sizeof(retval->context) - 1);
  364. }
  365. populate_defaults(retval);
  366. snprintf(query, sizeof(query), "SELECT password,fullname,email,pager,options FROM voicemail WHERE context='%s' AND mailbox='%s'", retval->context, mailbox);
  367. /* fprintf(stderr,"postgres find_user: query = %s\n",query); */
  368. ast_mutex_lock(&postgreslock);
  369. PGSQLres=PQexec(dbhandler,query);
  370. if (PGSQLres!=NULL) {
  371. if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
  372. PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
  373. PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
  374. ast_log(LOG_WARNING,"PGSQL_query: Query Error (%s) Calling PQreset\n",PQcmdStatus(PGSQLres));
  375. PQclear(PGSQLres);
  376. PQreset(dbhandler);
  377. ast_mutex_unlock(&postgreslock);
  378. free(retval);
  379. return(NULL);
  380. } else {
  381. numFields = PQnfields(PGSQLres);
  382. /* fprintf(stderr,"postgres find_user: query found %d rows with %d fields\n",PQntuples(PGSQLres), numFields); */
  383. if (PQntuples(PGSQLres) != 1) {
  384. ast_log(LOG_WARNING,"PGSQL_query: Did not find a unique mailbox for %s\n",mailbox);
  385. PQclear(PGSQLres);
  386. ast_mutex_unlock(&postgreslock);
  387. free(retval);
  388. return(NULL);
  389. }
  390. for (i=0; i<numFields; i++) {
  391. fname = PQfname(PGSQLres,i);
  392. if (!strcmp(fname, "password") && !PQgetisnull (PGSQLres,0,i)) {
  393. strncpy(retval->password, PQgetvalue(PGSQLres,0,i),sizeof(retval->password) - 1);
  394. } else if (!strcmp(fname, "fullname")) {
  395. strncpy(retval->fullname, PQgetvalue(PGSQLres,0,i),sizeof(retval->fullname) - 1);
  396. } else if (!strcmp(fname, "email")) {
  397. strncpy(retval->email, PQgetvalue(PGSQLres,0,i),sizeof(retval->email) - 1);
  398. } else if (!strcmp(fname, "pager")) {
  399. strncpy(retval->pager, PQgetvalue(PGSQLres,0,i),sizeof(retval->pager) - 1);
  400. } else if (!strcmp(fname, "options")) {
  401. strncpy(options, PQgetvalue(PGSQLres,0,i), sizeof(options) - 1);
  402. apply_options(retval, options);
  403. }
  404. }
  405. }
  406. PQclear(PGSQLres);
  407. ast_mutex_unlock(&postgreslock);
  408. return(retval);
  409. }
  410. else {
  411. ast_log(LOG_WARNING,"PGSQL_query: Connection Error (%s)\n",PQerrorMessage(dbhandler));
  412. ast_mutex_unlock(&postgreslock);
  413. free(retval);
  414. return(NULL);
  415. }
  416. /* not reached */
  417. } /* malloc() retval */
  418. return(NULL);
  419. }
  420. static void vm_change_password(struct ast_vm_user *vmu, char *password)
  421. {
  422. char query[400];
  423. if (*vmu->context) {
  424. snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->context, vmu->mailbox, vmu->password);
  425. } else {
  426. snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s' AND (password='%s' OR password IS NULL)", password, vmu->mailbox, vmu->password);
  427. }
  428. /* fprintf(stderr,"postgres change_password: query = %s\n",query); */
  429. ast_mutex_lock(&postgreslock);
  430. PQexec(dbhandler, query);
  431. strncpy(vmu->password, password, sizeof(vmu->password) - 1);
  432. ast_mutex_unlock(&postgreslock);
  433. }
  434. static void reset_user_pw(char *context, char *mailbox, char *password)
  435. {
  436. char query[320];
  437. if (context) {
  438. snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE context='%s' AND mailbox='%s'", password, context, mailbox);
  439. } else {
  440. snprintf(query, sizeof(query), "UPDATE voicemail SET password='%s' WHERE mailbox='%s'", password, mailbox);
  441. }
  442. ast_mutex_lock(&postgreslock);
  443. /* fprintf(stderr,"postgres reset_user_pw: query = %s\n",query); */
  444. PQexec(dbhandler, query);
  445. ast_mutex_unlock(&postgreslock);
  446. }
  447. #endif /* Postgres */
  448. #ifndef USESQLVM
  449. static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, char *mailbox)
  450. {
  451. /* This function could be made to generate one from a database, too */
  452. struct ast_vm_user *vmu=NULL, *cur;
  453. ast_mutex_lock(&vmlock);
  454. cur = users;
  455. while(cur) {
  456. if ((!context || !strcasecmp(context, cur->context)) &&
  457. (!strcasecmp(mailbox, cur->mailbox)))
  458. break;
  459. cur=cur->next;
  460. }
  461. if (cur) {
  462. if (ivm)
  463. vmu = ivm;
  464. else
  465. /* Make a copy, so that on a reload, we have no race */
  466. vmu = malloc(sizeof(struct ast_vm_user));
  467. if (vmu) {
  468. memcpy(vmu, cur, sizeof(struct ast_vm_user));
  469. if (ivm)
  470. vmu->alloced = 0;
  471. else
  472. vmu->alloced = 1;
  473. vmu->next = NULL;
  474. }
  475. }
  476. ast_mutex_unlock(&vmlock);
  477. return vmu;
  478. }
  479. static int reset_user_pw(char *context, char *mailbox, char *newpass)
  480. {
  481. /* This function could be made to generate one from a database, too */
  482. struct ast_vm_user *cur;
  483. int res = -1;
  484. ast_mutex_lock(&vmlock);
  485. cur = users;
  486. while(cur) {
  487. if ((!context || !strcasecmp(context, cur->context)) &&
  488. (!strcasecmp(mailbox, cur->mailbox)))
  489. break;
  490. cur=cur->next;
  491. }
  492. if (cur) {
  493. strncpy(cur->password, newpass, sizeof(cur->password) - 1);
  494. res = 0;
  495. }
  496. ast_mutex_unlock(&vmlock);
  497. return res;
  498. }
  499. static void vm_change_password(struct ast_vm_user *vmu, char *newpassword)
  500. {
  501. /* There's probably a better way of doing this. */
  502. /* That's why I've put the password change in a separate function. */
  503. /* This could also be done with a database function */
  504. FILE *configin;
  505. FILE *configout;
  506. int linenum=0;
  507. char inbuf[256];
  508. char orig[256];
  509. char currcontext[256] ="";
  510. char tmpin[AST_CONFIG_MAX_PATH];
  511. char tmpout[AST_CONFIG_MAX_PATH];
  512. char *user, *pass, *rest, *trim, *tempcontext;
  513. struct stat statbuf;
  514. tempcontext = NULL;
  515. snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR);
  516. snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR);
  517. configin = fopen(tmpin,"r");
  518. if (configin)
  519. configout = fopen(tmpout,"w+");
  520. else
  521. configout = NULL;
  522. if(!configin || !configout) {
  523. if (configin)
  524. fclose(configin);
  525. else
  526. ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
  527. if (configout)
  528. fclose(configout);
  529. else
  530. ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
  531. return;
  532. }
  533. while (!feof(configin)) {
  534. /* Read in the line */
  535. fgets(inbuf, sizeof(inbuf), configin);
  536. linenum++;
  537. if (!feof(configin)) {
  538. /* Make a backup of it */
  539. memcpy(orig, inbuf, sizeof(orig));
  540. /* Strip trailing \n and comment */
  541. inbuf[strlen(inbuf) - 1] = '\0';
  542. user = strchr(inbuf, ';');
  543. if (user)
  544. *user = '\0';
  545. user=inbuf;
  546. while(*user < 33)
  547. user++;
  548. /* check for '[' (opening of context name ) */
  549. tempcontext = strchr(user, '[');
  550. if (tempcontext) {
  551. strncpy(currcontext, tempcontext +1,
  552. sizeof(currcontext) - 1);
  553. /* now check for ']' */
  554. tempcontext = strchr(currcontext, ']');
  555. if (tempcontext)
  556. *tempcontext = '\0';
  557. else
  558. currcontext[0] = '\0';
  559. }
  560. pass = strchr(user, '=');
  561. if (pass > user) {
  562. trim = pass - 1;
  563. while(*trim && *trim < 33) {
  564. *trim = '\0';
  565. trim--;
  566. }
  567. }
  568. if (pass) {
  569. *pass = '\0';
  570. pass++;
  571. if (*pass == '>')
  572. pass++;
  573. while(*pass && *pass < 33)
  574. pass++;
  575. }
  576. if (pass) {
  577. rest = strchr(pass,',');
  578. if (rest) {
  579. *rest = '\0';
  580. rest++;
  581. }
  582. } else
  583. rest = NULL;
  584. /* Compare user, pass AND context */
  585. if (user && *user && !strcmp(user, vmu->mailbox) &&
  586. pass && !strcmp(pass, vmu->password) &&
  587. currcontext && *currcontext && !strcmp(currcontext, vmu->context)) {
  588. /* This is the line */
  589. if (rest) {
  590. fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
  591. } else {
  592. fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
  593. }
  594. } else {
  595. /* Put it back like it was */
  596. fprintf(configout, "%s", orig);
  597. }
  598. }
  599. }
  600. fclose(configin);
  601. fclose(configout);
  602. stat((char *)tmpin, &statbuf);
  603. chmod((char *)tmpout, statbuf.st_mode);
  604. chown((char *)tmpout, statbuf.st_uid, statbuf.st_gid);
  605. unlink((char *)tmpin);
  606. rename((char *)tmpout,(char *)tmpin);
  607. reset_user_pw(vmu->context, vmu->mailbox, newpassword);
  608. strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
  609. }
  610. #endif
  611. static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
  612. {
  613. char buf[255];
  614. snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
  615. if (!ast_safe_system(buf))
  616. strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
  617. }
  618. static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
  619. {
  620. return snprintf(dest, len, "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR,context, ext, mailbox);
  621. }
  622. static int make_file(char *dest, int len, char *dir, int num)
  623. {
  624. return snprintf(dest, len, "%s/msg%04d", dir, num);
  625. }
  626. static int last_message_index(char *dir)
  627. {
  628. int x;
  629. char fn[256];
  630. ast_lock_path(dir);
  631. for (x=0;x<MAXMSG;x++) {
  632. make_file(fn, sizeof(fn), dir, x);
  633. if (ast_fileexists(fn, NULL, NULL) < 1)
  634. break;
  635. }
  636. ast_unlock_path(dir);
  637. return x-1;
  638. }
  639. static int
  640. inbuf(struct baseio *bio, FILE *fi)
  641. {
  642. int l;
  643. if(bio->ateof)
  644. return 0;
  645. if ( (l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
  646. if(ferror(fi))
  647. return -1;
  648. bio->ateof = 1;
  649. return 0;
  650. }
  651. bio->iolen= l;
  652. bio->iocp= 0;
  653. return 1;
  654. }
  655. static int
  656. inchar(struct baseio *bio, FILE *fi)
  657. {
  658. if(bio->iocp>=bio->iolen)
  659. if(!inbuf(bio, fi))
  660. return EOF;
  661. return bio->iobuf[bio->iocp++];
  662. }
  663. static int
  664. ochar(struct baseio *bio, int c, FILE *so)
  665. {
  666. if(bio->linelength>=BASELINELEN) {
  667. if(fputs(eol,so)==EOF)
  668. return -1;
  669. bio->linelength= 0;
  670. }
  671. if(putc(((unsigned char)c),so)==EOF)
  672. return -1;
  673. bio->linelength++;
  674. return 1;
  675. }
  676. static int base_encode(char *filename, FILE *so)
  677. {
  678. unsigned char dtable[BASEMAXINLINE];
  679. int i,hiteof= 0;
  680. FILE *fi;
  681. struct baseio bio;
  682. memset(&bio, 0, sizeof(bio));
  683. bio.iocp = BASEMAXINLINE;
  684. if ( !(fi = fopen(filename, "rb"))) {
  685. ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
  686. return -1;
  687. }
  688. for(i= 0;i<9;i++){
  689. dtable[i]= 'A'+i;
  690. dtable[i+9]= 'J'+i;
  691. dtable[26+i]= 'a'+i;
  692. dtable[26+i+9]= 'j'+i;
  693. }
  694. for(i= 0;i<8;i++){
  695. dtable[i+18]= 'S'+i;
  696. dtable[26+i+18]= 's'+i;
  697. }
  698. for(i= 0;i<10;i++){
  699. dtable[52+i]= '0'+i;
  700. }
  701. dtable[62]= '+';
  702. dtable[63]= '/';
  703. while(!hiteof){
  704. unsigned char igroup[3],ogroup[4];
  705. int c,n;
  706. igroup[0]= igroup[1]= igroup[2]= 0;
  707. for(n= 0;n<3;n++){
  708. if ( (c = inchar(&bio, fi)) == EOF) {
  709. hiteof= 1;
  710. break;
  711. }
  712. igroup[n]= (unsigned char)c;
  713. }
  714. if(n> 0){
  715. ogroup[0]= dtable[igroup[0]>>2];
  716. ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
  717. ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
  718. ogroup[3]= dtable[igroup[2]&0x3F];
  719. if(n<3) {
  720. ogroup[3]= '=';
  721. if(n<2)
  722. ogroup[2]= '=';
  723. }
  724. for(i= 0;i<4;i++)
  725. ochar(&bio, ogroup[i], so);
  726. }
  727. }
  728. if(fputs(eol,so)==EOF)
  729. return 0;
  730. fclose(fi);
  731. return 1;
  732. }
  733. static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *dur, char *date, char *passdata, size_t passdatasize)
  734. {
  735. /* Prepare variables for substition in email body and subject */
  736. pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
  737. pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
  738. snprintf(passdata, passdatasize, "%d", msgnum);
  739. pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
  740. pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
  741. pbx_builtin_setvar_helper(ast, "VM_CALLERID", (callerid ? callerid : "an unknown caller"));
  742. pbx_builtin_setvar_helper(ast, "VM_DATE", date);
  743. }
  744. static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *callerid, char *attach, char *format, int duration, int attach_user_voicemail)
  745. {
  746. FILE *p=NULL;
  747. int pfd;
  748. char date[256];
  749. char host[MAXHOSTNAMELEN] = "";
  750. char who[256];
  751. char bound[256];
  752. char fname[256];
  753. char dur[256];
  754. char tmp[80] = "/tmp/astmail-XXXXXX";
  755. char tmp2[256];
  756. time_t t;
  757. struct tm tm;
  758. struct vm_zone *the_zone = NULL;
  759. if (vmu && ast_strlen_zero(vmu->email)) {
  760. ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
  761. return(0);
  762. }
  763. if (!strcmp(format, "wav49"))
  764. format = "WAV";
  765. ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, attach_voicemail);
  766. /* Make a temporary file instead of piping directly to sendmail, in case the mail
  767. command hangs */
  768. pfd = mkstemp(tmp);
  769. if (pfd > -1) {
  770. p = fdopen(pfd, "w");
  771. if (!p) {
  772. close(pfd);
  773. pfd = -1;
  774. }
  775. }
  776. if (p) {
  777. gethostname(host, sizeof(host)-1);
  778. if (strchr(srcemail, '@'))
  779. strncpy(who, srcemail, sizeof(who)-1);
  780. else {
  781. snprintf(who, sizeof(who), "%s@%s", srcemail, host);
  782. }
  783. snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
  784. time(&t);
  785. /* Does this user have a timezone specified? */
  786. if (!ast_strlen_zero(vmu->zonetag)) {
  787. /* Find the zone in the list */
  788. struct vm_zone *z;
  789. z = zones;
  790. while (z) {
  791. if (!strcmp(z->name, vmu->zonetag)) {
  792. the_zone = z;
  793. break;
  794. }
  795. z = z->next;
  796. }
  797. }
  798. if (the_zone)
  799. ast_localtime(&t,&tm,the_zone->timezone);
  800. else
  801. ast_localtime(&t,&tm,NULL);
  802. strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
  803. fprintf(p, "Date: %s\n", date);
  804. if (*fromstring) {
  805. struct ast_channel *ast = ast_channel_alloc(0);
  806. if (ast) {
  807. char *passdata;
  808. int vmlen = strlen(fromstring)*3 + 200;
  809. if ((passdata = alloca(vmlen))) {
  810. memset(passdata, 0, vmlen);
  811. prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
  812. pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen);
  813. fprintf(p, "From: %s <%s>\n",passdata,who);
  814. } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
  815. ast_channel_free(ast);
  816. } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
  817. } else
  818. fprintf(p, "From: Asterisk PBX <%s>\n", who);
  819. fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
  820. if (emailsubject) {
  821. struct ast_channel *ast = ast_channel_alloc(0);
  822. if (ast) {
  823. char *passdata;
  824. int vmlen = strlen(emailsubject)*3 + 200;
  825. if ((passdata = alloca(vmlen))) {
  826. memset(passdata, 0, vmlen);
  827. prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
  828. pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen);
  829. fprintf(p, "Subject: %s\n",passdata);
  830. } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
  831. ast_channel_free(ast);
  832. } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
  833. } else
  834. if( *emailtitle)
  835. {
  836. fprintf(p, emailtitle, msgnum + 1, mailbox) ;
  837. fprintf(p,"\n") ;
  838. }
  839. else
  840. if (pbxskip)
  841. fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
  842. else
  843. fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
  844. fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)rand(), mailbox, getpid(), host);
  845. fprintf(p, "MIME-Version: 1.0\n");
  846. if (attach_user_voicemail) {
  847. /* Something unique. */
  848. snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand());
  849. fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
  850. fprintf(p, "--%s\n", bound);
  851. }
  852. fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
  853. strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
  854. if (emailbody) {
  855. struct ast_channel *ast = ast_channel_alloc(0);
  856. if (ast) {
  857. char *passdata;
  858. int vmlen = strlen(emailbody)*3 + 200;
  859. if ((passdata = alloca(vmlen))) {
  860. memset(passdata, 0, vmlen);
  861. prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
  862. pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
  863. fprintf(p, "%s\n",passdata);
  864. } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
  865. ast_channel_free(ast);
  866. } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
  867. } else {
  868. fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
  869. "in mailbox %s from %s, on %s so you might\n"
  870. "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
  871. dur, msgnum + 1, mailbox, (callerid ? callerid : "an unknown caller"), date);
  872. }
  873. if (attach_user_voicemail) {
  874. fprintf(p, "--%s\n", bound);
  875. fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
  876. fprintf(p, "Content-Transfer-Encoding: base64\n");
  877. fprintf(p, "Content-Description: Voicemail sound attachment.\n");
  878. fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
  879. snprintf(fname, sizeof(fname), "%s.%s", attach, format);
  880. base_encode(fname, p);
  881. fprintf(p, "\n\n--%s--\n.\n", bound);
  882. }
  883. fclose(p);
  884. snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
  885. ast_safe_system(tmp2);
  886. ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
  887. } else {
  888. ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
  889. return -1;
  890. }
  891. return 0;
  892. }
  893. static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *callerid, int duration, struct ast_vm_user *vmu)
  894. {
  895. FILE *p=NULL;
  896. int pfd;
  897. char date[256];
  898. char host[MAXHOSTNAMELEN]="";
  899. char who[256];
  900. char dur[256];
  901. char tmp[80] = "/tmp/astmail-XXXXXX";
  902. char tmp2[256];
  903. time_t t;
  904. struct tm tm;
  905. struct vm_zone *the_zone = NULL;
  906. pfd = mkstemp(tmp);
  907. if (pfd > -1) {
  908. p = fdopen(pfd, "w");
  909. if (!p) {
  910. close(pfd);
  911. pfd = -1;
  912. }
  913. }
  914. if (p) {
  915. gethostname(host, sizeof(host)-1);
  916. if (strchr(srcemail, '@'))
  917. strncpy(who, srcemail, sizeof(who)-1);
  918. else {
  919. snprintf(who, sizeof(who), "%s@%s", srcemail, host);
  920. }
  921. snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
  922. time(&t);
  923. /* Does this user have a timezone specified? */
  924. if (!ast_strlen_zero(vmu->zonetag)) {
  925. /* Find the zone in the list */
  926. struct vm_zone *z;
  927. z = zones;
  928. while (z) {
  929. if (!strcmp(z->name, vmu->zonetag)) {
  930. the_zone = z;
  931. break;
  932. }
  933. z = z->next;
  934. }
  935. }
  936. if (the_zone)
  937. ast_localtime(&t,&tm,the_zone->timezone);
  938. else
  939. ast_localtime(&t,&tm,NULL);
  940. strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
  941. fprintf(p, "Date: %s\n", date);
  942. if (*pagerfromstring) {
  943. struct ast_channel *ast = ast_channel_alloc(0);
  944. if (ast) {
  945. char *passdata;
  946. int vmlen = strlen(fromstring)*3 + 200;
  947. if ((passdata = alloca(vmlen))) {
  948. memset(passdata, 0, vmlen);
  949. prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,callerid,dur,date,passdata, vmlen);
  950. pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen);
  951. fprintf(p, "From: %s <%s>\n",passdata,who);
  952. } else
  953. ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
  954. ast_channel_free(ast);
  955. } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
  956. } else
  957. fprintf(p, "From: Asterisk PBX <%s>\n", who);
  958. fprintf(p, "To: %s\n", pager);
  959. fprintf(p, "Subject: New VM\n\n");
  960. strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
  961. fprintf(p, "New %s long msg in box %s\n"
  962. "from %s, on %s", dur, mailbox, (callerid ? callerid : "unknown"), date);
  963. fclose(p);
  964. snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
  965. ast_safe_system(tmp2);
  966. ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
  967. } else {
  968. ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
  969. return -1;
  970. }
  971. return 0;
  972. }
  973. static int get_date(char *s, int len)
  974. {
  975. struct tm tm;
  976. time_t t;
  977. t = time(0);
  978. localtime_r(&t,&tm);
  979. return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
  980. }
  981. static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
  982. {
  983. int res;
  984. char fn[256];
  985. snprintf(fn, sizeof(fn), "voicemail/%s/%s/greet", context, ext);
  986. if (ast_fileexists(fn, NULL, NULL) > 0) {
  987. res = ast_streamfile(chan, fn, chan->language);
  988. if (res)
  989. return -1;
  990. res = ast_waitstream(chan, ecodes);
  991. if (res)
  992. return res;
  993. } else {
  994. res = ast_streamfile(chan, "vm-theperson", chan->language);
  995. if (res)
  996. return -1;
  997. res = ast_waitstream(chan, ecodes);
  998. if (res)
  999. return res;
  1000. res = ast_say_digit_str(chan, ext, ecodes, chan->language);
  1001. if (res)
  1002. return res;
  1003. }
  1004. if (busy)
  1005. res = ast_streamfile(chan, "vm-isonphone", chan->language);
  1006. else
  1007. res = ast_streamfile(chan, "vm-isunavail", chan->language);
  1008. if (res)
  1009. return -1;
  1010. res = ast_waitstream(chan, ecodes);
  1011. return res;
  1012. }
  1013. static void free_user(struct ast_vm_user *vmu)
  1014. {
  1015. if (vmu->alloced)
  1016. free(vmu);
  1017. }
  1018. static void free_zone(struct vm_zone *z)
  1019. {
  1020. free(z);
  1021. }
  1022. static char *mbox(int id)
  1023. {
  1024. switch(id) {
  1025. case 0:
  1026. return "INBOX";
  1027. case 1:
  1028. return "Old";
  1029. case 2:
  1030. return "Work";
  1031. case 3:
  1032. return "Family";
  1033. case 4:
  1034. return "Friends";
  1035. case 5:
  1036. return "Cust1";
  1037. case 6:
  1038. return "Cust2";
  1039. case 7:
  1040. return "Cust3";
  1041. case 8:
  1042. return "Cust4";
  1043. case 9:
  1044. return "Cust5";
  1045. default:
  1046. return "Unknown";
  1047. }
  1048. }
  1049. static int copy(char *infile, char *outfile)
  1050. {
  1051. int ifd;
  1052. int ofd;
  1053. int res;
  1054. int len;
  1055. char buf[4096];
  1056. #ifdef HARDLINK_WHEN_POSSIBLE
  1057. /* Hard link if possible; saves disk space & is faster */
  1058. if (link(infile, outfile)) {
  1059. #endif
  1060. if ((ifd = open(infile, O_RDONLY)) < 0) {
  1061. ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
  1062. return -1;
  1063. }
  1064. if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
  1065. ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
  1066. close(ifd);
  1067. return -1;
  1068. }
  1069. do {
  1070. len = read(ifd, buf, sizeof(buf));
  1071. if (len < 0) {
  1072. ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
  1073. close(ifd);
  1074. close(ofd);
  1075. unlink(outfile);
  1076. }
  1077. if (len) {
  1078. res = write(ofd, buf, len);
  1079. if (res != len) {
  1080. ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
  1081. close(ifd);
  1082. close(ofd);
  1083. unlink(outfile);
  1084. }
  1085. }
  1086. } while(len);
  1087. close(ifd);
  1088. close(ofd);
  1089. return 0;
  1090. #ifdef HARDLINK_WHEN_POSSIBLE
  1091. } else {
  1092. /* Hard link succeeded */
  1093. return 0;
  1094. }
  1095. #endif
  1096. }
  1097. static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid);
  1098. static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt)
  1099. {
  1100. char fromdir[256], todir[256], frompath[256], topath[256];
  1101. char *frombox = mbox(imbox);
  1102. int recipmsgnum;
  1103. ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
  1104. make_dir(todir, sizeof(todir), recip->context, "", "");
  1105. /* It's easier just to try to make it than to check for its existence */
  1106. if (mkdir(todir, 0700) && (errno != EEXIST))
  1107. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
  1108. make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
  1109. /* It's easier just to try to make it than to check for its existence */
  1110. if (mkdir(todir, 0700) && (errno != EEXIST))
  1111. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
  1112. make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
  1113. if (mkdir(todir, 0700) && (errno != EEXIST))
  1114. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
  1115. make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
  1116. make_file(frompath, sizeof(frompath), fromdir, msgnum);
  1117. ast_lock_path(topath);
  1118. recipmsgnum = 0;
  1119. do {
  1120. make_file(topath, sizeof(topath), todir, recipmsgnum);
  1121. if (ast_fileexists(topath, NULL, chan->language) <= 0)
  1122. break;
  1123. recipmsgnum++;
  1124. } while(recipmsgnum < MAXMSG);
  1125. if (recipmsgnum < MAXMSG) {
  1126. char frompath2[256],topath2[256];
  1127. ast_filecopy(frompath, topath, NULL);
  1128. snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
  1129. snprintf(topath2, sizeof(topath2), "%s.txt", topath);
  1130. copy(frompath2, topath2);
  1131. } else {
  1132. ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
  1133. }
  1134. ast_unlock_path(topath);
  1135. notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
  1136. }
  1137. static void run_externnotify(char *context, char *extension)
  1138. {
  1139. char arguments[255];
  1140. int newvoicemails = 0, oldvoicemails = 0;
  1141. if(!ast_strlen_zero(externnotify)) {
  1142. if (ast_app_messagecount(extension, &newvoicemails, &oldvoicemails)) {
  1143. ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
  1144. } else {
  1145. snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
  1146. ast_log(LOG_DEBUG,"Executing %s\n", arguments);
  1147. ast_safe_system(arguments);
  1148. }
  1149. }
  1150. }
  1151. static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
  1152. {
  1153. char txtfile[256];
  1154. FILE *txt;
  1155. int res = 0;
  1156. int msgnum;
  1157. int duration = 0;
  1158. int ausemacro = 0;
  1159. int ousemacro = 0;
  1160. char date[256];
  1161. char dir[256];
  1162. char fn[256];
  1163. char prefile[256]="";
  1164. char ext_context[256] = "";
  1165. char fmt[80];
  1166. char *context;
  1167. char ecodes[16] = "#";
  1168. char tmp[256] = "", *tmpptr;
  1169. struct ast_vm_user *vmu;
  1170. struct ast_vm_user svm;
  1171. strncpy(tmp, ext, sizeof(tmp) - 1);
  1172. ext = tmp;
  1173. context = strchr(tmp, '@');
  1174. if (context) {
  1175. *context = '\0';
  1176. context++;
  1177. tmpptr = strchr(context, '&');
  1178. } else {
  1179. tmpptr = strchr(ext, '&');
  1180. }
  1181. if (tmpptr) {
  1182. *tmpptr = '\0';
  1183. tmpptr++;
  1184. }
  1185. if ((vmu = find_user(&svm, context, ext))) {
  1186. /* Setup pre-file if appropriate */
  1187. if (strcmp(vmu->context, "default"))
  1188. snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
  1189. else
  1190. strncpy(ext_context, vmu->context, sizeof(ext_context) - 1);
  1191. if (busy)
  1192. snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
  1193. else if (unavail)
  1194. snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
  1195. make_dir(dir, sizeof(dir), vmu->context, "", "");
  1196. /* It's easier just to try to make it than to check for its existence */
  1197. if (mkdir(dir, 0700) && (errno != EEXIST))
  1198. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
  1199. make_dir(dir, sizeof(dir), vmu->context, ext, "");
  1200. /* It's easier just to try to make it than to check for its existence */
  1201. if (mkdir(dir, 0700) && (errno != EEXIST))
  1202. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
  1203. make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
  1204. if (mkdir(dir, 0700) && (errno != EEXIST))
  1205. ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
  1206. /* Check current or macro-calling context for special extensions */
  1207. if (!ast_strlen_zero(vmu->exit)) {
  1208. if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->callerid))
  1209. strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
  1210. } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->callerid))
  1211. strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
  1212. else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->callerid)) {
  1213. strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
  1214. ousemacro = 1;
  1215. }
  1216. if (!ast_strlen_zero(vmu->exit)) {
  1217. if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->callerid))
  1218. strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
  1219. } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->callerid))
  1220. strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
  1221. else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->callerid)) {
  1222. strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
  1223. ausemacro = 1;
  1224. }
  1225. /* Play the beginning intro if desired */
  1226. if (!ast_strlen_zero(prefile)) {
  1227. if (ast_fileexists(prefile, NULL, NULL) > 0) {
  1228. if (ast_streamfile(chan, prefile, chan->language) > -1)
  1229. res = ast_waitstream(chan, ecodes);
  1230. } else {
  1231. ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
  1232. res = invent_message(chan, vmu->context, ext, busy, ecodes);
  1233. }
  1234. if (res < 0) {
  1235. ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
  1236. free_user(vmu);
  1237. return -1;
  1238. }
  1239. }
  1240. if (res == '#') {
  1241. /* On a '#' we skip the instructions */
  1242. silent = 1;
  1243. res = 0;
  1244. }
  1245. if (!res && !silent) {
  1246. res = ast_streamfile(chan, INTRO, chan->language);
  1247. if (!res)
  1248. res = ast_waitstream(chan, ecodes);
  1249. if (res == '#') {
  1250. silent = 1;
  1251. res = 0;
  1252. }
  1253. }
  1254. if (res > 0)
  1255. ast_stopstream(chan);
  1256. /* Check for a '*' here in case the caller wants to escape from voicemail to something
  1257. other than the operator -- an automated attendant or mailbox login for example */
  1258. if (res == '*') {
  1259. strncpy(chan->exten, "a", sizeof(chan->exten) - 1);
  1260. if (!ast_strlen_zero(vmu->exit)) {
  1261. strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
  1262. } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
  1263. strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
  1264. }
  1265. chan->priority = 0;
  1266. free_user(vmu);
  1267. return 0;
  1268. }
  1269. /* Check for a '0' here */
  1270. if (res == '0') {
  1271. transfer:
  1272. if (vmu->operator) {
  1273. strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
  1274. if (!ast_strlen_zero(vmu->exit)) {
  1275. strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
  1276. } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
  1277. strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
  1278. }
  1279. ast_play_and_wait(chan, "transfer");
  1280. chan->priority = 0;
  1281. free_user(vmu);
  1282. return 0;
  1283. } else {
  1284. ast_play_and_wait(chan, "vm-sorry");
  1285. return 0;
  1286. }
  1287. }
  1288. if (res < 0) {
  1289. free_user(vmu);
  1290. return -1;
  1291. }
  1292. /* The meat of recording the message... All the announcements and beeps have been played*/
  1293. strncpy(fmt, vmfmts, sizeof(fmt) - 1);
  1294. if (!ast_strlen_zero(fmt)) {
  1295. msgnum = 0;
  1296. if (res >= 0) {
  1297. /* Unless we're *really* silent, try to send the beep */
  1298. res = ast_streamfile(chan, "beep", chan->language);
  1299. if (!res)
  1300. res = ast_waitstream(chan, "");
  1301. }
  1302. ast_lock_path(dir);
  1303. do {
  1304. make_file(fn, sizeof(fn), dir, msgnum);
  1305. if (ast_fileexists(fn, NULL, chan->language) <= 0)
  1306. break;
  1307. msgnum++;
  1308. } while(msgnum < MAXMSG);
  1309. if (msgnum < MAXMSG) {
  1310. /* Store information */
  1311. snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
  1312. txt = fopen(txtfile, "w+");
  1313. if (txt) {
  1314. get_date(date, sizeof(date));
  1315. fprintf(txt,
  1316. ";\n"
  1317. "; Message Information file\n"
  1318. ";\n"
  1319. "[message]\n"
  1320. "origmailbox=%s\n"
  1321. "context=%s\n"
  1322. "macrocontext=%s\n"
  1323. "exten=%s\n"
  1324. "priority=%d\n"
  1325. "callerchan=%s\n"
  1326. "callerid=%s\n"
  1327. "origdate=%s\n"
  1328. "origtime=%ld\n",
  1329. ext,
  1330. chan->context,
  1331. chan->macrocontext,
  1332. chan->exten,
  1333. chan->priority,
  1334. chan->name,
  1335. chan->callerid ? chan->callerid : "Unknown",
  1336. date, (long)time(NULL));
  1337. } else
  1338. ast_log(LOG_WARNING, "Error opening text file for output\n");
  1339. res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir);
  1340. if (res == '0') {
  1341. if (txt)
  1342. fclose(txt);
  1343. goto transfer;
  1344. }
  1345. if (res > 0)
  1346. res = 0;
  1347. if (txt) {
  1348. fprintf(txt, "duration=%d\n", duration);
  1349. fclose(txt);
  1350. }
  1351. if (duration < vmminmessage) {
  1352. if (option_verbose > 2)
  1353. ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
  1354. vm_delete(fn);
  1355. /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
  1356. goto leave_vm_out;
  1357. }
  1358. /* Are there to be more recipients of this message? */
  1359. while (tmpptr) {
  1360. struct ast_vm_user recipu, *recip;
  1361. char *exten, *context;
  1362. exten = strsep(&tmpptr, "&");
  1363. context = strchr(exten, '@');
  1364. if (context) {
  1365. *context = '\0';
  1366. context++;
  1367. }
  1368. if ((recip = find_user(&recipu, context, exten))) {
  1369. copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
  1370. free_user(recip);
  1371. }
  1372. }
  1373. if (ast_fileexists(fn, NULL, NULL))
  1374. notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
  1375. } else {
  1376. ast_unlock_path(dir);
  1377. res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
  1378. if (!res)
  1379. res = ast_waitstream(chan, "");
  1380. ast_log(LOG_WARNING, "No more messages possible\n");
  1381. }
  1382. } else
  1383. ast_log(LOG_WARNING, "No format for saving voicemail?\n");
  1384. leave_vm_out:
  1385. free_user(vmu);
  1386. } else {
  1387. ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
  1388. /*Send the call to n+101 priority, where n is the current priority*/
  1389. if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
  1390. chan->priority+=100;
  1391. }
  1392. return res;
  1393. }
  1394. static int count_messages(char *dir)
  1395. {
  1396. /* Find all .txt files - even if they are not in sequence from 0000 */
  1397. int vmcount = 0;
  1398. DIR *vmdir = NULL;
  1399. struct dirent *vment = NULL;
  1400. if ((vmdir = opendir(dir))) {
  1401. while ((vment = readdir(vmdir)))
  1402. {
  1403. if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
  1404. {
  1405. vmcount++;
  1406. }
  1407. }
  1408. closedir(vmdir);
  1409. }
  1410. return vmcount;
  1411. }
  1412. static void resequence_mailbox(char * dir)
  1413. {
  1414. /* we know max messages, so stop process when number is hit */
  1415. int x,dest;
  1416. char sfn[256];
  1417. char dfn[256];
  1418. char stxt[256];
  1419. char dtxt[256];
  1420. ast_lock_path(dir);
  1421. for (x=0,dest=0;x<MAXMSG;x++) {
  1422. make_file(sfn, sizeof(sfn), dir, x);
  1423. if (ast_fileexists(sfn, NULL, NULL) > 0) {
  1424. if(x != dest) {
  1425. make_file(dfn, sizeof(dfn), dir, dest);
  1426. ast_filerename(sfn,dfn,NULL);
  1427. snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
  1428. snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
  1429. rename(stxt, dtxt);
  1430. }
  1431. dest++;
  1432. }
  1433. }
  1434. ast_unlock_path(dir);
  1435. }
  1436. static int say_and_wait(struct ast_channel *chan, int num, char *language)
  1437. {
  1438. int d;
  1439. d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
  1440. return d;
  1441. }
  1442. static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
  1443. {
  1444. char sfn[256];
  1445. char dfn[256];
  1446. char ddir[256];
  1447. char txt[256];
  1448. char ntxt[256];
  1449. char *dbox = mbox(box);
  1450. int x;
  1451. make_file(sfn, sizeof(sfn), dir, msg);
  1452. make_dir(ddir, sizeof(ddir), context, username, dbox);
  1453. mkdir(ddir, 0700);
  1454. ast_lock_path(ddir);
  1455. for (x=0;x<MAXMSG;x++) {
  1456. make_file(dfn, sizeof(dfn), ddir, x);
  1457. if (ast_fileexists(dfn, NULL, NULL) < 0)
  1458. break;
  1459. }
  1460. if (x >= MAXMSG) {
  1461. ast_unlock_path(ddir);
  1462. return -1;
  1463. }
  1464. ast_filecopy(sfn, dfn, NULL);
  1465. if (strcmp(sfn, dfn)) {
  1466. snprintf(txt, sizeof(txt), "%s.txt", sfn);
  1467. snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
  1468. copy(txt, ntxt);
  1469. }
  1470. ast_unlock_path(ddir);
  1471. return 0;
  1472. }
  1473. static int adsi_logo(unsigned char *buf)
  1474. {
  1475. int bytes = 0;
  1476. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
  1477. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
  1478. return bytes;
  1479. }
  1480. static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
  1481. {
  1482. char buf[256];
  1483. int bytes=0;
  1484. int x;
  1485. char num[5];
  1486. *useadsi = 0;
  1487. bytes += adsi_data_mode(buf + bytes);
  1488. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1489. bytes = 0;
  1490. bytes += adsi_logo(buf);
  1491. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
  1492. #ifdef DISPLAY
  1493. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
  1494. #endif
  1495. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1496. bytes += adsi_data_mode(buf + bytes);
  1497. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1498. if (adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
  1499. bytes = 0;
  1500. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
  1501. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
  1502. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1503. bytes += adsi_voice_mode(buf + bytes, 0);
  1504. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1505. return 0;
  1506. }
  1507. #ifdef DISPLAY
  1508. /* Add a dot */
  1509. bytes = 0;
  1510. bytes += adsi_logo(buf);
  1511. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
  1512. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
  1513. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1514. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1515. #endif
  1516. bytes = 0;
  1517. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
  1518. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
  1519. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
  1520. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
  1521. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
  1522. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
  1523. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
  1524. #ifdef DISPLAY
  1525. /* Add another dot */
  1526. bytes = 0;
  1527. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
  1528. bytes += adsi_voice_mode(buf + bytes, 0);
  1529. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1530. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1531. #endif
  1532. bytes = 0;
  1533. /* These buttons we load but don't use yet */
  1534. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
  1535. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
  1536. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
  1537. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
  1538. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
  1539. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
  1540. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
  1541. #ifdef DISPLAY
  1542. /* Add another dot */
  1543. bytes = 0;
  1544. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
  1545. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1546. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1547. #endif
  1548. bytes = 0;
  1549. for (x=0;x<5;x++) {
  1550. snprintf(num, sizeof(num), "%d", x);
  1551. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
  1552. }
  1553. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
  1554. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
  1555. #ifdef DISPLAY
  1556. /* Add another dot */
  1557. bytes = 0;
  1558. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
  1559. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1560. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1561. #endif
  1562. if (adsi_end_download(chan)) {
  1563. bytes = 0;
  1564. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
  1565. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
  1566. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1567. bytes += adsi_voice_mode(buf + bytes, 0);
  1568. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1569. return 0;
  1570. }
  1571. bytes = 0;
  1572. bytes += adsi_download_disconnect(buf + bytes);
  1573. bytes += adsi_voice_mode(buf + bytes, 0);
  1574. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
  1575. ast_log(LOG_DEBUG, "Done downloading scripts...\n");
  1576. #ifdef DISPLAY
  1577. /* Add last dot */
  1578. bytes = 0;
  1579. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
  1580. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1581. #endif
  1582. ast_log(LOG_DEBUG, "Restarting session...\n");
  1583. bytes = 0;
  1584. /* Load the session now */
  1585. if (adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
  1586. *useadsi = 1;
  1587. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
  1588. } else
  1589. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
  1590. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1591. return 0;
  1592. }
  1593. static void adsi_begin(struct ast_channel *chan, int *useadsi)
  1594. {
  1595. int x;
  1596. if (!adsi_available(chan))
  1597. return;
  1598. x = adsi_load_session(chan, adsifdn, adsiver, 1);
  1599. if (x < 0)
  1600. return;
  1601. if (!x) {
  1602. if (adsi_load_vmail(chan, useadsi)) {
  1603. ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
  1604. return;
  1605. }
  1606. } else
  1607. *useadsi = 1;
  1608. }
  1609. static void adsi_login(struct ast_channel *chan)
  1610. {
  1611. char buf[256];
  1612. int bytes=0;
  1613. unsigned char keys[8];
  1614. int x;
  1615. if (!adsi_available(chan))
  1616. return;
  1617. for (x=0;x<8;x++)
  1618. keys[x] = 0;
  1619. /* Set one key for next */
  1620. keys[3] = ADSI_KEY_APPS + 3;
  1621. bytes += adsi_logo(buf + bytes);
  1622. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
  1623. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
  1624. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1625. bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
  1626. bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
  1627. bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
  1628. bytes += adsi_set_keys(buf + bytes, keys);
  1629. bytes += adsi_voice_mode(buf + bytes, 0);
  1630. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1631. }
  1632. static void adsi_password(struct ast_channel *chan)
  1633. {
  1634. char buf[256];
  1635. int bytes=0;
  1636. unsigned char keys[8];
  1637. int x;
  1638. if (!adsi_available(chan))
  1639. return;
  1640. for (x=0;x<8;x++)
  1641. keys[x] = 0;
  1642. /* Set one key for next */
  1643. keys[3] = ADSI_KEY_APPS + 3;
  1644. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1645. bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
  1646. bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
  1647. bytes += adsi_set_keys(buf + bytes, keys);
  1648. bytes += adsi_voice_mode(buf + bytes, 0);
  1649. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1650. }
  1651. static void adsi_folders(struct ast_channel *chan, int start, char *label)
  1652. {
  1653. char buf[256];
  1654. int bytes=0;
  1655. unsigned char keys[8];
  1656. int x,y;
  1657. if (!adsi_available(chan))
  1658. return;
  1659. for (x=0;x<5;x++) {
  1660. y = ADSI_KEY_APPS + 12 + start + x;
  1661. if (y > ADSI_KEY_APPS + 12 + 4)
  1662. y = 0;
  1663. keys[x] = ADSI_KEY_SKT | y;
  1664. }
  1665. keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
  1666. keys[6] = 0;
  1667. keys[7] = 0;
  1668. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
  1669. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
  1670. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1671. bytes += adsi_set_keys(buf + bytes, keys);
  1672. bytes += adsi_voice_mode(buf + bytes, 0);
  1673. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1674. }
  1675. static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
  1676. {
  1677. int bytes=0;
  1678. char buf[256], buf1[256], buf2[256];
  1679. char fn2[256];
  1680. char cid[256]="";
  1681. char *val;
  1682. char *name, *num;
  1683. char datetime[21]="";
  1684. FILE *f;
  1685. unsigned char keys[8];
  1686. int x;
  1687. if (!adsi_available(chan))
  1688. return;
  1689. /* Retrieve important info */
  1690. snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
  1691. f = fopen(fn2, "r");
  1692. if (f) {
  1693. while(!feof(f)) {
  1694. fgets(buf, sizeof(buf), f);
  1695. if (!feof(f)) {
  1696. char *stringp=NULL;
  1697. stringp=buf;
  1698. strsep(&stringp, "=");
  1699. val = strsep(&stringp, "=");
  1700. if (val && !ast_strlen_zero(val)) {
  1701. if (!strcmp(buf, "callerid"))
  1702. strncpy(cid, val, sizeof(cid) - 1);
  1703. if (!strcmp(buf, "origdate"))
  1704. strncpy(datetime, val, sizeof(datetime) - 1);
  1705. }
  1706. }
  1707. }
  1708. fclose(f);
  1709. }
  1710. /* New meaning for keys */
  1711. for (x=0;x<5;x++)
  1712. keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
  1713. keys[6] = 0x0;
  1714. keys[7] = 0x0;
  1715. if (!vms->curmsg) {
  1716. /* No prev key, provide "Folder" instead */
  1717. keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
  1718. }
  1719. if (vms->curmsg >= vms->lastmsg) {
  1720. /* If last message ... */
  1721. if (vms->curmsg) {
  1722. /* but not only message, provide "Folder" instead */
  1723. keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
  1724. bytes += adsi_voice_mode(buf + bytes, 0);
  1725. } else {
  1726. /* Otherwise if only message, leave blank */
  1727. keys[3] = 1;
  1728. }
  1729. }
  1730. if (!ast_strlen_zero(cid)) {
  1731. ast_callerid_parse(cid, &name, &num);
  1732. if (!name)
  1733. name = num;
  1734. } else
  1735. name = "Unknown Caller";
  1736. /* If deleted, show "undeleted" */
  1737. if (vms->deleted[vms->curmsg])
  1738. keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
  1739. /* Except "Exit" */
  1740. keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
  1741. snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
  1742. strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
  1743. snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
  1744. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
  1745. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
  1746. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
  1747. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
  1748. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1749. bytes += adsi_set_keys(buf + bytes, keys);
  1750. bytes += adsi_voice_mode(buf + bytes, 0);
  1751. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1752. }
  1753. static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
  1754. {
  1755. int bytes=0;
  1756. char buf[256];
  1757. unsigned char keys[8];
  1758. int x;
  1759. if (!adsi_available(chan))
  1760. return;
  1761. /* New meaning for keys */
  1762. for (x=0;x<5;x++)
  1763. keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
  1764. keys[6] = 0x0;
  1765. keys[7] = 0x0;
  1766. if (!vms->curmsg) {
  1767. /* No prev key, provide "Folder" instead */
  1768. keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
  1769. }
  1770. if (vms->curmsg >= vms->lastmsg) {
  1771. /* If last message ... */
  1772. if (vms->curmsg) {
  1773. /* but not only message, provide "Folder" instead */
  1774. keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
  1775. } else {
  1776. /* Otherwise if only message, leave blank */
  1777. keys[3] = 1;
  1778. }
  1779. }
  1780. /* If deleted, show "undeleted" */
  1781. if (vms->deleted[vms->curmsg])
  1782. keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
  1783. /* Except "Exit" */
  1784. keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
  1785. bytes += adsi_set_keys(buf + bytes, keys);
  1786. bytes += adsi_voice_mode(buf + bytes, 0);
  1787. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1788. }
  1789. static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
  1790. {
  1791. char buf[256] = "", buf1[256] = "", buf2[256] = "";
  1792. int bytes=0;
  1793. unsigned char keys[8];
  1794. int x;
  1795. char *newm = (vms->newmessages == 1) ? "message" : "messages";
  1796. char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
  1797. if (!adsi_available(chan))
  1798. return;
  1799. if (vms->newmessages) {
  1800. snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
  1801. if (vms->oldmessages) {
  1802. strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
  1803. snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
  1804. } else {
  1805. snprintf(buf2, sizeof(buf2), "%s.", newm);
  1806. }
  1807. } else if (vms->oldmessages) {
  1808. snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
  1809. snprintf(buf2, sizeof(buf2), "%s.", oldm);
  1810. } else {
  1811. strncpy(buf1, "You have no messages.", sizeof(buf1) - 1);
  1812. buf2[0] = ' ';
  1813. buf2[1] = '\0';
  1814. }
  1815. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
  1816. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
  1817. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1818. for (x=0;x<6;x++)
  1819. keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
  1820. keys[6] = 0;
  1821. keys[7] = 0;
  1822. /* Don't let them listen if there are none */
  1823. if (vms->lastmsg < 0)
  1824. keys[0] = 1;
  1825. bytes += adsi_set_keys(buf + bytes, keys);
  1826. bytes += adsi_voice_mode(buf + bytes, 0);
  1827. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1828. }
  1829. static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
  1830. {
  1831. char buf[256] = "", buf1[256] = "", buf2[256] = "";
  1832. int bytes=0;
  1833. unsigned char keys[8];
  1834. int x;
  1835. char *mess = (vms->lastmsg == 0) ? "message" : "messages";
  1836. if (!adsi_available(chan))
  1837. return;
  1838. /* Original command keys */
  1839. for (x=0;x<6;x++)
  1840. keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
  1841. keys[6] = 0;
  1842. keys[7] = 0;
  1843. if ((vms->lastmsg + 1) < 1)
  1844. keys[0] = 0;
  1845. snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
  1846. strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
  1847. if (vms->lastmsg + 1)
  1848. snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
  1849. else
  1850. strncpy(buf2, "no messages.", sizeof(buf2) - 1);
  1851. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
  1852. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
  1853. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
  1854. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1855. bytes += adsi_set_keys(buf + bytes, keys);
  1856. bytes += adsi_voice_mode(buf + bytes, 0);
  1857. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1858. }
  1859. /*
  1860. static void adsi_clear(struct ast_channel *chan)
  1861. {
  1862. char buf[256];
  1863. int bytes=0;
  1864. if (!adsi_available(chan))
  1865. return;
  1866. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1867. bytes += adsi_voice_mode(buf + bytes, 0);
  1868. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1869. }
  1870. */
  1871. static void adsi_goodbye(struct ast_channel *chan)
  1872. {
  1873. char buf[256];
  1874. int bytes=0;
  1875. if (!adsi_available(chan))
  1876. return;
  1877. bytes += adsi_logo(buf + bytes);
  1878. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
  1879. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
  1880. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  1881. bytes += adsi_voice_mode(buf + bytes, 0);
  1882. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  1883. }
  1884. /*--- get_folder: Folder menu ---*/
  1885. /* Plays "press 1 for INBOX messages" etc
  1886. Should possibly be internationalized
  1887. */
  1888. static int get_folder(struct ast_channel *chan, int start)
  1889. {
  1890. int x;
  1891. int d;
  1892. char fn[256];
  1893. d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
  1894. if (d)
  1895. return d;
  1896. for (x = start; x< 5; x++) { /* For all folders */
  1897. if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
  1898. return d;
  1899. d = ast_play_and_wait(chan, "vm-for"); /* "for" */
  1900. if (d)
  1901. return d;
  1902. snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
  1903. d = vm_play_folder_name(chan, fn);
  1904. if (d)
  1905. return d;
  1906. d = ast_waitfordigit(chan, 500);
  1907. if (d)
  1908. return d;
  1909. }
  1910. d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
  1911. if (d)
  1912. return d;
  1913. d = ast_waitfordigit(chan, 4000);
  1914. return d;
  1915. }
  1916. static int get_folder2(struct ast_channel *chan, char *fn, int start)
  1917. {
  1918. int res = 0;
  1919. res = ast_play_and_wait(chan, fn); /* Folder name */
  1920. while (((res < '0') || (res > '9')) &&
  1921. (res != '#') && (res >= 0)) {
  1922. res = get_folder(chan, 0);
  1923. }
  1924. return res;
  1925. }
  1926. static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context)
  1927. {
  1928. int cmd = 0;
  1929. int retries = 0;
  1930. int duration = 0;
  1931. while((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
  1932. if (cmd)
  1933. retries = 0;
  1934. switch (cmd) {
  1935. case '1':
  1936. /* prepend a message to the current message and return */
  1937. {
  1938. char file[200];
  1939. snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
  1940. cmd = ast_play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1, silencethreshold, maxsilence);
  1941. break;
  1942. }
  1943. case '2':
  1944. cmd = 't';
  1945. break;
  1946. case '*':
  1947. cmd = '*';
  1948. break;
  1949. default:
  1950. cmd = ast_play_and_wait(chan,"vm-forwardoptions");
  1951. /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
  1952. if (!cmd)
  1953. cmd = ast_play_and_wait(chan,"vm-starmain");
  1954. /* "press star to return to the main menu" */
  1955. if (!cmd)
  1956. cmd = ast_waitfordigit(chan,6000);
  1957. if (!cmd)
  1958. retries++;
  1959. if (retries > 3)
  1960. cmd = 't';
  1961. }
  1962. }
  1963. if (cmd == 't')
  1964. cmd = 0;
  1965. return cmd;
  1966. }
  1967. static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid)
  1968. {
  1969. char todir[256], fn[256], ext_context[256], *stringp;
  1970. make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
  1971. make_file(fn, sizeof(fn), todir, msgnum);
  1972. snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
  1973. /* Attach only the first format */
  1974. fmt = ast_strdupa(fmt);
  1975. if (fmt) {
  1976. stringp = fmt;
  1977. strsep(&stringp, "|");
  1978. if (!ast_strlen_zero(vmu->email)) {
  1979. int attach_user_voicemail = attach_voicemail;
  1980. char *myserveremail = serveremail;
  1981. if (vmu->attach > -1)
  1982. attach_user_voicemail = vmu->attach;
  1983. if (!ast_strlen_zero(vmu->serveremail))
  1984. myserveremail = vmu->serveremail;
  1985. sendmail(myserveremail, vmu, msgnum, vmu->mailbox, callerid, fn, fmt, duration, attach_user_voicemail);
  1986. }
  1987. if (!ast_strlen_zero(vmu->pager)) {
  1988. char *myserveremail = serveremail;
  1989. if (!ast_strlen_zero(vmu->serveremail))
  1990. myserveremail = vmu->serveremail;
  1991. sendpage(myserveremail, vmu->pager, msgnum, vmu->mailbox, callerid, duration, vmu);
  1992. }
  1993. } else {
  1994. ast_log(LOG_ERROR, "Out of memory\n");
  1995. }
  1996. if (vmu->delete) {
  1997. vm_delete(fn);
  1998. }
  1999. /* Leave voicemail for someone */
  2000. manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context));
  2001. run_externnotify(chan->context, ext_context);
  2002. return 0;
  2003. }
  2004. static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt,int flag)
  2005. {
  2006. char username[70];
  2007. char sys[256];
  2008. char todir[256];
  2009. int todircount=0;
  2010. int duration;
  2011. struct ast_config *mif;
  2012. char miffile[256];
  2013. char fn[256];
  2014. char callerid[512];
  2015. char ext_context[256]="";
  2016. int res = 0, cmd = 0;
  2017. struct ast_vm_user *receiver = NULL, *extensions = NULL, *vmtmp = NULL, *vmfree;
  2018. char tmp[256];
  2019. char *stringp, *s;
  2020. int saved_messages = 0, found = 0;
  2021. int valid_extensions = 0;
  2022. while (!res && !valid_extensions) {
  2023. res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */
  2024. if (res)
  2025. break;
  2026. if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
  2027. break;
  2028. /* start all over if no username */
  2029. if (ast_strlen_zero(username))
  2030. continue;
  2031. stringp = username;
  2032. s = strsep(&stringp, "*");
  2033. /* start optimistic */
  2034. valid_extensions = 1;
  2035. while (s) {
  2036. /* find_user is going to malloc since we have a NULL as first argument */
  2037. if ((receiver = find_user(NULL, context, s))) {
  2038. if (!extensions)
  2039. vmtmp = extensions = receiver;
  2040. else {
  2041. vmtmp->next = receiver;
  2042. vmtmp = receiver;
  2043. }
  2044. found++;
  2045. } else {
  2046. valid_extensions = 0;
  2047. break;
  2048. }
  2049. s = strsep(&stringp, "*");
  2050. }
  2051. /* break from the loop of reading the extensions */
  2052. if (valid_extensions)
  2053. break;
  2054. /* "I am sorry, that's not a valid extension. Please try again." */
  2055. res = ast_play_and_wait(chan, "pbx-invalid");
  2056. }
  2057. /* check if we're clear to proceed */
  2058. if (!extensions || !valid_extensions)
  2059. return res;
  2060. vmtmp = extensions;
  2061. if(flag==1)/*Send VoiceMail*/
  2062. {
  2063. cmd=leave_voicemail(chan,username,0,0,0);
  2064. }
  2065. else /*Forward VoiceMail*/
  2066. {
  2067. cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context);
  2068. if (!cmd) {
  2069. while(!res && vmtmp) {
  2070. /* if (ast_play_and_wait(chan, "vm-savedto"))
  2071. break;
  2072. */
  2073. snprintf(todir, sizeof(todir), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
  2074. snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir);
  2075. snprintf(ext_context, sizeof(ext_context), "%s@%s", vmtmp->mailbox, vmtmp->context);
  2076. ast_log(LOG_DEBUG, "%s", sys);
  2077. ast_safe_system(sys);
  2078. todircount = count_messages(todir);
  2079. strncpy(tmp, fmt, sizeof(tmp) - 1);
  2080. stringp = tmp;
  2081. while((s = strsep(&stringp, "|"))) {
  2082. /* XXX This is a hack -- we should use build_filename or similar XXX */
  2083. if (!strcasecmp(s, "wav49"))
  2084. s = "WAV";
  2085. snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s);
  2086. ast_log(LOG_DEBUG, "%s", sys);
  2087. ast_safe_system(sys);
  2088. }
  2089. snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount);
  2090. ast_log(LOG_DEBUG, "%s", sys);
  2091. ast_safe_system(sys);
  2092. snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount);
  2093. /* load the information on the source message so we can send an e-mail like a new message */
  2094. snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg);
  2095. if ((mif=ast_load(miffile))) {
  2096. /* set callerid and duration variables */
  2097. snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid"));
  2098. s = ast_variable_retrieve(mif, NULL, "duration");
  2099. if (s)
  2100. duration = atoi(s);
  2101. else
  2102. duration = 0;
  2103. if (!ast_strlen_zero(vmtmp->email)) {
  2104. int attach_user_voicemail = attach_voicemail;
  2105. char *myserveremail = serveremail;
  2106. if (vmtmp->attach > -1)
  2107. attach_user_voicemail = vmtmp->attach;
  2108. if (!ast_strlen_zero(vmtmp->serveremail))
  2109. myserveremail = vmtmp->serveremail;
  2110. sendmail(myserveremail, vmtmp, todircount, vmtmp->mailbox, callerid, fn, tmp, duration, attach_user_voicemail);
  2111. }
  2112. if (!ast_strlen_zero(vmtmp->pager)) {
  2113. char *myserveremail = serveremail;
  2114. if (!ast_strlen_zero(vmtmp->serveremail))
  2115. myserveremail = vmtmp->serveremail;
  2116. sendpage(myserveremail, vmtmp->pager, todircount, vmtmp->mailbox, callerid, duration, vmtmp);
  2117. }
  2118. ast_destroy(mif); /* or here */
  2119. }
  2120. /* Leave voicemail for someone */
  2121. manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
  2122. run_externnotify(chan->context, ext_context);
  2123. saved_messages++;
  2124. vmfree = vmtmp;
  2125. vmtmp = vmtmp->next;
  2126. free_user(vmfree);
  2127. }
  2128. if (saved_messages > 0) {
  2129. /* give confirmation that the message was saved */
  2130. /* commented out since we can't forward batches yet
  2131. if (saved_messages == 1)
  2132. res = ast_play_and_wait(chan, "vm-message");
  2133. else
  2134. res = ast_play_and_wait(chan, "vm-messages");
  2135. if (!res)
  2136. res = ast_play_and_wait(chan, "vm-saved"); */
  2137. if (!res)
  2138. res = ast_play_and_wait(chan, "vm-msgsaved");
  2139. }
  2140. }
  2141. }
  2142. return res ? res : cmd;
  2143. }
  2144. static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
  2145. {
  2146. int res;
  2147. if ((res = ast_streamfile(chan, file, chan->language)))
  2148. ast_log(LOG_WARNING, "Unable to play message %s\n", file);
  2149. if (!res)
  2150. res = ast_waitstream(chan, AST_DIGIT_ANY);
  2151. return res;
  2152. }
  2153. static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
  2154. {
  2155. return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", skipms);
  2156. }
  2157. static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, char *origtime, char *filename)
  2158. {
  2159. int res = 0;
  2160. struct vm_zone *the_zone = NULL;
  2161. time_t t;
  2162. long tin;
  2163. if (sscanf(origtime,"%ld",&tin) < 1) {
  2164. ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
  2165. return 0;
  2166. }
  2167. t = tin;
  2168. /* Does this user have a timezone specified? */
  2169. if (!ast_strlen_zero(vmu->zonetag)) {
  2170. /* Find the zone in the list */
  2171. struct vm_zone *z;
  2172. z = zones;
  2173. while (z) {
  2174. if (!strcmp(z->name, vmu->zonetag)) {
  2175. the_zone = z;
  2176. break;
  2177. }
  2178. z = z->next;
  2179. }
  2180. }
  2181. /* No internal variable parsing for now, so we'll comment it out for the time being */
  2182. #if 0
  2183. /* Set the DIFF_* variables */
  2184. localtime_r(&t, &time_now);
  2185. gettimeofday(&tv_now,NULL);
  2186. tnow = tv_now.tv_sec;
  2187. localtime_r(&tnow,&time_then);
  2188. /* Day difference */
  2189. if (time_now.tm_year == time_then.tm_year)
  2190. snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
  2191. else
  2192. snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
  2193. pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
  2194. /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
  2195. #endif
  2196. if (the_zone)
  2197. res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
  2198. else if (!strcasecmp(chan->language,"nl")) /* DUTCH syntax */
  2199. res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
  2200. else
  2201. res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
  2202. #if 0
  2203. pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
  2204. #endif
  2205. return res;
  2206. }
  2207. static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, char *context, int callback)
  2208. {
  2209. int res = 0;
  2210. int i;
  2211. char *callerid, *name;
  2212. char prefile[256]="";
  2213. /* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
  2214. /* BB: Still need to change this so that if this function is called by the message envelope (and someone is explicitly requesting to hear the CID), it does not check to see if CID is enabled in the config file */
  2215. if((cid == NULL)||(context == NULL))
  2216. return res;
  2217. /* Strip off caller ID number from name */
  2218. ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
  2219. ast_callerid_parse(cid, &name, &callerid);
  2220. if((callerid != NULL)&&(!res)&&(!ast_strlen_zero(callerid))){
  2221. /* Check for internal contexts and only */
  2222. /* say extension when the call didn't come from an internal context in the list */
  2223. for(i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
  2224. ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
  2225. if((strcmp(cidinternalcontexts[i], context) == 0))
  2226. break;
  2227. }
  2228. if(i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
  2229. if(!res) {
  2230. snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/greet", context, callerid);
  2231. if (!ast_strlen_zero(prefile)) {
  2232. /* See if we can find a recorded name for this person instead of their extension number */
  2233. if (ast_fileexists(prefile, NULL, NULL) > 0) {
  2234. ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
  2235. if (!callback)
  2236. res = wait_file2(chan, vms, "vm-from");
  2237. res = ast_streamfile(chan, prefile, chan->language) > -1;
  2238. res = ast_waitstream(chan, "");
  2239. } else {
  2240. ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
  2241. /* BB: Say "from extension" as one saying to sound smoother */
  2242. if (!callback)
  2243. res = wait_file2(chan, vms, "vm-from-extension");
  2244. res = ast_say_digit_str(chan, callerid, "", chan->language);
  2245. }
  2246. }
  2247. }
  2248. }
  2249. else if (!res){
  2250. ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
  2251. /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
  2252. if (!callback)
  2253. res = wait_file2(chan, vms, "vm-from-phonenumber");
  2254. res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
  2255. }
  2256. }
  2257. else{
  2258. /* Number unknown */
  2259. ast_log(LOG_DEBUG, "VM-CID: From an unknown number");
  2260. if(!res)
  2261. /* BB: Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
  2262. res = wait_file2(chan, vms, "vm-unknown-caller");
  2263. }
  2264. return res;
  2265. }
  2266. static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
  2267. {
  2268. int res = 0;
  2269. char filename[256],*origtime, *cid, *context;
  2270. struct ast_config *msg_cfg;
  2271. vms->starting = 0;
  2272. make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
  2273. adsi_message(chan, vms);
  2274. if (!vms->curmsg)
  2275. res = wait_file2(chan, vms, "vm-first"); /* "First" */
  2276. else if (vms->curmsg == vms->lastmsg)
  2277. res = wait_file2(chan, vms, "vm-last"); /* "last" */
  2278. if (!res) {
  2279. res = wait_file2(chan, vms, "vm-message"); /* "message" */
  2280. if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
  2281. if (!res)
  2282. res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
  2283. }
  2284. }
  2285. /* Retrieve info from VM attribute file */
  2286. make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
  2287. snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
  2288. msg_cfg = ast_load(filename);
  2289. if (!msg_cfg) {
  2290. ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
  2291. return 0;
  2292. }
  2293. if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
  2294. return 0;
  2295. cid = ast_variable_retrieve(msg_cfg, "message", "callerid");
  2296. context = ast_variable_retrieve(msg_cfg, "message", "context");
  2297. if(!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */
  2298. context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
  2299. if ((!res)&&(vmu->envelope))
  2300. res = play_message_datetime(chan, vmu, origtime, filename);
  2301. if ((!res)&&(vmu->saycid))
  2302. res = play_message_callerid(chan, vms, cid, context, 0);
  2303. /* Allow pressing '1' to skip envelope / callerid */
  2304. if (res == '1')
  2305. res = 0;
  2306. ast_destroy(msg_cfg);
  2307. if (!res) {
  2308. make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
  2309. vms->heard[vms->curmsg] = 1;
  2310. res = wait_file(chan, vms, vms->fn);
  2311. }
  2312. return res;
  2313. }
  2314. static void open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
  2315. {
  2316. strncpy(vms->curbox, mbox(box), sizeof(vms->curbox) - 1);
  2317. make_dir(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
  2318. vms->lastmsg = count_messages(vms->curdir) - 1;
  2319. /*
  2320. The following test is needed in case sequencing gets messed up.
  2321. There appears to be more than one way to mess up sequence, so
  2322. we will not try to find all of the root causes--just fix it when
  2323. detected.
  2324. */
  2325. if(vms->lastmsg != last_message_index(vms->curdir))
  2326. {
  2327. ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
  2328. resequence_mailbox(vms->curdir);
  2329. }
  2330. snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
  2331. }
  2332. static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
  2333. {
  2334. int x;
  2335. char ntxt[256] = "";
  2336. char txt[256] = "";
  2337. if (vms->lastmsg > -1) {
  2338. /* Get the deleted messages fixed */
  2339. ast_lock_path(vms->curdir);
  2340. vms->curmsg = -1;
  2341. for (x=0;x < MAXMSG;x++) {
  2342. if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
  2343. /* Save this message. It's not in INBOX or hasn't been heard */
  2344. make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
  2345. if (ast_fileexists(vms->fn, NULL, NULL) < 1)
  2346. break;
  2347. vms->curmsg++;
  2348. make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
  2349. if (strcmp(vms->fn, vms->fn2)) {
  2350. snprintf(txt, sizeof(txt), "%s.txt", vms->fn);
  2351. snprintf(ntxt, sizeof(ntxt), "%s.txt", vms->fn2);
  2352. ast_filerename(vms->fn, vms->fn2, NULL);
  2353. rename(txt, ntxt);
  2354. }
  2355. } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
  2356. /* Move to old folder before deleting */
  2357. save_to_folder(vms->curdir, x, vmu->context, vms->username, 1);
  2358. }
  2359. }
  2360. for (x = vms->curmsg + 1; x <= MAXMSG; x++) {
  2361. make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
  2362. if (ast_fileexists(vms->fn, NULL, NULL) < 1)
  2363. break;
  2364. vm_delete(vms->fn);
  2365. }
  2366. ast_unlock_path(vms->curdir);
  2367. }
  2368. if (vms->deleted)
  2369. memset(vms->deleted, 0, sizeof(vms->deleted));
  2370. if (vms->heard)
  2371. memset(vms->heard, 0, sizeof(vms->heard));
  2372. }
  2373. static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
  2374. {
  2375. int cmd;
  2376. if (!strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /*Spanish, French or Portuguese syntax */
  2377. cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
  2378. if (cmd)
  2379. return cmd;
  2380. return ast_play_and_wait(chan, mbox);
  2381. } else { /* Default English */
  2382. cmd = ast_play_and_wait(chan, mbox);
  2383. if (cmd)
  2384. return cmd;
  2385. return ast_play_and_wait(chan, "vm-messages"); /* "messages */
  2386. }
  2387. }
  2388. /* Default English syntax */
  2389. static int vm_intro_en(struct ast_channel *chan,struct vm_state *vms)
  2390. {
  2391. /* Introduce messages they have */
  2392. int res;
  2393. res = ast_play_and_wait(chan, "vm-youhave");
  2394. if (!res) {
  2395. if (vms->newmessages) {
  2396. res = say_and_wait(chan, vms->newmessages, chan->language);
  2397. if (!res)
  2398. res = ast_play_and_wait(chan, "vm-INBOX");
  2399. if (vms->oldmessages && !res)
  2400. res = ast_play_and_wait(chan, "vm-and");
  2401. else if (!res) {
  2402. if ((vms->newmessages == 1))
  2403. res = ast_play_and_wait(chan, "vm-message");
  2404. else
  2405. res = ast_play_and_wait(chan, "vm-messages");
  2406. }
  2407. }
  2408. if (!res && vms->oldmessages) {
  2409. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2410. if (!res)
  2411. res = ast_play_and_wait(chan, "vm-Old");
  2412. if (!res) {
  2413. if (vms->oldmessages == 1)
  2414. res = ast_play_and_wait(chan, "vm-message");
  2415. else
  2416. res = ast_play_and_wait(chan, "vm-messages");
  2417. }
  2418. }
  2419. if (!res) {
  2420. if (!vms->oldmessages && !vms->newmessages) {
  2421. res = ast_play_and_wait(chan, "vm-no");
  2422. if (!res)
  2423. res = ast_play_and_wait(chan, "vm-messages");
  2424. }
  2425. }
  2426. }
  2427. return res;
  2428. }
  2429. /* GERMAN syntax */
  2430. static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
  2431. {
  2432. /* Introduce messages they have */
  2433. int res;
  2434. res = ast_play_and_wait(chan, "vm-youhave");
  2435. if (!res) {
  2436. if (vms->newmessages) {
  2437. if ((vms->newmessages == 1))
  2438. res = ast_play_and_wait(chan, "digits/1F");
  2439. else
  2440. res = say_and_wait(chan, vms->newmessages, chan->language);
  2441. if (!res)
  2442. res = ast_play_and_wait(chan, "vm-INBOX");
  2443. if (vms->oldmessages && !res)
  2444. res = ast_play_and_wait(chan, "vm-and");
  2445. else if (!res) {
  2446. if ((vms->newmessages == 1))
  2447. res = ast_play_and_wait(chan, "vm-message");
  2448. else
  2449. res = ast_play_and_wait(chan, "vm-messages");
  2450. }
  2451. }
  2452. if (!res && vms->oldmessages) {
  2453. if (vms->oldmessages == 1)
  2454. res = ast_play_and_wait(chan, "digits/1F");
  2455. else
  2456. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2457. if (!res)
  2458. res = ast_play_and_wait(chan, "vm-Old");
  2459. if (!res) {
  2460. if (vms->oldmessages == 1)
  2461. res = ast_play_and_wait(chan, "vm-message");
  2462. else
  2463. res = ast_play_and_wait(chan, "vm-messages");
  2464. }
  2465. }
  2466. if (!res) {
  2467. if (!vms->oldmessages && !vms->newmessages) {
  2468. res = ast_play_and_wait(chan, "vm-no");
  2469. if (!res)
  2470. res = ast_play_and_wait(chan, "vm-messages");
  2471. }
  2472. }
  2473. }
  2474. return res;
  2475. }
  2476. /* SPANISH syntax */
  2477. static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
  2478. {
  2479. /* Introduce messages they have */
  2480. int res;
  2481. if (!vms->oldmessages && !vms->newmessages) {
  2482. res = ast_play_and_wait(chan, "vm-youhaveno");
  2483. if (!res)
  2484. res = ast_play_and_wait(chan, "vm-messages");
  2485. } else {
  2486. res = ast_play_and_wait(chan, "vm-youhave");
  2487. }
  2488. if (!res) {
  2489. if (vms->newmessages) {
  2490. if (!res) {
  2491. if ((vms->newmessages == 1)) {
  2492. res = ast_play_and_wait(chan, "digits/1M");
  2493. if (!res)
  2494. res = ast_play_and_wait(chan, "vm-message");
  2495. if (!res)
  2496. res = ast_play_and_wait(chan, "vm-INBOXs");
  2497. } else {
  2498. res = say_and_wait(chan, vms->newmessages, chan->language);
  2499. if (!res)
  2500. res = ast_play_and_wait(chan, "vm-messages");
  2501. if (!res)
  2502. res = ast_play_and_wait(chan, "vm-INBOX");
  2503. }
  2504. }
  2505. if (vms->oldmessages && !res)
  2506. res = ast_play_and_wait(chan, "vm-and");
  2507. }
  2508. if (vms->oldmessages) {
  2509. if (!res) {
  2510. if (vms->oldmessages == 1) {
  2511. res = ast_play_and_wait(chan, "digits/1M");
  2512. if (!res)
  2513. res = ast_play_and_wait(chan, "vm-message");
  2514. if (!res)
  2515. res = ast_play_and_wait(chan, "vm-Olds");
  2516. } else {
  2517. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2518. if (!res)
  2519. res = ast_play_and_wait(chan, "vm-messages");
  2520. if (!res)
  2521. res = ast_play_and_wait(chan, "vm-Old");
  2522. }
  2523. }
  2524. }
  2525. }
  2526. return res;
  2527. }
  2528. /* FRENCH syntax */
  2529. static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
  2530. {
  2531. /* Introduce messages they have */
  2532. int res;
  2533. res = ast_play_and_wait(chan, "vm-youhave");
  2534. if (!res) {
  2535. if (vms->newmessages) {
  2536. res = say_and_wait(chan, vms->newmessages, chan->language);
  2537. if (!res)
  2538. res = ast_play_and_wait(chan, "vm-INBOX");
  2539. if (vms->oldmessages && !res)
  2540. res = ast_play_and_wait(chan, "vm-and");
  2541. else if (!res) {
  2542. if ((vms->newmessages == 1))
  2543. res = ast_play_and_wait(chan, "vm-message");
  2544. else
  2545. res = ast_play_and_wait(chan, "vm-messages");
  2546. }
  2547. }
  2548. if (!res && vms->oldmessages) {
  2549. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2550. if (!res) {
  2551. if (vms->oldmessages == 1)
  2552. res = ast_play_and_wait(chan, "vm-message");
  2553. else
  2554. res = ast_play_and_wait(chan, "vm-messages");
  2555. }
  2556. if (!res)
  2557. res = ast_play_and_wait(chan, "vm-Old");
  2558. }
  2559. if (!res) {
  2560. if (!vms->oldmessages && !vms->newmessages) {
  2561. res = ast_play_and_wait(chan, "vm-no");
  2562. if (!res)
  2563. res = ast_play_and_wait(chan, "vm-messages");
  2564. }
  2565. }
  2566. }
  2567. return res;
  2568. }
  2569. /* DUTCH syntax */
  2570. static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
  2571. {
  2572. /* Introduce messages they have */
  2573. int res;
  2574. res = ast_play_and_wait(chan, "vm-youhave");
  2575. if (!res) {
  2576. if (vms->newmessages) {
  2577. res = say_and_wait(chan, vms->newmessages, chan->language);
  2578. if (!res) {
  2579. if (vms->oldmessages == 1)
  2580. res = ast_play_and_wait(chan, "vm-INBOXs");
  2581. else
  2582. res = ast_play_and_wait(chan, "vm-INBOX");
  2583. }
  2584. if (vms->oldmessages && !res)
  2585. res = ast_play_and_wait(chan, "vm-and");
  2586. else if (!res) {
  2587. if ((vms->newmessages == 1))
  2588. res = ast_play_and_wait(chan, "vm-message");
  2589. else
  2590. res = ast_play_and_wait(chan, "vm-messages");
  2591. }
  2592. }
  2593. if (!res && vms->oldmessages) {
  2594. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2595. if (!res) {
  2596. if (vms->oldmessages == 1)
  2597. res = ast_play_and_wait(chan, "vm-Olds");
  2598. else
  2599. res = ast_play_and_wait(chan, "vm-Old");
  2600. }
  2601. if (!res) {
  2602. if (vms->oldmessages == 1)
  2603. res = ast_play_and_wait(chan, "vm-message");
  2604. else
  2605. res = ast_play_and_wait(chan, "vm-messages");
  2606. }
  2607. }
  2608. if (!res) {
  2609. if (!vms->oldmessages && !vms->newmessages) {
  2610. res = ast_play_and_wait(chan, "vm-no");
  2611. if (!res)
  2612. res = ast_play_and_wait(chan, "vm-messages");
  2613. }
  2614. }
  2615. }
  2616. return res;
  2617. }
  2618. /* PORTUGUESE syntax */
  2619. static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
  2620. {
  2621. /* Introduce messages they have */
  2622. int res;
  2623. res = ast_play_and_wait(chan, "vm-youhave");
  2624. if (!res) {
  2625. if (vms->newmessages) {
  2626. res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
  2627. if (!res) {
  2628. if ((vms->newmessages == 1)) {
  2629. res = ast_play_and_wait(chan, "vm-message");
  2630. if (!res)
  2631. res = ast_play_and_wait(chan, "vm-INBOXs");
  2632. } else {
  2633. res = ast_play_and_wait(chan, "vm-messages");
  2634. if (!res)
  2635. res = ast_play_and_wait(chan, "vm-INBOX");
  2636. }
  2637. }
  2638. if (vms->oldmessages && !res)
  2639. res = ast_play_and_wait(chan, "vm-and");
  2640. }
  2641. if (!res && vms->oldmessages) {
  2642. res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
  2643. if (!res) {
  2644. if (vms->oldmessages == 1) {
  2645. res = ast_play_and_wait(chan, "vm-message");
  2646. if (!res)
  2647. res = ast_play_and_wait(chan, "vm-Olds");
  2648. } else {
  2649. res = ast_play_and_wait(chan, "vm-messages");
  2650. if (!res)
  2651. res = ast_play_and_wait(chan, "vm-Old");
  2652. }
  2653. }
  2654. }
  2655. if (!res) {
  2656. if (!vms->oldmessages && !vms->newmessages) {
  2657. res = ast_play_and_wait(chan, "vm-no");
  2658. if (!res)
  2659. res = ast_play_and_wait(chan, "vm-messages");
  2660. }
  2661. }
  2662. }
  2663. return res;
  2664. }
  2665. /* CZECH syntax */
  2666. /* in czech there must be declension of word new and message
  2667. * czech : english : czech : english
  2668. * --------------------------------------------------------
  2669. * vm-youhave : you have
  2670. * vm-novou : one new : vm-zpravu : message
  2671. * vm-nove : 2-4 new : vm-zpravy : messages
  2672. * vm-novych : 5-infinite new : vm-zprav : messages
  2673. * vm-starou : one old
  2674. * vm-stare : 2-4 old
  2675. * vm-starych : 5-infinite old
  2676. * jednu : one - falling 4.
  2677. * vm-no : no ( no messages )
  2678. */
  2679. static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
  2680. {
  2681. int res;
  2682. res = ast_play_and_wait(chan, "vm-youhave");
  2683. if (!res) {
  2684. if (vms->newmessages) {
  2685. if (vms->newmessages == 1) {
  2686. res = ast_play_and_wait(chan, "digits/jednu");
  2687. } else {
  2688. res = say_and_wait(chan, vms->newmessages, chan->language);
  2689. }
  2690. if (!res) {
  2691. if ((vms->newmessages == 1))
  2692. res = ast_play_and_wait(chan, "vm-novou");
  2693. if ((vms->newmessages) > 1 && (vms->newmessages < 5))
  2694. res = ast_play_and_wait(chan, "vm-nove");
  2695. if (vms->newmessages > 4)
  2696. res = ast_play_and_wait(chan, "vm-novych");
  2697. }
  2698. if (vms->oldmessages && !res)
  2699. res = ast_play_and_wait(chan, "vm-and");
  2700. else if (!res) {
  2701. if ((vms->newmessages == 1))
  2702. res = ast_play_and_wait(chan, "vm-zpravu");
  2703. if ((vms->newmessages) > 1 && (vms->newmessages < 5))
  2704. res = ast_play_and_wait(chan, "vm-zpravy");
  2705. if (vms->newmessages > 4)
  2706. res = ast_play_and_wait(chan, "vm-zprav");
  2707. }
  2708. }
  2709. if (!res && vms->oldmessages) {
  2710. res = say_and_wait(chan, vms->oldmessages, chan->language);
  2711. if (!res) {
  2712. if ((vms->oldmessages == 1))
  2713. res = ast_play_and_wait(chan, "vm-starou");
  2714. if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
  2715. res = ast_play_and_wait(chan, "vm-stare");
  2716. if (vms->oldmessages > 4)
  2717. res = ast_play_and_wait(chan, "vm-starych");
  2718. }
  2719. if (!res) {
  2720. if ((vms->oldmessages == 1))
  2721. res = ast_play_and_wait(chan, "vm-zpravu");
  2722. if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
  2723. res = ast_play_and_wait(chan, "vm-zpravy");
  2724. if (vms->oldmessages > 4)
  2725. res = ast_play_and_wait(chan, "vm-zprav");
  2726. }
  2727. }
  2728. if (!res) {
  2729. if (!vms->oldmessages && !vms->newmessages) {
  2730. res = ast_play_and_wait(chan, "vm-no");
  2731. if (!res)
  2732. res = ast_play_and_wait(chan, "vm-zpravy");
  2733. }
  2734. }
  2735. }
  2736. return res;
  2737. }
  2738. static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
  2739. {
  2740. /* Play voicemail intro - syntax is different for different languages */
  2741. if (!strcasecmp(chan->language, "de")) { /* GERMAN syntax */
  2742. return vm_intro_de(chan, vms);
  2743. } else if (!strcasecmp(chan->language, "es")) { /* SPANISH syntax */
  2744. return vm_intro_es(chan, vms);
  2745. } else if (!strcasecmp(chan->language, "fr")) { /* FRENCH syntax */
  2746. return vm_intro_fr(chan, vms);
  2747. } else if (!strcasecmp(chan->language, "nl")) { /* DUTCH syntax */
  2748. return vm_intro_nl(chan, vms);
  2749. } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE syntax */
  2750. return vm_intro_pt(chan, vms);
  2751. } else if (!strcasecmp(chan->language, "cz")) { /* CZECH syntax */
  2752. return vm_intro_cz(chan, vms);
  2753. } else { /* Default to ENGLISH */
  2754. return vm_intro_en(chan, vms);
  2755. }
  2756. }
  2757. static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
  2758. {
  2759. int res = 0;
  2760. /* Play instructions and wait for new command */
  2761. while(!res) {
  2762. if (vms->starting) {
  2763. if (vms->lastmsg > -1) {
  2764. res = ast_play_and_wait(chan, "vm-onefor");
  2765. if (!res)
  2766. res = vm_play_folder_name(chan, vms->vmbox);
  2767. }
  2768. if (!res)
  2769. res = ast_play_and_wait(chan, "vm-opts");
  2770. } else {
  2771. if (vms->curmsg)
  2772. res = ast_play_and_wait(chan, "vm-prev");
  2773. if (!res && !skipadvanced)
  2774. res = ast_play_and_wait(chan, "vm-advopts");
  2775. if (!res)
  2776. res = ast_play_and_wait(chan, "vm-repeat");
  2777. if (!res && (vms->curmsg != vms->lastmsg))
  2778. res = ast_play_and_wait(chan, "vm-next");
  2779. if (!res) {
  2780. if (!vms->deleted[vms->curmsg])
  2781. res = ast_play_and_wait(chan, "vm-delete");
  2782. else
  2783. res = ast_play_and_wait(chan, "vm-undelete");
  2784. if (!res)
  2785. res = ast_play_and_wait(chan, "vm-toforward");
  2786. if (!res)
  2787. res = ast_play_and_wait(chan, "vm-savemessage");
  2788. }
  2789. }
  2790. if (!res)
  2791. res = ast_play_and_wait(chan, "vm-helpexit");
  2792. if (!res)
  2793. res = ast_waitfordigit(chan, 6000);
  2794. if (!res) {
  2795. vms->repeats++;
  2796. if (vms->repeats > 2) {
  2797. res = 't';
  2798. }
  2799. }
  2800. }
  2801. return res;
  2802. }
  2803. static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc)
  2804. {
  2805. int cmd = 0;
  2806. int retries = 0;
  2807. int duration = 0;
  2808. char newpassword[80] = "";
  2809. char newpassword2[80] = "";
  2810. char prefile[256]="";
  2811. char buf[256];
  2812. int bytes=0;
  2813. if (adsi_available(chan))
  2814. {
  2815. bytes += adsi_logo(buf + bytes);
  2816. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
  2817. bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
  2818. bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
  2819. bytes += adsi_voice_mode(buf + bytes, 0);
  2820. adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
  2821. }
  2822. while((cmd >= 0) && (cmd != 't')) {
  2823. if (cmd)
  2824. retries = 0;
  2825. switch (cmd) {
  2826. case '1':
  2827. snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
  2828. cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
  2829. break;
  2830. case '2':
  2831. snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
  2832. cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
  2833. break;
  2834. case '3':
  2835. snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
  2836. cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
  2837. break;
  2838. case '4':
  2839. if (vmu->password[0] == '-') {
  2840. cmd = ast_play_and_wait(chan, "vm-no");
  2841. break;
  2842. }
  2843. newpassword[1] = '\0';
  2844. newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
  2845. if (cmd == '#')
  2846. newpassword[0] = '\0';
  2847. else {
  2848. if (cmd < 0)
  2849. break;
  2850. if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0)
  2851. break;
  2852. }
  2853. newpassword2[1] = '\0';
  2854. newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
  2855. if (cmd == '#')
  2856. newpassword2[0] = '\0';
  2857. else {
  2858. if (cmd < 0)
  2859. break;
  2860. if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")))
  2861. break;
  2862. }
  2863. if (strcmp(newpassword, newpassword2)) {
  2864. ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
  2865. cmd = ast_play_and_wait(chan, "vm-mismatch");
  2866. break;
  2867. }
  2868. if(ast_strlen_zero(ext_pass_cmd))
  2869. vm_change_password(vmu,newpassword);
  2870. else
  2871. vm_change_password_shell(vmu,newpassword);
  2872. ast_log(LOG_DEBUG,"User %s set password to %s of length %i\n",vms->username,newpassword,(int)strlen(newpassword));
  2873. cmd = ast_play_and_wait(chan,"vm-passchanged");
  2874. break;
  2875. case '*':
  2876. cmd = 't';
  2877. break;
  2878. default:
  2879. cmd = ast_play_and_wait(chan,"vm-options");
  2880. if (!cmd)
  2881. cmd = ast_waitfordigit(chan,6000);
  2882. if (!cmd)
  2883. retries++;
  2884. if (retries > 3)
  2885. cmd = 't';
  2886. }
  2887. }
  2888. if (cmd == 't')
  2889. cmd = 0;
  2890. return cmd;
  2891. }
  2892. /* Default English syntax */
  2893. static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
  2894. {
  2895. int cmd=0;
  2896. if (vms->lastmsg > -1) {
  2897. cmd = play_message(chan, vmu, vms);
  2898. } else {
  2899. cmd = ast_play_and_wait(chan, "vm-youhave");
  2900. if (!cmd)
  2901. cmd = ast_play_and_wait(chan, "vm-no");
  2902. if (!cmd) {
  2903. snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
  2904. cmd = ast_play_and_wait(chan, vms->fn);
  2905. }
  2906. if (!cmd)
  2907. cmd = ast_play_and_wait(chan, "vm-messages");
  2908. }
  2909. return cmd;
  2910. }
  2911. /* SPANISH syntax */
  2912. static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
  2913. {
  2914. int cmd=0;
  2915. if (vms->lastmsg > -1) {
  2916. cmd = play_message(chan, vmu, vms);
  2917. } else {
  2918. cmd = ast_play_and_wait(chan, "vm-youhaveno");
  2919. if (!cmd)
  2920. cmd = ast_play_and_wait(chan, "vm-messages");
  2921. if (!cmd) {
  2922. snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
  2923. cmd = ast_play_and_wait(chan, vms->fn);
  2924. }
  2925. }
  2926. return cmd;
  2927. }
  2928. /* PORTUGUESE syntax */
  2929. static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
  2930. {
  2931. int cmd=0;
  2932. if (vms->lastmsg > -1) {
  2933. cmd = play_message(chan, vmu, vms);
  2934. } else {
  2935. cmd = ast_play_and_wait(chan, "vm-no");
  2936. if (!cmd) {
  2937. snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
  2938. cmd = ast_play_and_wait(chan, vms->fn);
  2939. }
  2940. if (!cmd)
  2941. cmd = ast_play_and_wait(chan, "vm-messages");
  2942. }
  2943. return cmd;
  2944. }
  2945. static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
  2946. {
  2947. if (!strcasecmp(chan->language, "es")) { /* SPANISH */
  2948. return vm_browse_messages_es(chan, vms, vmu);
  2949. } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE */
  2950. return vm_browse_messages_pt(chan, vms, vmu);
  2951. } else { /* Default to English syntax */
  2952. return vm_browse_messages_en(chan, vms, vmu);
  2953. }
  2954. }
  2955. static int vm_execmain(struct ast_channel *chan, void *data)
  2956. {
  2957. /* XXX This is, admittedly, some pretty horrendus code. For some
  2958. reason it just seemed a lot easier to do with GOTO's. I feel
  2959. like I'm back in my GWBASIC days. XXX */
  2960. int res=-1;
  2961. int valid = 0;
  2962. int prefix = 0;
  2963. int cmd=0;
  2964. struct localuser *u;
  2965. char prefixstr[80] ="";
  2966. char empty[80] = "";
  2967. char ext_context[256]="";
  2968. int box;
  2969. int useadsi = 0;
  2970. int skipuser = 0;
  2971. char tmp[256], *ext;
  2972. char fmtc[256] = "";
  2973. char password[80];
  2974. struct vm_state vms;
  2975. int logretries = 0;
  2976. struct ast_vm_user *vmu = NULL, vmus;
  2977. char *context=NULL;
  2978. int silentexit = 0;
  2979. char cid[256]="";
  2980. char *passptr;
  2981. LOCAL_USER_ADD(u);
  2982. memset(&vms, 0, sizeof(vms));
  2983. memset(&vmus, 0, sizeof(vmus));
  2984. strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
  2985. if (chan->_state != AST_STATE_UP)
  2986. ast_answer(chan);
  2987. if (data && !ast_strlen_zero(data)) {
  2988. strncpy(tmp, data, sizeof(tmp) - 1);
  2989. ext = tmp;
  2990. switch (*ext) {
  2991. case 's':
  2992. /* We should skip the user's password */
  2993. valid++;
  2994. ext++;
  2995. break;
  2996. case 'p':
  2997. /* We should prefix the mailbox with the supplied data */
  2998. prefix++;
  2999. ext++;
  3000. break;
  3001. }
  3002. context = strchr(ext, '@');
  3003. if (context) {
  3004. *context = '\0';
  3005. context++;
  3006. }
  3007. if (prefix)
  3008. strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
  3009. else
  3010. strncpy(vms.username, ext, sizeof(vms.username) - 1);
  3011. if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
  3012. skipuser++;
  3013. else
  3014. valid = 0;
  3015. }
  3016. /* If ADSI is supported, setup login screen */
  3017. adsi_begin(chan, &useadsi);
  3018. if (!skipuser && useadsi)
  3019. adsi_login(chan);
  3020. if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
  3021. ast_log(LOG_WARNING, "Couldn't stream login file\n");
  3022. goto out;
  3023. }
  3024. /* Authenticate them and get their mailbox/password */
  3025. while (!valid && (logretries < maxlogins)) {
  3026. /* Prompt for, and read in the username */
  3027. if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
  3028. ast_log(LOG_WARNING, "Couldn't read username\n");
  3029. goto out;
  3030. }
  3031. if (ast_strlen_zero(vms.username)) {
  3032. char *callerid=NULL, *name=NULL;
  3033. if(chan->callerid != NULL) {
  3034. strncpy(cid, chan->callerid, sizeof(cid) - 1);
  3035. ast_callerid_parse(cid, &name, &callerid);
  3036. }
  3037. if(callerid != NULL) {
  3038. if (option_verbose > 2)
  3039. ast_verbose(VERBOSE_PREFIX_3 "No username but # key pressed. Using CID '%s'\n",callerid);
  3040. strncpy(vms.username, callerid, sizeof(vms.username) - 1);
  3041. } else {
  3042. if (option_verbose > 2)
  3043. ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
  3044. res = 0;
  3045. goto out;
  3046. }
  3047. }
  3048. if (useadsi)
  3049. adsi_password(chan);
  3050. if (!skipuser)
  3051. vmu = find_user(&vmus, context, vms.username);
  3052. if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
  3053. /* saved password is blank, so don't bother asking */
  3054. password[0] = '\0';
  3055. } else {
  3056. if (ast_streamfile(chan, "vm-password", chan->language)) {
  3057. ast_log(LOG_WARNING, "Unable to stream password file\n");
  3058. goto out;
  3059. }
  3060. if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
  3061. ast_log(LOG_WARNING, "Unable to read password\n");
  3062. goto out;
  3063. }
  3064. }
  3065. if (prefix && !ast_strlen_zero(prefixstr)) {
  3066. char fullusername[80] = "";
  3067. strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
  3068. strncat(fullusername, vms.username, sizeof(fullusername) - 1);
  3069. strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
  3070. }
  3071. if (vmu) {
  3072. passptr = vmu->password;
  3073. if (passptr[0] == '-') passptr++;
  3074. }
  3075. if (vmu && !strcmp(passptr, password))
  3076. valid++;
  3077. else {
  3078. if (option_verbose > 2)
  3079. ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
  3080. if (prefix)
  3081. strncpy(vms.username, empty, sizeof(vms.username) -1);
  3082. }
  3083. logretries++;
  3084. if (!valid) {
  3085. if (skipuser || logretries >= maxlogins) {
  3086. if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
  3087. ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
  3088. return -1;
  3089. }
  3090. } else {
  3091. if (useadsi)
  3092. adsi_login(chan);
  3093. if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
  3094. ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
  3095. return -1;
  3096. }
  3097. }
  3098. if (ast_waitstream(chan, "")) /* Channel is hung up */
  3099. return -1;
  3100. }
  3101. }
  3102. if (!valid && (logretries >= maxlogins)) {
  3103. ast_stopstream(chan);
  3104. res = ast_play_and_wait(chan, "vm-goodbye");
  3105. if (res > 0)
  3106. res = 0;
  3107. }
  3108. if (valid) {
  3109. /* Set language from config to override channel language */
  3110. if (vmu->language && !ast_strlen_zero(vmu->language))
  3111. strncpy(chan->language, vmu->language, sizeof(chan->language)-1);
  3112. snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context);
  3113. mkdir(vms.curdir, 0700);
  3114. snprintf(vms.curdir, sizeof(vms.curdir), "%s/voicemail/%s/%s", (char *)ast_config_AST_SPOOL_DIR, vmu->context, vms.username);
  3115. mkdir(vms.curdir, 0700);
  3116. /* Retrieve old and new message counts */
  3117. open_mailbox(&vms, vmu, 1);
  3118. vms.oldmessages = vms.lastmsg + 1;
  3119. /* Start in INBOX */
  3120. open_mailbox(&vms, vmu, 0);
  3121. vms.newmessages = vms.lastmsg + 1;
  3122. /* Select proper mailbox FIRST!! */
  3123. if (!vms.newmessages && vms.oldmessages) {
  3124. /* If we only have old messages start here */
  3125. open_mailbox(&vms, vmu, 1);
  3126. }
  3127. if (useadsi)
  3128. adsi_status(chan, &vms);
  3129. res = 0;
  3130. cmd = vm_intro(chan, &vms);
  3131. vms.repeats = 0;
  3132. vms.starting = 1;
  3133. while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
  3134. /* Run main menu */
  3135. switch(cmd) {
  3136. case '1':
  3137. vms.curmsg = 0;
  3138. /* Fall through */
  3139. case '5':
  3140. cmd = vm_browse_messages(chan, &vms, vmu);
  3141. break;
  3142. case '2': /* Change folders */
  3143. if (useadsi)
  3144. adsi_folders(chan, 0, "Change to folder...");
  3145. cmd = get_folder2(chan, "vm-changeto", 0);
  3146. if (cmd == '#') {
  3147. cmd = 0;
  3148. } else if (cmd > 0) {
  3149. cmd = cmd - '0';
  3150. close_mailbox(&vms, vmu);
  3151. open_mailbox(&vms, vmu, cmd);
  3152. cmd = 0;
  3153. }
  3154. if (useadsi)
  3155. adsi_status2(chan, &vms);
  3156. if (!cmd)
  3157. cmd = vm_play_folder_name(chan, vms.vmbox);
  3158. vms.starting = 1;
  3159. break;
  3160. case '3': /* Advanced options */
  3161. cmd = 0;
  3162. vms.repeats = 0;
  3163. while((cmd > -1) && (cmd != 't') && (cmd != '#')) {
  3164. switch(cmd) {
  3165. case '1': /* Reply */
  3166. if(vms.lastmsg > -1)
  3167. cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1);
  3168. else
  3169. cmd = ast_play_and_wait(chan, "vm-sorry");
  3170. cmd = 't';
  3171. break;
  3172. case '2': /* Callback */
  3173. ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
  3174. if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1) {
  3175. cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2);
  3176. if (cmd == 9) {
  3177. silentexit = 1;
  3178. goto out;
  3179. }
  3180. }
  3181. else
  3182. cmd = ast_play_and_wait(chan, "vm-sorry");
  3183. cmd = 't';
  3184. break;
  3185. case '3': /* Envelope */
  3186. if(vms.lastmsg > -1)
  3187. cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3);
  3188. else
  3189. cmd = ast_play_and_wait(chan, "vm-sorry");
  3190. cmd = 't';
  3191. break;
  3192. case '4': /* Dialout */
  3193. if (!ast_strlen_zero(vmu->dialout)) {
  3194. cmd = dialout(chan, vmu, NULL, vmu->dialout);
  3195. if (cmd == 9) {
  3196. silentexit = 1;
  3197. goto out;
  3198. }
  3199. }
  3200. else
  3201. cmd = ast_play_and_wait(chan, "vm-sorry");
  3202. cmd = 't';
  3203. break;
  3204. case '5': /* Leave VoiceMail */
  3205. if(vmu->svmail)
  3206. cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts,1);
  3207. else
  3208. cmd = ast_play_and_wait(chan,"vm-sorry");
  3209. cmd='t';
  3210. break;
  3211. case '*': /* Return to main menu */
  3212. cmd = 't';
  3213. break;
  3214. default:
  3215. cmd = 0;
  3216. if (!vms.starting) {
  3217. cmd = ast_play_and_wait(chan, "vm-toreply");
  3218. }
  3219. if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
  3220. cmd = ast_play_and_wait(chan, "vm-tocallback");
  3221. }
  3222. if (!cmd && !vms.starting) {
  3223. cmd = ast_play_and_wait(chan, "vm-tohearenv");
  3224. }
  3225. if (!ast_strlen_zero(vmu->dialout) && !cmd) {
  3226. cmd = ast_play_and_wait(chan, "vm-tomakecall");
  3227. }
  3228. if(vmu->svmail&&!cmd)
  3229. cmd=ast_play_and_wait(chan, "vm-leavemsg");
  3230. if (!cmd)
  3231. cmd = ast_play_and_wait(chan, "vm-starmain");
  3232. if (!cmd)
  3233. cmd = ast_waitfordigit(chan,6000);
  3234. if (!cmd)
  3235. vms.repeats++;
  3236. if (vms.repeats > 3)
  3237. cmd = 't';
  3238. }
  3239. }
  3240. if (cmd == 't') {
  3241. cmd = 0;
  3242. vms.repeats = 0;
  3243. }
  3244. break;
  3245. case '4':
  3246. if (vms.curmsg) {
  3247. vms.curmsg--;
  3248. cmd = play_message(chan, vmu, &vms);
  3249. } else {
  3250. cmd = ast_play_and_wait(chan, "vm-nomore");
  3251. }
  3252. break;
  3253. case '6':
  3254. if (vms.curmsg < vms.lastmsg) {
  3255. vms.curmsg++;
  3256. cmd = play_message(chan, vmu, &vms);
  3257. } else {
  3258. cmd = ast_play_and_wait(chan, "vm-nomore");
  3259. }
  3260. break;
  3261. case '7':
  3262. vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
  3263. if (useadsi)
  3264. adsi_delete(chan, &vms);
  3265. if (vms.deleted[vms.curmsg])
  3266. cmd = ast_play_and_wait(chan, "vm-deleted");
  3267. else
  3268. cmd = ast_play_and_wait(chan, "vm-undeleted");
  3269. if (skipaftercmd) {
  3270. if (vms.curmsg < vms.lastmsg) {
  3271. vms.curmsg++;
  3272. cmd = play_message(chan, vmu, &vms);
  3273. } else {
  3274. cmd = ast_play_and_wait(chan, "vm-nomore");
  3275. }
  3276. }
  3277. break;
  3278. case '8':
  3279. if(vms.lastmsg > -1)
  3280. cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts,0);
  3281. else
  3282. cmd = ast_play_and_wait(chan, "vm-nomore");
  3283. break;
  3284. case '9':
  3285. if (useadsi)
  3286. adsi_folders(chan, 1, "Save to folder...");
  3287. cmd = get_folder2(chan, "vm-savefolder", 1);
  3288. box = 0; /* Shut up compiler */
  3289. if (cmd == '#') {
  3290. cmd = 0;
  3291. break;
  3292. } else if (cmd > 0) {
  3293. box = cmd = cmd - '0';
  3294. cmd = save_to_folder(vms.curdir, vms.curmsg, vmu->context, vms.username, cmd);
  3295. vms.deleted[vms.curmsg]=1;
  3296. }
  3297. make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
  3298. if (useadsi)
  3299. adsi_message(chan, &vms);
  3300. if (!cmd)
  3301. cmd = ast_play_and_wait(chan, "vm-message");
  3302. if (!cmd)
  3303. cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
  3304. if (!cmd)
  3305. cmd = ast_play_and_wait(chan, "vm-savedto");
  3306. snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
  3307. if (!cmd)
  3308. cmd = vm_play_folder_name(chan, vms.fn);
  3309. if (skipaftercmd) {
  3310. if (vms.curmsg < vms.lastmsg) {
  3311. vms.curmsg++;
  3312. cmd = play_message(chan, vmu, &vms);
  3313. } else {
  3314. cmd = ast_play_and_wait(chan, "vm-nomore");
  3315. }
  3316. }
  3317. break;
  3318. case '*':
  3319. if (!vms.starting) {
  3320. cmd = ast_play_and_wait(chan, "vm-onefor");
  3321. if (!cmd)
  3322. cmd = vm_play_folder_name(chan, vms.vmbox);
  3323. if (!cmd)
  3324. cmd = ast_play_and_wait(chan, "vm-opts");
  3325. if (!cmd)
  3326. cmd = vm_instructions(chan, &vms, 1);
  3327. } else
  3328. cmd = 0;
  3329. break;
  3330. case '0':
  3331. cmd = vm_options(chan, vmu, &vms, vmfmts);
  3332. if (useadsi)
  3333. adsi_status(chan, &vms);
  3334. break;
  3335. default: /* Nothing */
  3336. cmd = vm_instructions(chan, &vms, 0);
  3337. break;
  3338. }
  3339. }
  3340. if ((cmd == 't') || (cmd == '#')) {
  3341. /* Timeout */
  3342. res = 0;
  3343. } else {
  3344. /* Hangup */
  3345. res = -1;
  3346. }
  3347. }
  3348. out:
  3349. if (res > -1) {
  3350. ast_stopstream(chan);
  3351. adsi_goodbye(chan);
  3352. if(valid) {
  3353. if (silentexit)
  3354. res = ast_play_and_wait(chan, "vm-dialout");
  3355. else
  3356. res = ast_play_and_wait(chan, "vm-goodbye");
  3357. if (res > 0)
  3358. res = 0;
  3359. }
  3360. if (useadsi)
  3361. adsi_unload_session(chan);
  3362. }
  3363. if (vmu)
  3364. close_mailbox(&vms, vmu);
  3365. if (valid) {
  3366. snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
  3367. manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
  3368. run_externnotify(chan->context, ext_context);
  3369. }
  3370. if (vmu)
  3371. free_user(vmu);
  3372. LOCAL_USER_REMOVE(u);
  3373. return res;
  3374. }
  3375. static int vm_exec(struct ast_channel *chan, void *data)
  3376. {
  3377. int res=0, silent=0, busy=0, unavail=0;
  3378. struct localuser *u;
  3379. char tmp[256], *ext;
  3380. LOCAL_USER_ADD(u);
  3381. if (chan->_state != AST_STATE_UP)
  3382. ast_answer(chan);
  3383. if (data && !ast_strlen_zero(data))
  3384. strncpy(tmp, data, sizeof(tmp) - 1);
  3385. else {
  3386. res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
  3387. if (res < 0)
  3388. return res;
  3389. if (ast_strlen_zero(tmp))
  3390. return 0;
  3391. }
  3392. ext = tmp;
  3393. while(*ext) {
  3394. if (*ext == 's') {
  3395. silent = 2;
  3396. ext++;
  3397. } else if (*ext == 'b') {
  3398. busy=1;
  3399. ext++;
  3400. } else if (*ext == 'u') {
  3401. unavail=1;
  3402. ext++;
  3403. } else
  3404. break;
  3405. }
  3406. res = leave_voicemail(chan, ext, silent, busy, unavail);
  3407. LOCAL_USER_REMOVE(u);
  3408. return res;
  3409. }
  3410. static int append_mailbox(char *context, char *mbox, char *data)
  3411. {
  3412. /* Assumes lock is already held */
  3413. char tmp[256] = "";
  3414. char *stringp;
  3415. char *s;
  3416. struct ast_vm_user *vmu;
  3417. strncpy(tmp, data, sizeof(tmp) - 1);
  3418. vmu = malloc(sizeof(struct ast_vm_user));
  3419. if (vmu) {
  3420. memset(vmu, 0, sizeof(struct ast_vm_user));
  3421. strncpy(vmu->context, context, sizeof(vmu->context) - 1);
  3422. strncpy(vmu->mailbox, mbox, sizeof(vmu->mailbox) - 1);
  3423. populate_defaults(vmu);
  3424. stringp = tmp;
  3425. if ((s = strsep(&stringp, ",")))
  3426. strncpy(vmu->password, s, sizeof(vmu->password) - 1);
  3427. if (stringp && (s = strsep(&stringp, ",")))
  3428. strncpy(vmu->fullname, s, sizeof(vmu->fullname) - 1);
  3429. if (stringp && (s = strsep(&stringp, ",")))
  3430. strncpy(vmu->email, s, sizeof(vmu->email) - 1);
  3431. if (stringp && (s = strsep(&stringp, ",")))
  3432. strncpy(vmu->pager, s, sizeof(vmu->pager) - 1);
  3433. if (stringp && (s = strsep(&stringp, ",")))
  3434. apply_options(vmu, s);
  3435. vmu->next = NULL;
  3436. if (usersl)
  3437. usersl->next = vmu;
  3438. else
  3439. users = vmu;
  3440. usersl = vmu;
  3441. }
  3442. return 0;
  3443. }
  3444. static int vm_box_exists(struct ast_channel *chan, void *data) {
  3445. struct localuser *u;
  3446. struct ast_vm_user svm;
  3447. char *context, *box;
  3448. char tmp[256];
  3449. if (!data || !strlen(data)) {
  3450. ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context])\n");
  3451. return -1;
  3452. } else {
  3453. strncpy(tmp, data, sizeof(tmp) - 1);
  3454. }
  3455. LOCAL_USER_ADD(u);
  3456. box = tmp;
  3457. while(*box) {
  3458. if ((*box == 's') || (*box == 'b') || (*box == 'u')) {
  3459. box++;
  3460. } else
  3461. break;
  3462. }
  3463. context = strchr(tmp, '@');
  3464. if (context) {
  3465. *context = '\0';
  3466. context++;
  3467. }
  3468. if (find_user(&svm, context, box)) {
  3469. if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
  3470. chan->priority += 100;
  3471. } else
  3472. ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
  3473. }
  3474. LOCAL_USER_REMOVE(u);
  3475. return 0;
  3476. }
  3477. #ifndef USEMYSQLVM
  3478. /* XXX TL Bug 690 */
  3479. static char show_voicemail_users_help[] =
  3480. "Usage: show voicemail users [for <context>]\n"
  3481. " Lists all mailboxes currently set up\n";
  3482. static char show_voicemail_zones_help[] =
  3483. "Usage: show voicemail zones\n"
  3484. " Lists zone message formats\n";
  3485. static int handle_show_voicemail_users(int fd, int argc, char *argv[])
  3486. {
  3487. struct ast_vm_user *vmu = users;
  3488. char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
  3489. if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
  3490. else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
  3491. if (vmu) {
  3492. if (argc == 3)
  3493. ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
  3494. else {
  3495. int count = 0;
  3496. while (vmu) {
  3497. if (!strcmp(argv[4],vmu->context))
  3498. count++;
  3499. vmu = vmu->next;
  3500. }
  3501. if (count) {
  3502. vmu = users;
  3503. ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
  3504. } else {
  3505. ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
  3506. return RESULT_FAILURE;
  3507. }
  3508. }
  3509. while (vmu) {
  3510. char dirname[256];
  3511. DIR *vmdir;
  3512. struct dirent *vment;
  3513. int vmcount = 0;
  3514. char count[12];
  3515. if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
  3516. make_dir(dirname, 255, vmu->context, vmu->mailbox, "INBOX");
  3517. if ((vmdir = opendir(dirname))) {
  3518. /* No matter what the format of VM, there will always be a .txt file for each message. */
  3519. while ((vment = readdir(vmdir)))
  3520. if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
  3521. vmcount++;
  3522. closedir(vmdir);
  3523. }
  3524. snprintf(count,sizeof(count),"%d",vmcount);
  3525. ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
  3526. }
  3527. vmu = vmu->next;
  3528. }
  3529. } else {
  3530. ast_cli(fd, "There are no voicemail users currently defined\n");
  3531. return RESULT_FAILURE;
  3532. }
  3533. return RESULT_SUCCESS;
  3534. }
  3535. static int handle_show_voicemail_zones(int fd, int argc, char *argv[])
  3536. {
  3537. struct vm_zone *zone = zones;
  3538. char *output_format = "%-15s %-20s %-45s\n";
  3539. if (argc != 3) return RESULT_SHOWUSAGE;
  3540. if (zone) {
  3541. ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
  3542. while (zone) {
  3543. ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
  3544. zone = zone->next;
  3545. }
  3546. } else {
  3547. ast_cli(fd, "There are no voicemail zones currently defined\n");
  3548. return RESULT_FAILURE;
  3549. }
  3550. return RESULT_SUCCESS;
  3551. }
  3552. static char *complete_show_voicemail_users(char *line, char *word, int pos, int state)
  3553. {
  3554. int which = 0;
  3555. struct ast_vm_user *vmu = users;
  3556. char *context = "";
  3557. /* 0 - show; 1 - voicemail; 2 - users; 3 - for; 4 - <context> */
  3558. if (pos > 4)
  3559. return NULL;
  3560. if (pos == 3) {
  3561. if (state == 0)
  3562. return strdup("for");
  3563. else
  3564. return NULL;
  3565. }
  3566. while (vmu) {
  3567. if (!strncasecmp(word, vmu->context, strlen(word))) {
  3568. if (context && strcmp(context, vmu->context)) {
  3569. if (++which > state) {
  3570. return strdup(vmu->context);
  3571. }
  3572. context = vmu->context;
  3573. }
  3574. }
  3575. vmu = vmu->next;
  3576. }
  3577. return NULL;
  3578. }
  3579. static struct ast_cli_entry show_voicemail_users_cli =
  3580. { { "show", "voicemail", "users", NULL },
  3581. handle_show_voicemail_users, "List defined voicemail boxes",
  3582. show_voicemail_users_help, complete_show_voicemail_users };
  3583. static struct ast_cli_entry show_voicemail_zones_cli =
  3584. { { "show", "voicemail", "zones", NULL },
  3585. handle_show_voicemail_zones, "List zone message formats",
  3586. show_voicemail_zones_help, NULL };
  3587. #endif
  3588. static int load_config(void)
  3589. {
  3590. struct ast_vm_user *cur, *l;
  3591. struct vm_zone *zcur, *zl;
  3592. struct ast_config *cfg;
  3593. char *cat;
  3594. struct ast_variable *var;
  3595. char *notifystr = NULL;
  3596. char *astattach;
  3597. char *astsaycid;
  3598. char *send_voicemail;
  3599. char *astcallop;
  3600. char *astreview;
  3601. char *astskipcmd;
  3602. char *asthearenv;
  3603. char *silencestr;
  3604. char *thresholdstr;
  3605. char *fmt;
  3606. char *astemail;
  3607. char *astmailcmd = SENDMAIL;
  3608. char *s,*q,*stringp;
  3609. char *dialoutcxt = NULL;
  3610. char *callbackcxt = NULL;
  3611. char *exitcxt = NULL;
  3612. char *extpc;
  3613. int x;
  3614. int tmpadsi[4];
  3615. cfg = ast_load(VOICEMAIL_CONFIG);
  3616. ast_mutex_lock(&vmlock);
  3617. cur = users;
  3618. while(cur) {
  3619. l = cur;
  3620. cur = cur->next;
  3621. l->alloced = 1;
  3622. free_user(l);
  3623. }
  3624. zcur = zones;
  3625. while(zcur) {
  3626. zl = zcur;
  3627. zcur = zcur->next;
  3628. free_zone(zl);
  3629. }
  3630. zones = NULL;
  3631. zonesl = NULL;
  3632. users = NULL;
  3633. usersl = NULL;
  3634. memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
  3635. if (cfg) {
  3636. /* General settings */
  3637. /* Attach voice message to mail message ? */
  3638. attach_voicemail = 1;
  3639. if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
  3640. astattach = "yes";
  3641. attach_voicemail = ast_true(astattach);
  3642. /* Mail command */
  3643. strncpy(mailcmd, SENDMAIL, sizeof(mailcmd) - 1); /* Default */
  3644. if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
  3645. strncpy(mailcmd, astmailcmd, sizeof(mailcmd) - 1); /* User setting */
  3646. maxsilence = 0;
  3647. if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
  3648. maxsilence = atoi(silencestr);
  3649. if (maxsilence > 0)
  3650. maxsilence *= 1000;
  3651. }
  3652. /* External password changing command */
  3653. if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
  3654. strncpy(ext_pass_cmd,extpc,sizeof(ext_pass_cmd) - 1);
  3655. }
  3656. /* External voicemail notify application */
  3657. if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
  3658. strncpy(externnotify, notifystr, sizeof(externnotify) - 1);
  3659. ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
  3660. } else {
  3661. externnotify[0] = '\0';
  3662. }
  3663. /* Silence treshold */
  3664. silencethreshold = 256;
  3665. if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
  3666. silencethreshold = atoi(thresholdstr);
  3667. if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
  3668. astemail = ASTERISK_USERNAME;
  3669. strncpy(serveremail, astemail, sizeof(serveremail) - 1);
  3670. vmmaxmessage = 0;
  3671. if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
  3672. if (sscanf(s, "%d", &x) == 1) {
  3673. vmmaxmessage = x;
  3674. } else {
  3675. ast_log(LOG_WARNING, "Invalid max message time length\n");
  3676. }
  3677. }
  3678. vmminmessage = 0;
  3679. if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
  3680. if (sscanf(s, "%d", &x) == 1) {
  3681. vmminmessage = x;
  3682. if (maxsilence <= vmminmessage)
  3683. ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
  3684. } else {
  3685. ast_log(LOG_WARNING, "Invalid min message time length\n");
  3686. }
  3687. }
  3688. fmt = ast_variable_retrieve(cfg, "general", "format");
  3689. if (!fmt)
  3690. fmt = "wav";
  3691. strncpy(vmfmts, fmt, sizeof(vmfmts) - 1);
  3692. skipms = 3000;
  3693. if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
  3694. if (sscanf(s, "%d", &x) == 1) {
  3695. maxgreet = x;
  3696. } else {
  3697. ast_log(LOG_WARNING, "Invalid max message greeting length\n");
  3698. }
  3699. }
  3700. if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
  3701. if (sscanf(s, "%d", &x) == 1) {
  3702. skipms = x;
  3703. } else {
  3704. ast_log(LOG_WARNING, "Invalid skipms value\n");
  3705. }
  3706. }
  3707. maxlogins = 3;
  3708. if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
  3709. if (sscanf(s, "%d", &x) == 1) {
  3710. maxlogins = x;
  3711. } else {
  3712. ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
  3713. }
  3714. }
  3715. if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
  3716. ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
  3717. stringp = ast_strdupa(s);
  3718. for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
  3719. if ((stringp)&&(!ast_strlen_zero(stringp))){
  3720. q = strsep(&stringp,",");
  3721. while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
  3722. q++;
  3723. strncpy(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]) - 1);
  3724. ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
  3725. } else {
  3726. cidinternalcontexts[x][0] = '\0';
  3727. }
  3728. }
  3729. }
  3730. reviewvm = 0;
  3731. if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
  3732. ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
  3733. astreview = "no";
  3734. }
  3735. reviewvm = ast_true(astreview);
  3736. calloper = 0;
  3737. if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
  3738. ast_log(LOG_DEBUG,"VM Operator break disabled globally\n"); astcallop = "no";
  3739. }
  3740. calloper = ast_true(astcallop);
  3741. saycidinfo = 0;
  3742. if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
  3743. ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
  3744. astsaycid = "no";
  3745. }
  3746. saycidinfo = ast_true(astsaycid);
  3747. svmailinfo =0;
  3748. if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
  3749. ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
  3750. send_voicemail = "no";
  3751. }
  3752. svmailinfo=ast_true(send_voicemail);
  3753. hearenv = 1;
  3754. if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
  3755. ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
  3756. asthearenv = "yes";
  3757. }
  3758. hearenv = ast_true(asthearenv);
  3759. skipaftercmd = 0;
  3760. if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
  3761. ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
  3762. astskipcmd = "no";
  3763. }
  3764. skipaftercmd = ast_true(astskipcmd);
  3765. if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
  3766. strncpy(dialcontext, dialoutcxt, sizeof(dialcontext) - 1);
  3767. ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
  3768. } else {
  3769. dialcontext[0] = '\0';
  3770. }
  3771. if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
  3772. strncpy(callcontext, callbackcxt, sizeof(callcontext) -1);
  3773. ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
  3774. } else {
  3775. callcontext[0] = '\0';
  3776. }
  3777. if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
  3778. strncpy(exitcontext, exitcxt, sizeof(exitcontext) - 1);
  3779. ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
  3780. } else {
  3781. exitcontext[0] = '\0';
  3782. }
  3783. #ifdef USEMYSQLVM
  3784. if (!(s=ast_variable_retrieve(cfg, "general", "dbuser"))) {
  3785. strncpy(dbuser, "test", sizeof(dbuser) - 1);
  3786. } else {
  3787. strncpy(dbuser, s, sizeof(dbuser) - 1);
  3788. }
  3789. if (!(s=ast_variable_retrieve(cfg, "general", "dbpass"))) {
  3790. strncpy(dbpass, "test", sizeof(dbpass) - 1);
  3791. } else {
  3792. strncpy(dbpass, s, sizeof(dbpass) - 1);
  3793. }
  3794. if (!(s=ast_variable_retrieve(cfg, "general", "dbhost"))) {
  3795. dbhost[0] = '\0';
  3796. } else {
  3797. strncpy(dbhost, s, sizeof(dbhost) - 1);
  3798. }
  3799. if (!(s=ast_variable_retrieve(cfg, "general", "dbname"))) {
  3800. strncpy(dbname, "vmdb", sizeof(dbname) - 1);
  3801. } else {
  3802. strncpy(dbname, s, sizeof(dbname) - 1);
  3803. }
  3804. #endif
  3805. #ifdef USEPOSTGRESVM
  3806. if (!(s=ast_variable_retrieve(cfg, "general", "dboption"))) {
  3807. strncpy(dboption, "dboption not-specified in voicemail.conf", sizeof(dboption) - 1);
  3808. } else {
  3809. strncpy(dboption, s, sizeof(dboption) - 1);
  3810. }
  3811. #endif
  3812. cat = ast_category_browse(cfg, NULL);
  3813. while(cat) {
  3814. if (strcasecmp(cat, "general")) {
  3815. var = ast_variable_browse(cfg, cat);
  3816. if (strcasecmp(cat, "zonemessages")) {
  3817. #ifndef USESQLVM
  3818. /* Process mailboxes in this context */
  3819. while(var) {
  3820. append_mailbox(cat, var->name, var->value);
  3821. var = var->next;
  3822. }
  3823. #endif
  3824. } else {
  3825. /* Timezones in this context */
  3826. while(var) {
  3827. struct vm_zone *z;
  3828. z = malloc(sizeof(struct vm_zone));
  3829. if (z != NULL) {
  3830. char *msg_format, *timezone;
  3831. msg_format = ast_strdupa(var->value);
  3832. if (msg_format != NULL) {
  3833. timezone = strsep(&msg_format, "|");
  3834. if (msg_format) {
  3835. strncpy(z->name, var->name, sizeof(z->name) - 1);
  3836. strncpy(z->timezone, timezone, sizeof(z->timezone) - 1);
  3837. strncpy(z->msg_format, msg_format, sizeof(z->msg_format) - 1);
  3838. z->next = NULL;
  3839. if (zones) {
  3840. zonesl->next = z;
  3841. zonesl = z;
  3842. } else {
  3843. zones = z;
  3844. zonesl = z;
  3845. }
  3846. } else {
  3847. ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
  3848. free(z);
  3849. }
  3850. } else {
  3851. ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
  3852. free(z);
  3853. return -1;
  3854. }
  3855. } else {
  3856. ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n");
  3857. return -1;
  3858. }
  3859. var = var->next;
  3860. }
  3861. }
  3862. }
  3863. cat = ast_category_browse(cfg, cat);
  3864. }
  3865. memset(fromstring,0,sizeof(fromstring));
  3866. memset(pagerfromstring,0,sizeof(pagerfromstring));
  3867. memset(emailtitle,0,sizeof(emailtitle));
  3868. strncpy(charset, "ISO-8859-1", sizeof(charset) - 1);
  3869. if (emailbody) {
  3870. free(emailbody);
  3871. emailbody = NULL;
  3872. }
  3873. if (emailsubject) {
  3874. free(emailsubject);
  3875. emailsubject = NULL;
  3876. }
  3877. if ((s=ast_variable_retrieve(cfg, "general", "pbxskip")))
  3878. pbxskip = ast_true(s);
  3879. if ((s=ast_variable_retrieve(cfg, "general", "fromstring")))
  3880. strncpy(fromstring,s,sizeof(fromstring)-1);
  3881. if ((s=ast_variable_retrieve(cfg, "general", "pagerfromstring")))
  3882. strncpy(pagerfromstring,s,sizeof(pagerfromstring)-1);
  3883. if ((s=ast_variable_retrieve(cfg, "general", "charset")))
  3884. strncpy(charset,s,sizeof(charset)-1);
  3885. if ((s=ast_variable_retrieve(cfg, "general", "adsifdn"))) {
  3886. sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
  3887. for (x=0; x<4; x++) {
  3888. memcpy(&adsifdn[x], &tmpadsi[x], 1);
  3889. }
  3890. }
  3891. if ((s=ast_variable_retrieve(cfg, "general", "adsisec"))) {
  3892. sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
  3893. for (x=0; x<4; x++) {
  3894. memcpy(&adsisec[x], &tmpadsi[x], 1);
  3895. }
  3896. }
  3897. if ((s=ast_variable_retrieve(cfg, "general", "adsiver")))
  3898. if (atoi(s)) {
  3899. adsiver = atoi(s);
  3900. }
  3901. if ((s=ast_variable_retrieve(cfg, "general", "emailtitle"))) {
  3902. ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
  3903. strncpy(emailtitle,s,sizeof(emailtitle)-1);
  3904. }
  3905. if ((s=ast_variable_retrieve(cfg, "general", "emailsubject")))
  3906. emailsubject = strdup(s);
  3907. if ((s=ast_variable_retrieve(cfg, "general", "emailbody"))) {
  3908. char *tmpread, *tmpwrite;
  3909. emailbody = strdup(s);
  3910. /* substitute strings \t and \n into the apropriate characters */
  3911. tmpread = tmpwrite = emailbody;
  3912. while ((tmpwrite = strchr(tmpread,'\\'))) {
  3913. int len = strlen("\n");
  3914. switch (tmpwrite[1]) {
  3915. case 'n':
  3916. strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
  3917. strncpy(tmpwrite,"\n",len);
  3918. break;
  3919. case 't':
  3920. strncpy(tmpwrite+len,tmpwrite+2,strlen(tmpwrite+2)+1);
  3921. strncpy(tmpwrite,"\t",len);
  3922. break;
  3923. default:
  3924. ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n",tmpwrite[1]);
  3925. }
  3926. tmpread = tmpwrite+len;
  3927. }
  3928. }
  3929. ast_destroy(cfg);
  3930. ast_mutex_unlock(&vmlock);
  3931. return 0;
  3932. } else {
  3933. ast_mutex_unlock(&vmlock);
  3934. ast_log(LOG_WARNING, "Error reading voicemail config\n");
  3935. return -1;
  3936. }
  3937. }
  3938. int reload(void)
  3939. {
  3940. return(load_config());
  3941. }
  3942. int unload_module(void)
  3943. {
  3944. int res;
  3945. STANDARD_HANGUP_LOCALUSERS;
  3946. res = ast_unregister_application(app);
  3947. res |= ast_unregister_application(capp);
  3948. res |= ast_unregister_application(app2);
  3949. res |= ast_unregister_application(capp2);
  3950. res |= ast_unregister_application(app3);
  3951. sql_close();
  3952. #ifndef USEMYSQLVM
  3953. ast_cli_unregister(&show_voicemail_users_cli);
  3954. ast_cli_unregister(&show_voicemail_zones_cli);
  3955. #endif
  3956. return res;
  3957. }
  3958. int load_module(void)
  3959. {
  3960. int res;
  3961. res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
  3962. res |= ast_register_application(capp, vm_exec, synopsis_vm, descrip_vm);
  3963. res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
  3964. res |= ast_register_application(capp2, vm_execmain, synopsis_vmain, descrip_vmain);
  3965. res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
  3966. if (res)
  3967. return(res);
  3968. if ((res=load_config())) {
  3969. return(res);
  3970. }
  3971. if ((res = sql_init())) {
  3972. ast_log(LOG_WARNING, "SQL init\n");
  3973. return res;
  3974. }
  3975. #ifndef USEMYSQLVM
  3976. ast_cli_register(&show_voicemail_users_cli);
  3977. ast_cli_register(&show_voicemail_zones_cli);
  3978. #endif
  3979. return res;
  3980. }
  3981. char *description(void)
  3982. {
  3983. return tdesc;
  3984. }
  3985. static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
  3986. {
  3987. int cmd = 0;
  3988. char destination[80] = "";
  3989. int retries = 0;
  3990. if (!num) {
  3991. ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
  3992. while (retries < 3 && cmd != 't') {
  3993. destination[1] = '\0';
  3994. destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
  3995. if (!cmd)
  3996. destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
  3997. if (!cmd)
  3998. destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
  3999. if (!cmd) {
  4000. cmd = ast_waitfordigit(chan, 6000);
  4001. if (cmd)
  4002. destination[0] = cmd;
  4003. }
  4004. if (!cmd) {
  4005. retries++;
  4006. } else {
  4007. if (cmd < 0)
  4008. return 0;
  4009. if (cmd == '*') {
  4010. ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
  4011. return 0;
  4012. }
  4013. if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
  4014. retries++;
  4015. else
  4016. cmd = 't';
  4017. }
  4018. }
  4019. if (retries >= 3) {
  4020. return 0;
  4021. }
  4022. } else {
  4023. ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
  4024. strncpy(destination, num, sizeof(destination) -1);
  4025. }
  4026. if (!ast_strlen_zero(destination)) {
  4027. if (destination[strlen(destination) -1 ] == '*')
  4028. return 0;
  4029. ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
  4030. strncpy(chan->exten, destination, sizeof(chan->exten) - 1);
  4031. strncpy(chan->context, outgoing_context, sizeof(chan->context) - 1);
  4032. chan->priority = 0;
  4033. return 9;
  4034. }
  4035. return 0;
  4036. }
  4037. static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option)
  4038. {
  4039. int res = 0;
  4040. char filename[256],*origtime, *cid, *context, *name, *num;
  4041. struct ast_config *msg_cfg;
  4042. int retries = 0;
  4043. vms->starting = 0;
  4044. make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
  4045. /* Retrieve info from VM attribute file */
  4046. make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
  4047. snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
  4048. msg_cfg = ast_load(filename);
  4049. if (!msg_cfg) {
  4050. ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
  4051. return 0;
  4052. }
  4053. if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")))
  4054. return 0;
  4055. cid = ast_variable_retrieve(msg_cfg, "message", "callerid");
  4056. context = ast_variable_retrieve(msg_cfg, "message", "context");
  4057. if(!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */
  4058. context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
  4059. if (option == 3) {
  4060. if (!res)
  4061. res = play_message_datetime(chan, vmu, origtime, filename);
  4062. if (!res)
  4063. res = play_message_callerid(chan, vms, cid, context, 0);
  4064. } else if (option == 2) { /* Call back */
  4065. if (!ast_strlen_zero(cid)) {
  4066. ast_callerid_parse(cid, &name, &num);
  4067. while ((res > -1) && (res != 't')) {
  4068. switch(res) {
  4069. case '1':
  4070. if (num) {
  4071. /* Dial the CID number */
  4072. res = dialout(chan, vmu, num, vmu->callback);
  4073. if (res)
  4074. return 9;
  4075. } else {
  4076. res = '2';
  4077. }
  4078. break;
  4079. case '2':
  4080. /* Want to enter a different number, can only do this if there's a dialout context for this user */
  4081. if (!ast_strlen_zero(vmu->dialout)) {
  4082. res = dialout(chan, vmu, NULL, vmu->dialout);
  4083. if (res)
  4084. return 9;
  4085. } else {
  4086. ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
  4087. res = ast_play_and_wait(chan, "vm-sorry");
  4088. }
  4089. return res;
  4090. case '*':
  4091. res = 't';
  4092. break;
  4093. case '3':
  4094. case '4':
  4095. case '5':
  4096. case '6':
  4097. case '7':
  4098. case '8':
  4099. case '9':
  4100. case '0':
  4101. res = ast_play_and_wait(chan, "vm-sorry");
  4102. retries++;
  4103. break;
  4104. default:
  4105. if (num) {
  4106. ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
  4107. res = ast_play_and_wait(chan, "vm-num-i-have");
  4108. if (!res)
  4109. res = play_message_callerid(chan, vms, num, vmu->context, 1);
  4110. if (!res)
  4111. res = ast_play_and_wait(chan, "vm-tocallnum");
  4112. /* Only prompt for a caller-specified number if there is a dialout context specified */
  4113. if (!ast_strlen_zero(vmu->dialout)) {
  4114. if (!res)
  4115. res = ast_play_and_wait(chan, "vm-calldiffnum");
  4116. }
  4117. } else {
  4118. res = ast_play_and_wait(chan, "vm-nonumber");
  4119. if (!ast_strlen_zero(vmu->dialout)) {
  4120. if (!res)
  4121. res = ast_play_and_wait(chan, "vm-toenternumber");
  4122. }
  4123. }
  4124. if (!res)
  4125. res = ast_play_and_wait(chan, "vm-star-cancel");
  4126. if (!res)
  4127. res = ast_waitfordigit(chan, 6000);
  4128. if (!res)
  4129. retries++;
  4130. if (retries > 3)
  4131. res = 't';
  4132. break;
  4133. }
  4134. if (res == 't')
  4135. res = 0;
  4136. else if (res == '*')
  4137. res = -1;
  4138. }
  4139. }
  4140. }
  4141. else if (option == 1) { /* Reply */
  4142. /* Send reply directly to sender */
  4143. if (!ast_strlen_zero(cid)) {
  4144. ast_callerid_parse(cid, &name, &num);
  4145. if (!num) {
  4146. ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
  4147. if (!res)
  4148. res = ast_play_and_wait(chan, "vm-nonumber");
  4149. return res;
  4150. } else {
  4151. if (find_user(NULL, vmu->context, num)) {
  4152. ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
  4153. leave_voicemail(chan, num, 1, 0, 1);
  4154. res = 't';
  4155. return res;
  4156. }
  4157. else {
  4158. ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
  4159. /* Sender has no mailbox, can't reply */
  4160. ast_play_and_wait(chan, "vm-nobox");
  4161. res = 't';
  4162. return res;
  4163. }
  4164. }
  4165. res = 0;
  4166. }
  4167. }
  4168. ast_destroy(msg_cfg);
  4169. if (!res) {
  4170. make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
  4171. vms->heard[msg] = 1;
  4172. res = wait_file(chan, vms, vms->fn);
  4173. }
  4174. return res;
  4175. }
  4176. static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir)
  4177. {
  4178. /* Record message & let caller review or re-record it, or set options if applicable */
  4179. int res = 0;
  4180. int cmd = 0;
  4181. int max_attempts = 3;
  4182. int attempts = 0;
  4183. int recorded = 0;
  4184. int message_exists = 0;
  4185. /* Note that urgent and private are for flagging messages as such in the future */
  4186. /* barf if no pointer passed to store duration in */
  4187. if (duration == NULL) {
  4188. ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
  4189. return -1;
  4190. }
  4191. cmd = '3'; /* Want to start by recording */
  4192. while((cmd >= 0) && (cmd != 't')) {
  4193. switch (cmd) {
  4194. case '1':
  4195. if (!message_exists) {
  4196. /* In this case, 1 is to record a message */
  4197. cmd = '3';
  4198. break;
  4199. } else {
  4200. /* Otherwise 1 is to save the existing message */
  4201. ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
  4202. ast_streamfile(chan, "vm-msgsaved", chan->language);
  4203. ast_waitstream(chan, "");
  4204. cmd = 't';
  4205. return res;
  4206. }
  4207. case '2':
  4208. /* Review */
  4209. ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
  4210. ast_streamfile(chan, recordfile, chan->language);
  4211. cmd = ast_waitstream(chan, AST_DIGIT_ANY);
  4212. break;
  4213. case '3':
  4214. message_exists = 0;
  4215. /* Record */
  4216. if (recorded == 1)
  4217. ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
  4218. else
  4219. ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
  4220. if (recorded && outsidecaller) {
  4221. cmd = ast_play_and_wait(chan, INTRO);
  4222. cmd = ast_play_and_wait(chan, "beep");
  4223. }
  4224. recorded = 1;
  4225. /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
  4226. cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir);
  4227. if (cmd == -1)
  4228. /* User has hung up, no options to give */
  4229. return cmd;
  4230. if (cmd == '0') {
  4231. break;
  4232. } else if (cmd == '*') {
  4233. break;
  4234. }
  4235. #if 0
  4236. else if (vmu->review && (*duration < 5)) {
  4237. /* Message is too short */
  4238. ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
  4239. cmd = ast_play_and_wait(chan, "vm-tooshort");
  4240. cmd = vm_delete(recordfile);
  4241. break;
  4242. }
  4243. else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
  4244. /* Message is all silence */
  4245. ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
  4246. cmd = vm_delete(recordfile);
  4247. cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
  4248. if (!cmd)
  4249. cmd = ast_play_and_wait(chan, "vm-speakup");
  4250. break;
  4251. }
  4252. #endif
  4253. else {
  4254. /* If all is well, a message exists */
  4255. message_exists = 1;
  4256. cmd = 0;
  4257. }
  4258. break;
  4259. case '4':
  4260. case '5':
  4261. case '6':
  4262. case '7':
  4263. case '8':
  4264. case '9':
  4265. case '*':
  4266. case '#':
  4267. cmd = ast_play_and_wait(chan, "vm-sorry");
  4268. break;
  4269. #if 0
  4270. /* XXX Commented out for the moment because of the dangers of deleting
  4271. a message while recording (can put the message numbers out of sync) */
  4272. case '*':
  4273. /* Cancel recording, delete message, offer to take another message*/
  4274. cmd = ast_play_and_wait(chan, "vm-deleted");
  4275. cmd = vm_delete(recordfile);
  4276. if (outsidecaller) {
  4277. res = vm_exec(chan, NULL);
  4278. return res;
  4279. }
  4280. else
  4281. return 1;
  4282. #endif
  4283. case '0':
  4284. if (message_exists || recorded) {
  4285. cmd = ast_play_and_wait(chan, "vm-saveoper");
  4286. if (!cmd)
  4287. cmd = ast_waitfordigit(chan, 3000);
  4288. if (cmd == '1') {
  4289. ast_play_and_wait(chan, "vm-msgsaved");
  4290. cmd = '0';
  4291. } else {
  4292. ast_play_and_wait(chan, "vm-deleted");
  4293. vm_delete(recordfile);
  4294. cmd = '0';
  4295. }
  4296. }
  4297. return cmd;
  4298. default:
  4299. /* If the caller is an ouside caller, and the review option is enabled,
  4300. allow them to review the message, but let the owner of the box review
  4301. their OGM's */
  4302. if (outsidecaller && !vmu->review)
  4303. return cmd;
  4304. if (message_exists) {
  4305. cmd = ast_play_and_wait(chan, "vm-review");
  4306. }
  4307. else {
  4308. cmd = ast_play_and_wait(chan, "vm-torerecord");
  4309. if (!cmd)
  4310. cmd = ast_waitfordigit(chan, 600);
  4311. }
  4312. if (!cmd && outsidecaller && vmu->operator) {
  4313. cmd = ast_play_and_wait(chan, "vm-reachoper");
  4314. if (!cmd)
  4315. cmd = ast_waitfordigit(chan, 600);
  4316. }
  4317. #if 0
  4318. if (!cmd)
  4319. cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
  4320. #endif
  4321. if (!cmd)
  4322. cmd = ast_waitfordigit(chan, 6000);
  4323. if (!cmd) {
  4324. attempts++;
  4325. }
  4326. if (attempts > max_attempts) {
  4327. cmd = 't';
  4328. }
  4329. }
  4330. }
  4331. if (outsidecaller)
  4332. ast_play_and_wait(chan, "vm-goodbye");
  4333. if (cmd == 't')
  4334. cmd = 0;
  4335. return cmd;
  4336. }
  4337. static int vm_delete(char *file)
  4338. {
  4339. char *txt;
  4340. int txtsize = 0;
  4341. txtsize = (strlen(file) + 5)*sizeof(char);
  4342. txt = (char *)alloca(txtsize);
  4343. /* Sprintf here would safe because we alloca'd exactly the right length,
  4344. * but trying to eliminate all sprintf's anyhow
  4345. */
  4346. snprintf(txt, txtsize, "%s.txt", file);
  4347. unlink(txt);
  4348. return ast_filedelete(file, NULL);
  4349. }
  4350. int usecount(void)
  4351. {
  4352. int res;
  4353. STANDARD_USECOUNT(res);
  4354. return res;
  4355. }
  4356. char *key()
  4357. {
  4358. return ASTERISK_GPL_KEY;
  4359. }