2002-09-11 17:09:48 +00:00
|
|
|
/*
|
2005-09-14 20:46:50 +00:00
|
|
|
* Asterisk -- An open source telephony toolkit.
|
2002-09-11 17:09:48 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2002, Christos Ricudis
|
|
|
|
*
|
2004-03-15 16:51:58 +00:00
|
|
|
* Christos Ricudis <ricudis@itc.auth.gr>
|
2002-09-11 17:09:48 +00:00
|
|
|
*
|
2005-09-14 20:46:50 +00:00
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
2002-09-11 17:09:48 +00:00
|
|
|
* This program is free software, distributed under the terms of
|
2005-09-14 20:46:50 +00:00
|
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
|
|
* at the top of the source tree.
|
|
|
|
*/
|
|
|
|
|
2005-10-24 20:12:06 +00:00
|
|
|
/*! \file
|
2005-09-14 20:46:50 +00:00
|
|
|
*
|
2005-10-24 20:12:06 +00:00
|
|
|
* \brief Connect to PostgreSQL
|
2005-12-30 21:18:06 +00:00
|
|
|
*
|
|
|
|
* \author Christos Ricudis <ricudis@itc.auth.gr>
|
2006-01-21 21:29:06 +00:00
|
|
|
*
|
2005-11-06 15:09:47 +00:00
|
|
|
* \ingroup applications
|
2002-09-11 17:09:48 +00:00
|
|
|
*/
|
|
|
|
|
2005-06-06 22:39:32 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "asterisk.h"
|
|
|
|
|
|
|
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|
|
|
|
2005-04-21 06:02:45 +00:00
|
|
|
#include "asterisk/file.h"
|
|
|
|
#include "asterisk/logger.h"
|
|
|
|
#include "asterisk/channel.h"
|
|
|
|
#include "asterisk/pbx.h"
|
|
|
|
#include "asterisk/module.h"
|
|
|
|
#include "asterisk/linkedlists.h"
|
|
|
|
#include "asterisk/chanvars.h"
|
|
|
|
#include "asterisk/lock.h"
|
2005-06-06 22:39:32 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
#include "libpq-fe.h"
|
|
|
|
|
|
|
|
static char *tdesc = "Simple PostgreSQL Interface";
|
|
|
|
|
|
|
|
static char *app = "PGSQL";
|
|
|
|
|
|
|
|
static char *synopsis = "Do several SQLy things";
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static char *descrip =
|
2004-04-30 05:27:35 +00:00
|
|
|
"PGSQL(): Do several SQLy things\n"
|
|
|
|
"Syntax:\n"
|
|
|
|
" PGSQL(Connect var option-string)\n"
|
|
|
|
" Connects to a database. Option string contains standard PostgreSQL\n"
|
2006-01-21 21:29:06 +00:00
|
|
|
" parameters like host=, dbname=, user=. Connection identifier returned\n"
|
|
|
|
" in ${var}.\n"
|
2004-04-30 05:27:35 +00:00
|
|
|
" PGSQL(Query var ${connection_identifier} query-string)\n"
|
|
|
|
" Executes standard SQL query contained in query-string using established\n"
|
2006-01-21 21:29:06 +00:00
|
|
|
" connection identified by ${connection_identifier}. Result of query is\n"
|
|
|
|
" stored in ${var}.\n"
|
2004-04-30 05:27:35 +00:00
|
|
|
" PGSQL(Fetch statusvar ${result_identifier} var1 var2 ... varn)\n"
|
|
|
|
" Fetches a single row from a result set contained in ${result_identifier}.\n"
|
|
|
|
" Assigns returned fields to ${var1} ... ${varn}. ${statusvar} is set TRUE\n"
|
2006-01-21 21:29:06 +00:00
|
|
|
" if additional rows exist in result set.\n"
|
2004-04-30 05:27:35 +00:00
|
|
|
" PGSQL(Clear ${result_identifier})\n"
|
2006-01-21 21:29:06 +00:00
|
|
|
" Frees memory and data structures associated with result set.\n"
|
2004-04-30 05:27:35 +00:00
|
|
|
" PGSQL(Disconnect ${connection_identifier})\n"
|
|
|
|
" Disconnects from named connection to PostgreSQL.\n" ;
|
2002-09-11 17:09:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
Syntax of SQL commands :
|
2002-09-11 17:09:48 +00:00
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Connect var option-string
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
Connects to a database using the option-string and stores the
|
2004-04-30 05:27:35 +00:00
|
|
|
connection identifier in ${var}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Query var ${connection_identifier} query-string
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
Submits query-string to database backend and stores the result
|
|
|
|
identifier in ${var}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Fetch statusvar ${result_identifier} var1 var2 var3 ... varn
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
Fetches a row from the query and stores end-of-table status in
|
|
|
|
${statusvar} and columns in ${var1} ... ${varn}
|
|
|
|
|
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Clear ${result_identifier}
|
2002-09-11 17:09:48 +00:00
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Clears data structures associated with ${result_identifier}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
Disconnect ${connection_identifier}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
Disconnects from named connection
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
EXAMPLES OF USE :
|
2002-09-11 17:09:48 +00:00
|
|
|
|
2004-04-30 05:27:35 +00:00
|
|
|
exten => s,2,PGSQL(Connect connid host=localhost user=asterisk dbname=credit)
|
|
|
|
exten => s,3,PGSQL(Query resultid ${connid} SELECT username,credit FROM credit WHERE callerid=${CALLERIDNUM})
|
|
|
|
exten => s,4,PGSQL(Fetch fetchid ${resultid} datavar1 datavar2)
|
|
|
|
exten => s,5,GotoIf(${fetchid}?6:8)
|
2006-01-21 21:29:06 +00:00
|
|
|
exten => s,6,Festival("User ${datavar1} currently has credit balance of ${datavar2} dollars.")
|
2004-04-30 05:27:35 +00:00
|
|
|
exten => s,7,Goto(s,4)
|
|
|
|
exten => s,8,PGSQL(Clear ${resultid})
|
|
|
|
exten => s,9,PGSQL(Disconnect ${connid})
|
2002-09-11 17:09:48 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
STANDARD_LOCAL_USER;
|
|
|
|
|
|
|
|
LOCAL_USER_DECL;
|
|
|
|
|
|
|
|
#define AST_PGSQL_ID_DUMMY 0
|
|
|
|
#define AST_PGSQL_ID_CONNID 1
|
|
|
|
#define AST_PGSQL_ID_RESID 2
|
|
|
|
#define AST_PGSQL_ID_FETCHID 3
|
|
|
|
|
|
|
|
struct ast_PGSQL_id {
|
2006-01-21 21:29:06 +00:00
|
|
|
int identifier_type; /* 0 = dummy, 1 = connid, 2 = resultid */
|
2002-09-11 17:09:48 +00:00
|
|
|
int identifier;
|
|
|
|
void *data;
|
|
|
|
AST_LIST_ENTRY(ast_PGSQL_id) entries;
|
|
|
|
} *ast_PGSQL_id;
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
AST_LIST_HEAD(PGSQLidshead, ast_PGSQL_id) PGSQLidshead;
|
2002-09-11 17:09:48 +00:00
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static void *find_identifier(int identifier, int identifier_type)
|
|
|
|
{
|
2002-09-11 17:09:48 +00:00
|
|
|
struct PGSQLidshead *headp;
|
|
|
|
struct ast_PGSQL_id *i;
|
2006-01-21 21:29:06 +00:00
|
|
|
void *res = NULL;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
headp = &PGSQLidshead;
|
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
if (AST_LIST_LOCK(headp)) {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to lock identifiers list\n");
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
AST_LIST_TRAVERSE(headp, i, entries) {
|
|
|
|
if ((i->identifier == identifier) && (i->identifier_type == identifier_type)) {
|
|
|
|
found = 1;
|
|
|
|
res = i->data;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "Identifier %d, identifier_type %d not found in identifier list\n", identifier, identifier_type);
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(headp);
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
return res;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int add_identifier(int identifier_type, void *data)
|
|
|
|
{
|
|
|
|
struct ast_PGSQL_id *i, *j;
|
2002-09-11 17:09:48 +00:00
|
|
|
struct PGSQLidshead *headp;
|
2006-01-21 21:29:06 +00:00
|
|
|
int maxidentifier = 0;
|
|
|
|
|
|
|
|
headp = &PGSQLidshead;
|
|
|
|
i = NULL;
|
|
|
|
j = NULL;
|
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
if (AST_LIST_LOCK(headp)) {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to lock identifiers list\n");
|
|
|
|
return -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
i = malloc(sizeof(struct ast_PGSQL_id));
|
|
|
|
AST_LIST_TRAVERSE(headp, j, entries) {
|
|
|
|
if (j->identifier > maxidentifier) {
|
|
|
|
maxidentifier = j->identifier;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
i->identifier = maxidentifier + 1;
|
|
|
|
i->identifier_type = identifier_type;
|
|
|
|
i->data = data;
|
|
|
|
AST_LIST_INSERT_HEAD(headp, i, entries);
|
2002-09-11 17:09:48 +00:00
|
|
|
AST_LIST_UNLOCK(headp);
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
return i->identifier;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int del_identifier(int identifier, int identifier_type)
|
|
|
|
{
|
2002-09-11 17:09:48 +00:00
|
|
|
struct ast_PGSQL_id *i;
|
|
|
|
struct PGSQLidshead *headp;
|
2006-01-21 21:29:06 +00:00
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
headp = &PGSQLidshead;
|
|
|
|
|
|
|
|
if (AST_LIST_LOCK(headp)) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to lock identifiers list\n");
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
AST_LIST_TRAVERSE(headp, i, entries) {
|
|
|
|
if ((i->identifier == identifier) && (i->identifier_type == identifier_type)) {
|
|
|
|
AST_LIST_REMOVE(headp, i, entries);
|
2002-09-11 17:09:48 +00:00
|
|
|
free(i);
|
2006-01-21 21:29:06 +00:00
|
|
|
found = 1;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(headp);
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
ast_log(LOG_WARNING, "Could not find identifier %d, identifier_type %d in list to delete\n", identifier, identifier_type);
|
|
|
|
return -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
return 0;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_connect(struct ast_channel *chan, void *data)
|
|
|
|
{
|
2004-07-14 07:34:34 +00:00
|
|
|
char *s1;
|
|
|
|
char s[100] = "";
|
2002-09-11 17:09:48 +00:00
|
|
|
char *optionstring;
|
|
|
|
char *var;
|
|
|
|
int l;
|
|
|
|
int res;
|
2006-01-21 21:29:06 +00:00
|
|
|
PGconn *PGSQLconn;
|
2002-09-11 17:09:48 +00:00
|
|
|
int id;
|
2006-01-21 21:29:06 +00:00
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s1 = malloc(l);
|
|
|
|
strncpy(s1, data, l - 1);
|
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
var = strsep(&stringp, " ");
|
|
|
|
optionstring = strsep(&stringp, "\n");
|
|
|
|
|
|
|
|
PGSQLconn = PQconnectdb(optionstring);
|
|
|
|
if (PQstatus(PGSQLconn) == CONNECTION_BAD) {
|
|
|
|
ast_log(LOG_WARNING, "Connection to database using '%s' failed. postgress reports : %s\n", optionstring, PQerrorMessage(PGSQLconn));
|
|
|
|
res = -1;
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Adding identifier\n");
|
|
|
|
id = add_identifier(AST_PGSQL_ID_CONNID, PGSQLconn);
|
2004-07-14 07:34:34 +00:00
|
|
|
snprintf(s, sizeof(s), "%d", id);
|
2006-01-21 21:29:06 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, var, s);
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
free(s1);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_query(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *s1, *s2, *s3, *s4;
|
2004-07-14 07:34:34 +00:00
|
|
|
char s[100] = "";
|
2002-09-11 17:09:48 +00:00
|
|
|
char *querystring;
|
|
|
|
char *var;
|
|
|
|
int l;
|
2006-01-21 21:29:06 +00:00
|
|
|
int res, nres;
|
|
|
|
PGconn *PGSQLconn;
|
2002-09-11 17:09:48 +00:00
|
|
|
PGresult *PGSQLres;
|
2006-01-21 21:29:06 +00:00
|
|
|
int id, id1;
|
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s1 = malloc(l);
|
|
|
|
s2 = malloc(l);
|
2004-07-14 07:34:34 +00:00
|
|
|
strncpy(s1, data, l - 1);
|
2006-01-21 21:29:06 +00:00
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
s3 = strsep(&stringp, " ");
|
2004-12-19 21:13:41 +00:00
|
|
|
while (1) { /* ugly trick to make branches with break; */
|
2006-01-21 21:29:06 +00:00
|
|
|
var = s3;
|
|
|
|
s4 = strsep(&stringp, " ");
|
|
|
|
id = atoi(s4);
|
|
|
|
querystring = strsep(&stringp, "\n");
|
|
|
|
if (!(PGSQLconn = find_identifier(id, AST_PGSQL_ID_CONNID))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid connection identifier %d passed in aPGSQL_query\n", id);
|
|
|
|
res = -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
if (!(PGSQLres = PQexec(PGSQLconn, querystring))) {
|
|
|
|
ast_log(LOG_WARNING, "aPGSQL_query: Connection Error (connection identifier = %d, error message : %s)\n", id, PQerrorMessage(PGSQLconn));
|
|
|
|
res = -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
|
|
|
|
PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
|
|
|
|
PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "aPGSQL_query: Query Error (connection identifier : %d, error message : %s)\n", id, PQcmdStatus(PGSQLres));
|
|
|
|
res = -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
nres = PQnfields(PGSQLres);
|
|
|
|
id1 = add_identifier(AST_PGSQL_ID_RESID, PGSQLres);
|
2004-07-14 07:34:34 +00:00
|
|
|
snprintf(s, sizeof(s), "%d", id1);
|
2006-01-21 21:29:06 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, var, s);
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
free(s1);
|
|
|
|
free(s2);
|
2004-06-16 03:28:42 +00:00
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
return res;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_fetch(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *s1, *s2, *fetchid_var, *s4, *s5, *s6;
|
|
|
|
const char *s7;
|
2002-09-11 17:09:48 +00:00
|
|
|
char s[100];
|
|
|
|
char *var;
|
|
|
|
int l;
|
|
|
|
int res;
|
|
|
|
PGresult *PGSQLres;
|
2006-01-21 21:29:06 +00:00
|
|
|
int id, id1, i, j, fnd;
|
|
|
|
int *identp = NULL;
|
2002-09-11 17:09:48 +00:00
|
|
|
int nres;
|
2006-01-21 21:29:06 +00:00
|
|
|
struct ast_var_t *variables;
|
|
|
|
struct varshead *headp;
|
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
headp = &chan->varshead;
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s7 = NULL;
|
|
|
|
s1 = malloc(l);
|
|
|
|
s2 = malloc(l);
|
2004-07-14 07:34:34 +00:00
|
|
|
strncpy(s1, data, l - 1);
|
2006-01-21 21:29:06 +00:00
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
fetchid_var = strsep(&stringp, " ");
|
2004-12-19 21:13:41 +00:00
|
|
|
while (1) { /* ugly trick to make branches with break; */
|
2006-01-21 21:29:06 +00:00
|
|
|
var = fetchid_var; /* fetchid */
|
|
|
|
fnd = 0;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(headp, variables, entries) {
|
|
|
|
if (!(strncasecmp(ast_var_name(variables), fetchid_var, strlen(fetchid_var)))) {
|
|
|
|
s7 = ast_var_value(variables);
|
|
|
|
fnd = 1;
|
|
|
|
break;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
if (!fnd) {
|
|
|
|
s7 = "0";
|
|
|
|
pbx_builtin_setvar_helper(chan, fetchid_var, s7);
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
s4 = strsep(&stringp, " ");
|
|
|
|
id = atoi(s4); /* resultid */
|
|
|
|
if (!(PGSQLres = find_identifier(id, AST_PGSQL_ID_RESID))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid result identifier %d passed in aPGSQL_fetch\n", id);
|
|
|
|
res = -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
id = atoi(s7); /*fetchid */
|
|
|
|
if (!(identp = find_identifier(id, AST_PGSQL_ID_FETCHID))) {
|
|
|
|
i = 0; /* fetching the very first row */
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
i = *identp;
|
|
|
|
free(identp);
|
|
|
|
del_identifier(id, AST_PGSQL_ID_FETCHID); /* will re-add it a bit later */
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2004-06-16 03:28:42 +00:00
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
if (i < PQntuples(PGSQLres)) {
|
|
|
|
nres = PQnfields(PGSQLres);
|
|
|
|
ast_log(LOG_WARNING, "ast_PGSQL_fetch : nres = %d i = %d ;\n", nres, i);
|
|
|
|
for (j = 0; j < nres; j++) {
|
|
|
|
if (!(s5 = strsep(&stringp, " "))) {
|
|
|
|
ast_log(LOG_WARNING, "ast_PGSQL_fetch : More tuples (%d) than variables (%d)\n", nres, j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!(s6 = PQgetvalue(PGSQLres, i, j))) {
|
|
|
|
ast_log(LOG_WARNING, "PQgetvalue(res, %d, %d) returned NULL in ast_PGSQL_fetch\n", i, j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ast_log(LOG_WARNING, "===setting variable '%s' to '%s'\n", s5, s6);
|
|
|
|
pbx_builtin_setvar_helper(chan, s5, s6);
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
identp = malloc(sizeof(int));
|
|
|
|
*identp = ++i; /* advance to the next row */
|
|
|
|
id1 = add_identifier(AST_PGSQL_ID_FETCHID, identp);
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "ast_PGSQL_fetch : EOF\n");
|
|
|
|
id1 = 0; /* no more rows */
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2004-07-14 07:34:34 +00:00
|
|
|
snprintf(s, sizeof(s), "%d", id1);
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "Setting var '%s' to value '%s'\n", fetchid_var, s);
|
|
|
|
pbx_builtin_setvar_helper(chan, fetchid_var, s);
|
|
|
|
break;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
free(s1);
|
|
|
|
free(s2);
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
return res;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_reset(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *s1, *s3;
|
2002-09-11 17:09:48 +00:00
|
|
|
int l;
|
2006-01-21 21:29:06 +00:00
|
|
|
PGconn *PGSQLconn;
|
2002-09-11 17:09:48 +00:00
|
|
|
int id;
|
2006-01-21 21:29:06 +00:00
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s1 = malloc(l);
|
2004-07-14 07:34:34 +00:00
|
|
|
strncpy(s1, data, l - 1);
|
2006-01-21 21:29:06 +00:00
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
s3 = strsep(&stringp, " ");
|
|
|
|
id = atoi(s3);
|
|
|
|
if (!(PGSQLconn = find_identifier(id, AST_PGSQL_ID_CONNID))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid connection identifier %d passed in aPGSQL_reset\n", id);
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
PQreset(PGSQLconn);
|
|
|
|
}
|
2002-09-11 17:09:48 +00:00
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
free(s1);
|
|
|
|
|
|
|
|
return 0;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_clear(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *s1, *s3;
|
2002-09-11 17:09:48 +00:00
|
|
|
int l;
|
2006-01-21 21:29:06 +00:00
|
|
|
PGresult *PGSQLres;
|
2002-09-11 17:09:48 +00:00
|
|
|
int id;
|
2006-01-21 21:29:06 +00:00
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s1 = malloc(l);
|
2004-07-14 07:34:34 +00:00
|
|
|
strncpy(s1, data, l - 1);
|
2006-01-21 21:29:06 +00:00
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
s3 = strsep(&stringp, " ");
|
|
|
|
id = atoi(s3);
|
|
|
|
if (!(PGSQLres = find_identifier(id, AST_PGSQL_ID_RESID))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid result identifier %d passed in aPGSQL_clear\n", id);
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
PQclear(PGSQLres);
|
|
|
|
del_identifier(id, AST_PGSQL_ID_RESID);
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
free(s1);
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
return 0;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_disconnect(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *s1, *s3;
|
2002-09-11 17:09:48 +00:00
|
|
|
int l;
|
2006-01-21 21:29:06 +00:00
|
|
|
PGconn *PGSQLconn;
|
2002-09-11 17:09:48 +00:00
|
|
|
int id;
|
2006-01-21 21:29:06 +00:00
|
|
|
char *stringp = NULL;
|
|
|
|
|
|
|
|
l = strlen(data) + 2;
|
|
|
|
s1 = malloc(l);
|
2004-07-14 07:34:34 +00:00
|
|
|
strncpy(s1, data, l - 1);
|
2006-01-21 21:29:06 +00:00
|
|
|
stringp = s1;
|
|
|
|
strsep(&stringp, " "); /* eat the first token, we already know it :P */
|
|
|
|
s3 = strsep(&stringp, " ");
|
|
|
|
id = atoi(s3);
|
|
|
|
if (!(PGSQLconn = find_identifier(id, AST_PGSQL_ID_CONNID))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid connection identifier %d passed in aPGSQL_disconnect\n", id);
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
PQfinish(PGSQLconn);
|
|
|
|
del_identifier(id, AST_PGSQL_ID_CONNID);
|
|
|
|
}
|
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
free(s1);
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
return 0;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
static int aPGSQL_debug(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
ast_log(LOG_WARNING, "Debug : %s\n", (char *)data);
|
|
|
|
return 0;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int PGSQL_exec(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
struct localuser *u;
|
|
|
|
int result;
|
|
|
|
|
2005-10-26 19:48:14 +00:00
|
|
|
if (ast_strlen_zero(data)) {
|
2002-09-11 17:09:48 +00:00
|
|
|
ast_log(LOG_WARNING, "APP_PGSQL requires an argument (see manual)\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
LOCAL_USER_ADD(u);
|
2005-10-19 18:19:02 +00:00
|
|
|
|
2006-01-21 21:29:06 +00:00
|
|
|
result = 0;
|
|
|
|
|
|
|
|
if (!(strncasecmp("connect", data, strlen("connect")))) {
|
|
|
|
result = (aPGSQL_connect(chan, data));
|
|
|
|
} else if (!(strncasecmp("query", data, strlen("query")))) {
|
|
|
|
result = (aPGSQL_query(chan, data));
|
|
|
|
} else if (!(strncasecmp("fetch", data, strlen("fetch")))) {
|
|
|
|
result = (aPGSQL_fetch(chan, data));
|
|
|
|
} else if (!(strncasecmp("reset", data, strlen("reset")))) {
|
|
|
|
result = (aPGSQL_reset(chan, data));
|
|
|
|
} else if (!(strncasecmp("clear", data, strlen("clear")))) {
|
|
|
|
result = (aPGSQL_clear(chan, data));
|
|
|
|
} else if (!(strncasecmp("debug", data, strlen("debug")))) {
|
|
|
|
result = (aPGSQL_debug(chan, data));
|
|
|
|
} else if (!(strncasecmp("disconnect", data, strlen("disconnect")))) {
|
|
|
|
result = (aPGSQL_disconnect(chan, data));
|
2002-09-11 17:09:48 +00:00
|
|
|
} else {
|
2006-01-21 21:29:06 +00:00
|
|
|
ast_log(LOG_WARNING, "Unknown APP_PGSQL argument : %s\n", (char *)data);
|
|
|
|
result = -1;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
2006-01-21 21:29:06 +00:00
|
|
|
|
|
|
|
LOCAL_USER_REMOVE(u);
|
|
|
|
|
2002-09-11 17:09:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int unload_module(void)
|
|
|
|
{
|
2006-01-21 21:29:06 +00:00
|
|
|
int res = ast_unregister_application(app);
|
2002-09-11 17:09:48 +00:00
|
|
|
STANDARD_HANGUP_LOCALUSERS;
|
2005-10-18 22:52:21 +00:00
|
|
|
return res;
|
2002-09-11 17:09:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int load_module(void)
|
|
|
|
{
|
2006-01-21 21:29:06 +00:00
|
|
|
struct PGSQLidshead *headp = &PGSQLidshead;
|
2002-09-11 17:09:48 +00:00
|
|
|
AST_LIST_HEAD_INIT(headp);
|
|
|
|
return ast_register_application(app, PGSQL_exec, synopsis, descrip);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *description(void)
|
|
|
|
{
|
|
|
|
return tdesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int usecount(void)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
STANDARD_USECOUNT(res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *key()
|
|
|
|
{
|
|
|
|
return ASTERISK_GPL_KEY;
|
|
|
|
}
|