From: Sipwise Development Team Date: Mon, 4 Nov 2024 15:37:29 +0100 Subject: sipwise_vm_add_pcre_support --- Makefile | 2 +- apps/app_voicemail.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 67ec08d..ad0c960 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ CC?=gcc OPTIMIZE=-O2 DEBUG=-g -LIBS+= +LIBS+=-lpcre CFLAGS+=-pipe -fPIC CFLAGS+=-Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations CFLAGS+=-D_REENTRANT -D_GNU_SOURCE -DODBC_STORAGE diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 8769654..692e796 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -50,6 +50,7 @@ res_adsi res_smdi yes + pcre core ***/ @@ -144,6 +145,9 @@ #include "asterisk/threadstorage.h" #endif +#include +#include + /*** DOCUMENTATION @@ -1024,6 +1028,8 @@ static int maxlogins = 3; static int minpassword = MINPASSWORD; static int passwordlocation; static char aliasescontext[MAX_VM_CONTEXT_LEN]; +static char sw_normalize_user_match[256]; +static char sw_normalize_user_replace[256]; /*! Poll mailboxes for changes since there is something external to * app_voicemail that may change them. */ @@ -1280,6 +1286,114 @@ static int inprocess_count(const char *context, const char *mailbox, int delta) static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit); #endif +/* sipwise pcre helper functions taken from contrib of pcre: + + Written by: Bert Driehuis + Copyright (c) 2000 Bert Driehuis + + Permission is granted to anyone to use this software for any purpose on any + computer system, and to redistribute it freely, subject to the following + restrictions: + + 1. This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + 2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + + 3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +*/ +#define MAXCAPTURE 50 + +static int findreplen(const char *rep, int nmat, const int *replen) +{ + int len = 0; + int val; + char *cp = (char *)rep; + while(*cp) { + if (*cp == '$' && isdigit(cp[1])) { + val = strtoul(&cp[1], &cp, 10); + if (val && val <= nmat + 1) + len += replen[val -1]; + else + fprintf(stderr, "repl %d out of range\n", val); + } else { + cp++; + len++; + } + } + return len; +} + +static void doreplace(char *out, const char *rep, + int nmat, int *replen, const char **repstr) +{ + int val; + char *cp = (char *)rep; + while(*cp) { + if (*cp == '$' && isdigit(cp[1])) { + val = strtoul(&cp[1], &cp, 10); + if (val && val <= nmat + 1) { + strncpy(out, repstr[val - 1], replen[val - 1]); + out += replen[val -1]; + } + } else { + *out++ = *cp++; + } + } +} + +static char *edit(const char *str, int len, const char *rep, + int nmat, const int *ovec) +{ + int i, slen, rlen; + const int *mvec = ovec; + char *res, *cp; + int replen[MAXCAPTURE]; + const char *repstr[MAXCAPTURE]; + nmat--; + ovec += 2; + for (i = 0; i < nmat; i++) { + replen[i] = ovec[i * 2 + 1] - ovec[i * 2]; + repstr[i] = &str[ovec[i * 2]]; + } + slen = len; + len -= mvec[1] - mvec[0]; + len += rlen = findreplen(rep, nmat, replen); + cp = res = pcre_malloc(len + 1); + if (mvec[0] > 0) { + strncpy(cp, str, mvec[0]); + cp += mvec[0]; + } + doreplace(cp, rep, nmat, replen, repstr); + cp += rlen; + if (mvec[1] < slen) + strcpy(cp, &str[mvec[1]]); + res[len] = 0; + return res; +} + +static char *pcre_subst(const pcre *ppat, const pcre_extra *extra, + const char *str, int len, + int offset, int options, const char *rep) +{ + int nmat; + int ovec[MAXCAPTURE * 3]; + nmat = pcre_exec(ppat, extra, str, len, offset, options, + ovec, sizeof(ovec)); + if (nmat <= 0) + return NULL; + return(edit(str, len, rep, nmat, ovec)); +} + +/* end of pcre helper functions */ + /*! * \brief Strips control and non 7-bit clean characters from input string. * @@ -8011,6 +8125,8 @@ static int get_folder2(struct ast_channel *chan, char *fn, int start) * This is invoked from forward_message() when performing a forward operation (option 8 from main menu). * \return zero on success, -1 on error. */ + +#if 0 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts, char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag) { @@ -8172,6 +8288,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, cmd = 0; return cmd; } +#endif static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old) { @@ -8332,6 +8449,8 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, * * \return zero on success, -1 on error. */ + +#if 0 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent) { #ifdef IMAP_STORAGE @@ -8671,6 +8790,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st } return res ? res : cmd; } +#endif static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file) { @@ -11421,6 +11541,11 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ int useadsi = 0, valid = 0, logretries = 0; char password[AST_MAX_EXTENSION], *passptr = NULL; struct ast_vm_user vmus, *vmu = NULL; + const char *err; + int erroffset; + pcre_extra *extra = NULL; + pcre *ppat = NULL; + char *normalized_mailbox; /* If ADSI is supported, setup login screen */ adsi_begin(chan, &useadsi); @@ -11431,6 +11556,22 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ return -1; } + if(sw_normalize_user_match[0] != '\0' && sw_normalize_user_replace[0] != '\0') { + // TODO: could be done once on start + ppat = pcre_compile(sw_normalize_user_match, 0, &err, &erroffset, NULL); + if(ppat == NULL) { + ast_log(LOG_WARNING, "Couldn't compile user match regex '%s': %s at offset %d\n", + sw_normalize_user_match, err, erroffset); + return -1; + } + extra = pcre_study(ppat, 0, &err); + if(err) { + ast_log(LOG_WARNING, "Couldn't study regex '%s': %s\n", + sw_normalize_user_match, err); + return -1; + } + } + /* Authenticate them and get their mailbox/password */ while (!valid && (logretries < max_logins)) { @@ -11460,6 +11601,18 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ if (useadsi) adsi_password(chan); + if(ppat && extra) { + ast_log(LOG_NOTICE, "Trying to rewrite user input '%s' using s/%s/%s/\n", + mailbox, sw_normalize_user_match, sw_normalize_user_replace); + normalized_mailbox = pcre_subst(ppat, extra, mailbox, strlen(mailbox), 0, 0, sw_normalize_user_replace); + if(normalized_mailbox) { + ast_log(LOG_NOTICE, "Rewrote mailbox user input '%s' to %s\n", + mailbox, normalized_mailbox); + ast_copy_string(mailbox, normalized_mailbox, mailbox_size); + free(normalized_mailbox); + } + } + if (!ast_strlen_zero(prefix)) { char fullusername[80]; @@ -14057,6 +14210,8 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con char secretfn[PATH_MAX] = ""; long tps_queue_low; long tps_queue_high; + const char *ast_sw_normalize_user_match = NULL; + const char *ast_sw_normalize_user_replace = NULL; #ifdef IMAP_STORAGE ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder)); @@ -14121,6 +14276,19 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con ast_copy_string(odbc_table, val, sizeof(odbc_table)); } #endif + + /* sipwise sw_normalize_user_match/replace */ + if ((ast_sw_normalize_user_match = ast_variable_retrieve(cfg, "general", "sw_normalize_user_match"))) { + ast_copy_string(sw_normalize_user_match, ast_sw_normalize_user_match, sizeof(sw_normalize_user_match)); + } else { + sw_normalize_user_match[0] = '\0'; + } + if ((ast_sw_normalize_user_replace = ast_variable_retrieve(cfg, "general", "sw_normalize_user_replace"))) { + ast_copy_string(sw_normalize_user_replace, ast_sw_normalize_user_replace, sizeof(sw_normalize_user_replace)); + } else { + sw_normalize_user_replace[0] = '\0'; + } + /* Mail command */ strcpy(mailcmd, SENDMAIL); if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))