line
stmt
bran
cond
sub
pod
time
code
1
#
2
# OSDial.pm
3
#
4
## Copyright (C) 2010-2011 Lott Caskey LICENSE: AGPLv3
5
##
6
## This file is part of OSDial.
7
##
8
## OSDial is free software: you can redistribute it and/or modify
9
## it under the terms of the GNU Affero General Public License as
10
## published by the Free Software Foundation, either version 3 of
11
## the License, or (at your option) any later version.
12
##
13
## OSDial is distributed in the hope that it will be useful,
14
## but WITHOUT ANY WARRANTY; without even the implied warranty of
15
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
## GNU Affero General Public License for more details.
17
##
18
## You should have received a copy of the GNU Affero General Public
19
## License along with OSDial. If not, see .
20
##
21
#
22
package OSDial;
23
24
1
1
29439
use 5.008000;
1
4
1
37
25
1
1
6
use strict;
1
1
1
33
26
1
1
4
use warnings;
1
6
1
27
27
28
1
1
2433
use DBI;
1
22306
1
70
29
1
1
1139
use Asterisk::AGI;
1
7871
1
35
30
1
1
10
use Digest::MD5 qw(md5_hex);
1
2
1
79
31
1
1
539
use Email::Stuffer;
0
0
32
use Email::Sender::Transport::SMTP;
33
use Proc::Exists ('pexists');
34
use Data::Dumper;
35
36
our $VERSION = '3.0.2.124';
37
38
my %vars;
39
40
=head1 NAME
41
42
OSDial - Perl extension for interfacing with OSDial
43
44
=head1 SYNOPSIS
45
46
use strict;
47
use OSDial;
48
49
my $osdial = OSDial->new('DB'=>1);
50
51
# Database example
52
while ( my $rec = $osdial->sql_query("SELECT * FROM servers;") ) {
53
print $rec->{server_ip} . ": " . $rec->{server_name} . "\n";
54
55
# Secondary connection and query
56
while ( my $rec2 = $osdial->sql_query( sprintf('SELECT * FROM osdial_log WHERE server_ip=%s;', $rec->quote($rec->{server_ip}) ) ) {
57
print " " . $rec2->{lead_id} . ": " . $rec2->{call_date} . ": " . $rec2->{status} . "\n";
58
}
59
60
}
61
62
# Asterisk::AGI example
63
$osdial->AGI('myscript.pl');
64
$osdial->AGI->verbose("OSDial Rocks",1);
65
$osdial->AGI->hangup();
66
67
68
=head1 DESCRIPTION
69
70
This module is inteded to provided quick and easy access to common functions
71
in OSDial. The module will read existing configuration files, connect to
72
the OSDial database, and interface with Asterisk as needed.
73
74
75
=head1 CONSTRUCTOR
76
77
=over 4
78
79
=item B - create a new OSDial object.
80
81
Creates a new C object. C optionally takes arguments in the form
82
of key value pairs.
83
84
Examples:
85
86
$osdial = OSDial->new( DB => 1);
87
88
$osdial = new OSDial( DB => 1);
89
90
$osdial = OSDial->new( VARDB_server => '127.0.0.1',
91
VARDB_database => 'osdial',
92
VARDB_user => 'osdial',
93
VARDB_pass => 'osdial1234' );
94
95
=cut
96
97
sub new {
98
my ($proto,%options) = @_;
99
my $class = ref($proto) || $proto;
100
101
&_set_defaults();
102
103
my $self = {%vars};
104
foreach my $key (keys %options) {
105
$self->{$key} = $options{$key};
106
}
107
$self->{DB} = 0 unless ($self->{DB});
108
bless $self, $class;
109
110
$self->debug(1,'new',"Initializing OSDial module, debug-level is %s.",$self->{DB});
111
112
# Load osdial.conf and database settings.
113
$self->load_config();
114
115
return $self;
116
}
117
118
sub clone {
119
my $self = shift;
120
my $copy = bless { %$self }, ref $self;
121
return $copy;
122
}
123
124
=head2 B
125
126
DB => '0'
127
128
PATHconf => '/etc/osdial.conf'
129
PATHdocs => '/usr/share/doc/osdial-3.0.2.124'
130
PATHhome => '/opt/osdial/bin'
131
PATHlogs => '/var/log/osdial'
132
PATHagi => '/var/lib/asterisk/agi-bin'
133
PATHweb => '/opt/osdial/html'
134
PATHsounds => '/var/lib/asterisk/sounds'
135
PATHmonitor => '/var/spool/asterisk/VDmonitor'
136
PATHDONEmonitor => '/var/spool/asterisk/VDmonitor'
137
PATHarchive_home => '/opt/osdial/recordings'
138
PATHarchive_unmixed => 'processing/unmixed'
139
PATHarchive_mixed => 'processing/mixed'
140
PATHarchive_sorted => 'completed'
141
PATHarchive_backup => '/opt/osdial/backups/recordings'
142
143
VARserver_ip => '127.0.0.1'
144
VARactive_keepalives => 'X'
145
146
VARDB_server => '127.0.0.1'
147
VARDB_database => 'osdial'
148
VARDB_user => 'osdial'
149
VARDB_pass => 'osdial1234'
150
VARDB_port => '3306'
151
152
VARfastagi_log_min_servers => '3'
153
VARfastagi_log_max_servers => '16'
154
VARfastagi_log_min_spare_servers => '2'
155
VARfastagi_log_max_spare_servers => '8'
156
VARfastagi_log_max_requests => '1000'
157
VARfastagi_log_checkfordead => '30'
158
VARfastagi_log_checkforwait => '60'
159
160
VARFTP_host => '127.0.0.1'
161
VARFTP_user => 'osdial'
162
VARFTP_pass => 'osdialftp1234'
163
VARFTP_port => '21'
164
VARFTP_dir => 'recordings/processing/unmixed'
165
VARHTTP_path => '/'
166
167
VARREPORT_host => '127.0.0.1'
168
VARREPORT_user => 'osdial'
169
VARREPORT_pass => 'osdialftp1234'
170
VARREPORT_port => '21'
171
VARREPORT_dir => 'reports'
172
173
VARcps => '9'
174
VARadapt_min_level => '1.5'
175
VARadapt_overlimit_mod => '20'
176
VARflush_hopper_each_run => '0'
177
VARflush_hopper_manual => '1'
178
179
180
=back
181
182
=cut
183
184
sub _set_defaults {
185
%vars = (
186
'DB' => 0,
187
188
'PATHconf' => '/etc/osdial.conf',
189
'PATHdocs' => '/usr/share/doc/osdial-3.0.2.124',
190
'PATHhome' => '/opt/osdial/bin',
191
'PATHlogs' => '/var/log/osdial',
192
'PATHagi' => '/var/lib/asterisk/agi-bin',
193
'PATHweb' => '/opt/osdial/html',
194
'PATHsounds' => '/var/lib/asterisk/sounds',
195
'PATHmonitor' => '/var/spool/asterisk/VDmonitor',
196
'PATHDONEmonitor' => '/var/spool/asterisk/VDmonitor',
197
'PATHarchive_home' => '/opt/osdial/recordings',
198
'PATHarchive_unmixed' => 'processing/unmixed',
199
'PATHarchive_mixed' => 'processing/mixed',
200
'PATHarchive_sorted' => 'completed',
201
'PATHarchive_backup' => '/opt/osdial/backups/recordings',
202
203
'VARserver_ip' => '127.0.0.1',
204
'VARactive_keepalives' => 'X',
205
206
'VARDB_server' => '127.0.0.1',
207
'VARDB_database' => 'osdial',
208
'VARDB_user' => 'osdial',
209
'VARDB_pass' => 'osdial1234',
210
'VARDB_port' => '3306',
211
'VARDB_onfail' => 'die',
212
213
'VARfastagi_log_min_servers' => '3',
214
'VARfastagi_log_max_servers' => '16',
215
'VARfastagi_log_min_spare_servers' => '2',
216
'VARfastagi_log_max_spare_servers' => '8',
217
'VARfastagi_log_max_requests' => '1000',
218
'VARfastagi_log_checkfordead' => '30',
219
'VARfastagi_log_checkforwait' => '60',
220
221
'VARFTP_host' => '127.0.0.1',
222
'VARFTP_user' => 'osdial',
223
'VARFTP_pass' => 'osdialftp1234',
224
'VARFTP_port' => '21',
225
'VARFTP_dir' => 'recordings/processing/unmixed',
226
'VARHTTP_path' => '/',
227
228
'VARREPORT_host' => '127.0.0.1',
229
'VARREPORT_user' => 'osdial',
230
'VARREPORT_pass' => 'osdialftp1234',
231
'VARREPORT_port' => '21',
232
'VARREPORT_dir' => 'reports',
233
234
'VARcps' => '9',
235
'VARadapt_min_level' => '1.5',
236
'VARadapt_overlimit_mod' => '20',
237
'VARflush_hopper_each_run' => '0',
238
'VARflush_hopper_manual' => '1',
239
240
'_sql' => { },
241
242
'_mimemap' => {
243
'g722' => 'audio/G722',
244
'g729' => 'audio/G729',
245
'gsm' => 'audio/GSM',
246
'ogg' => 'audio/ogg',
247
'ulaw' => 'audio/PCMU',
248
'alaw' => 'audio/PCMA',
249
'siren7' => 'audio/siren7',
250
'siren14' => 'audio/siren14',
251
'sln' => 'audio/sln',
252
'sln16' => 'audio/sln-16',
253
'mp3' => 'audio/mpeg',
254
'wav' => 'audio/x-wav'
255
},
256
);
257
}
258
259
=item B - load configuration.
260
261
Loads in the configuration from /etc/osdial.conf, global and server specific
262
database settings.
263
264
# Read /etc/osdial.conf setting.
265
$osdial->{VARserver_ip}
266
267
# Read setting from system_settings table.
268
$osdial->{settings}{company_name}
269
270
# Read setting for this specific server.
271
$osdial->{server}{server_id}
272
273
# Read a setting in from the configuration table.
274
$osdial->{configuration}{ArchiveHost}
275
276
=cut
277
278
sub load_config {
279
my $self = shift;
280
if (-e $self->{PATHconf}) {
281
$self->debug(4,'load_config',"Loading configuration file (%s).",$self->{PATHconf});
282
open(CONF, $self->{PATHconf}) or die 'OSDial: Error opening ' . $self->{PATHconf} . "\n";
283
while (my $line = ) {
284
$line =~ s/ |>|"|'|\n|\r|\t|\#.*|;.*//gi;
285
if ($line =~ /=|:/) {
286
my($key,$val) = split /=|:/, $line, 2;
287
$self->{$key} = $val;
288
$self->debug(4,'load_config'," %-40s => %-40s.",$key,$val);
289
}
290
}
291
292
$self->sql_max_packet();
293
294
# Load system settings.
295
$self->{settings} = $self->sql_query("SELECT * FROM system_settings LIMIT 1;");
296
foreach my $st (keys %{$self->{settings}}) {
297
$self->debug(4,'new',' %-30s => %-30s.',$st,$self->{settings}{$st});
298
}
299
300
# Load this servers settings.
301
$self->{server} = $self->sql_query(sprintf("SELECT * FROM servers WHERE server_ip='%s' LIMIT 1;", $self->{VARserver_ip}));
302
foreach my $st (keys %{$self->{server}}) {
303
$self->debug(4,'new',' %-30s => %-30s.',$st,$self->{server}{$st});
304
}
305
306
# Parse in settings from configuration table.
307
while (my $sret = $self->sql_query(sprintf("SELECT name,data FROM configuration WHERE fk_id='';"))) {
308
$self->{configuration}{$sret->{name}} = $sret->{data};
309
$self->debug(4,'new',' %-30s => %-30s.',$sret->{name},$sret->{data});
310
}
311
312
} else {
313
$self->debug(0,'load_config',"Configuration file (%s) does not exist.",$self->{PATHconf});
314
}
315
}
316
317
=head1 METHODS - AGI
318
319
This method overloads the C module, parsing C variable into the OSDial
320
object and allowing direct access to C functions.
321
322
The B method must first be called with the name of the current script or instance.
323
After the initial call, B will return the C object for execution of C events.
324
325
=over 4
326
327
=item B - starts the AGI component.
328
329
When called the first time, it will initialize the C obeject.
330
331
$osdial = new OSDial;
332
$osdial->AGI('agi-script_name.agi');
333
334
Subsequent calls to B will return a reference to the C object. This reference can
335
be used to call C functions or be assigned to another variable to be called.
336
337
$osdial->AGI->verbose("OSDial Rocks",1);
338
$osdial->AGI->hangup();
339
340
$AGI = $osdial->AGI();
341
$AGI->verbose("OSDial Rocks",1);
342
$AGI->hangup();
343
344
=back
345
346
=cut
347
348
sub AGI {
349
my ($self,$mod) = @_;
350
if (!defined $self->{_agi}) {
351
die " -- OSDial [AGI]: Function must be passed the name of the calling module." unless ($mod);
352
353
$self->{_agi} = new Asterisk::AGI;
354
my %aout = $self->{_agi}->ReadParse();
355
$self->agi_output("AGI Environment Dump:");
356
foreach my $i (sort keys %aout) {
357
$self->{_agi}{$i} = $aout{$i};
358
$self->agi_output(" -- $i = " . $self->{_agi}{$i});
359
}
360
$self->{_agi}{mod} = $mod;
361
return 1;
362
}
363
return $self->{_agi};
364
}
365
366
=over 4
367
368
=item B - AGI logging method.
369
370
This method outputs a given I<$string> to the C log file if C logging is
371
enabled for the server as defined by I. The file is stored in the
372
directory specified by the OSDial object variable I in a file called
373
I. The I<$extended_info> variable is an optional boolean flag which
374
instructs the routine to log the I, I, I, I,
375
and I C channel variables;
376
377
$osdial->agi_output("An AGI event occurred");
378
379
$osdial->agi_output("Event occurred with additional channel variables",1);
380
381
=back
382
383
=cut
384
385
386
sub agi_output {
387
my ($self,$agi_string,$extinfo) = @_;
388
if ($self->{server}{agi_output} and $self->{_agi}{mod} and $self->{_agi} and $agi_string) {
389
$agi_string .= '|' . $self->{_agi}{uniqueid} if ($self->{_agi}{uniqueid});
390
$agi_string .= '|' . $self->{_agi}{CIDlead_id} if ($self->{_agi}{CIDlead_id});
391
$agi_string .= '|' . join('|',$self->{_agi}{channel},$self->{_agi}{extension},$self->{_agi}{priority},$self->{_agi}{type},$self->{_agi}{accountcode}) if ($extinfo);
392
if ($self->{server}{agi_output} =~ /FILE|BOTH/) {
393
### open the log file for writing ###
394
my $logfile = $self->{PATHlogs} . '/agiout.' . $self->get_date();
395
open(Lout, '>>' . $logfile) or die ' -- OSDial: agi_output: Error opening ' . $logfile . "\n";
396
print Lout sprintf("\%s|\%s|\%s|\%s\n",$self->get_datetime(),$self->{_agi}{mod},$$,$agi_string);
397
close(Lout);
398
}
399
### send to STDERR writing ###
400
$self->debug(2,'agi_output','%s|%s|%s|%s',$self->get_datetime(),$self->{_agi}{mod},$$,$agi_string) if ($self->{server}{agi_output} =~ /STDERR|BOTH/);
401
}
402
}
403
404
sub agi_tts_sayphrase {
405
my ($self,$phrase,$voice,$data) = @_;
406
if (defined $self->{_agi}) {
407
foreach my $seg ($self->tts_osdial_parse($phrase,$data)){
408
my $ttsfile = $self->tts_generate($seg,$voice);
409
$self->AGI->stream_file($ttsfile) if ($ttsfile);
410
}
411
}
412
}
413
414
sub tts_osdial_parse {
415
my ($self,$phrase,$data) = @_;
416
$phrase =~ s/(\[\[[^\s]*\]\])/|||$1|||/g;
417
$phrase =~ s/(\{\{[^\s]*\}\})/|||$1|||/g;
418
my @splits;
419
foreach my $var (split('\|\|\|', $phrase)) {
420
my $tsdata;
421
if ($var =~ /\{\{[^\s]*\}\}/) {
422
my $fld = $var;
423
$fld =~ s/\{\{|\}\}//g;
424
$tsdata = '%'.$fld.'%';
425
} elsif ($var =~ /\[\[[^\s]*\]\]/) {
426
my $fld = $var;
427
$fld =~ s/\[\[|\]\]//g;
428
if (!defined($data->{$fld})) {
429
$tsdata = 'DATA_MISSING';
430
} else {
431
$tsdata = $data->{$fld};
432
}
433
} else {
434
$tsdata = $var;
435
}
436
$tsdata =~ s/^\s*$//g;
437
push @splits, $tsdata if ($tsdata ne '');
438
}
439
return @splits;
440
}
441
442
sub tts_generate {
443
my ($self,$phrase,$voice) = @_;
444
$voice = 'voice_nitech_us_rms_arctic_hts' unless ($voice);
445
my $cachedir = "/opt/osdial/tts";
446
my $sdir1 = "/mnt/ramdisk/sounds";
447
my $sdir2 = "/var/lib/asterisk/sounds";
448
449
if ($phrase =~ /^%.*%$/) {
450
$phrase =~ s/^%(.*)%$/$1/;
451
$phrase =~ s/^osdial\///;
452
return $phrase;
453
} else {
454
my $hash = md5_hex($voice.':'.$phrase);
455
my $base = 'tts-'.$hash;
456
if (! -f $cachedir.'/'.$base.'.wav') {
457
open(TXT, '>'.$cachedir.'/'.$base.'.txt');
458
print TXT $phrase . "\n";
459
close(TXT);
460
system("/usr/bin/text2wave -eval \"($voice)\" -F 8000 -o $cachedir/$base.wav $cachedir/$base.txt");
461
unlink($cachedir.'/'.$base.'.txt');
462
} else {
463
$self->debug(1,'tts_generate','%s/%s.wav already exists.',$cachedir,$base);
464
}
465
466
if(-f $cachedir.'/'.$base.'.wav') {
467
if (-d $sdir1 and -w $sdir1) {
468
if (! -d $sdir1.'/tts') {
469
$self->debug(1,'tts_generate','Making directory %s/tts.',$sdir1);
470
mkdir($sdir1.'/tts',oct('0777'));
471
}
472
if (! -f $sdir1.'/tts/'.$base.'.wav') {
473
$self->debug(1,'tts_generate','Copying %s/%s.wav to %s/tts.',$cachedir,$base,$sdir1);
474
system('/bin/cp -au '.$cachedir.'/'.$base.'.wav '.$sdir1.'/tts') unless (-f $sdir1.'/tts/'.$base.'.wav');
475
}
476
}
477
if (-d $sdir2 and -w $sdir2) {
478
if (! -d $sdir2.'/tts') {
479
$self->debug(1,'tts_generate','Making directory %s/tts.',$sdir2);
480
mkdir($sdir2.'/tts',oct('0777'));
481
}
482
if (! -f $sdir2.'/tts/'.$base.'.wav') {
483
$self->debug(1,'tts_generate','Copying %s/%s.wav to %s/tts.',$cachedir,$base,$sdir2);
484
system('/bin/cp -au '.$cachedir.'/'.$base.'.wav '.$sdir2.'/tts') unless (-f $sdir2.'/tts/'.$base.'.wav');
485
}
486
}
487
}
488
return 'tts/'.$base;
489
}
490
}
491
492
=head1 METHODS - SQL
493
494
These methods provide quick and easy access to the OSDial Database by way of its configuration files.
495
496
Every method has a definable I<$DBhandle> scalar variable. This variable is a text representation
497
of the handle being accessed. If not given, this always defaults to "A". This is very useful for
498
running nested queries, as you only need to call the nested statement with a different I<$DBhandle>.
499
Every SQL method will first check to see if the I<$DBhandle> exists and a connection to that database
500
has already been established. If a I<$DBhandle>, has not yet been opened, B will
501
automatically be called.
502
503
# Create a connection to DBhandle "A".
504
$osdial->sql_connect();
505
# Run given query against DBhandle "A".
506
$row = $osdial->sql_query("SELECT * FROM servers LIMIT 1;");
507
print $row->{"server_ip"} . "\n";
508
509
# Create a connection to DBhandle "SVR".
510
$osdial->sql_connect("SVR");
511
# Run given query against DBhandle "SVR".
512
while ($row = $osdial->sql_query("SELECT * FROM servers;","SVR")) {
513
# Run given query against DBhandle "OSDL", automatically connecting to handle.
514
$subrow = $osdial->sql_query("SELECT * FROM osdial_log WHERE server_ip='" . $row->{"server_ip"} . "';","OSDL");
515
print $subrow->{"call_date"} . "\n";
516
}
517
518
=over 4
519
520
=item B - connect to SQL server.
521
522
Connects to SQL server using sting label in I<$DBhandle>, if not given default to "A".
523
If I<$DBname> is given, B will allow you to override the respective default
524
server values for this connection.
525
526
$osdial->sql_connect("B");
527
528
=back
529
530
=cut
531
532
sub sql_connect {
533
my ($self, $dbh, $dbname, $dbsrvr, $dbport, $dbuser, $dbpass) = @_;
534
$dbh = 'A' unless ($dbh);
535
unless ($dbname) {
536
$dbname = $self->{VARDB_database};
537
$dbsrvr = $self->{VARDB_server};
538
$dbport = $self->{VARDB_port};
539
$dbuser = $self->{VARDB_user};
540
$dbpass = $self->{VARDB_pass};
541
}
542
$self->{_sql}{$dbh} = {'connected'=>0} if (!defined $self->{_sql}{$dbh});
543
if ($self->{_sql}{$dbh}{connected}<1) {
544
my $dsn = 'DBI:mysql:' . $dbname . ':' . $dbsrvr . ':' . $dbport;
545
$self->debug(5,'sql_connect',"Connecting to dbh %s at DSN: %s.",$dbh,$dsn);
546
$self->{_sql}{$dbh}{dbh} = DBI->connect($dsn,$dbuser,$dbpass);
547
my $myerr = DBI::errstr;
548
if ($myerr) {
549
$self->{_sql}{$dbh}{dbh}{mysql_auto_reconnect} = 0;
550
$self->{_sql}{$dbh}{connected} = 0;
551
if ($dbh eq 'A') {
552
$self->sql_onfail(' -- OSDial: sql_connect: ERROR ' . $myerr);
553
} else {
554
warn ' -- OSDial: sql_connect: ERROR ' . $myerr;
555
}
556
} else {
557
$self->{_sql}{$dbh}{dbh}{PrintError} = 0;
558
$self->{_sql}{$dbh}{dbh}{mysql_auto_reconnect} = 1;
559
$self->{_sql}{$dbh}{connected} = 1;
560
}
561
}
562
return $self->{_sql}{$dbh}{connected};
563
}
564
565
566
567
=over 4
568
569
=item B - disconnect from SQL server.
570
571
Disconnects from the database connection referenced by I<$DBhandle>.
572
If I<$DBhandle> is not given, it defaults to "A".
573
574
$osdial->sql_disconnect("B");
575
576
=back
577
578
=cut
579
580
sub sql_disconnect {
581
my ($self, $dbh) = @_;
582
$dbh = 'A' unless ($dbh);
583
$self->{_sql}{$dbh} = {'connected'=>0} if (!defined $self->{_sql}{$dbh});
584
if ($self->{_sql}{$dbh}{connected}>0) {
585
$self->debug(5,'sql_disconnect',"Disconnecting from dbh %s.",$dbh);
586
$self->{_sql}{$dbh}{dbh}->disconnect() if ($self->{_sql}{$dbh}{dbh});
587
$self->{_sql}{$dbh}{connected} = 0;
588
}
589
}
590
591
592
=over 4
593
594
=item B - Issues an SQL query.
595
596
The B method allows you to execute SQL statments. The
597
result is a HASHREF containing the key value pairs of a queried row.
598
This method will retain its iterative position within the running current
599
running query and will output each row on subsequent calls. If it is run
600
with a new and different query, while a previous query is currently buffered,
601
it will flush the buffer and start the new query. Just be mindful to start
602
sub-queries with a different I<$DBhandle> to avoid clearing the current buffer
603
of the parent query.
604
605
# Called in a single iteration, yeilds row #1.
606
$row = $osdial->sql_query('SELECT * FROM servers;');
607
608
# Called again with same query, yeilds row #2.
609
$row = $osdial->sql_query('SELECT * FROM servers;');
610
611
# Called again with diffent query, flushes buffer and yeilds row #1.
612
$row = $osdial->sql_query('SELECT * FROM server_stats;');
613
614
# Called in while loop, will cycle through all rows returned by query.
615
while ($row = $osdial->sql_query('SELECT * FROM servers;')) {
616
print $row->{"server_ip"} . "\n";
617
}
618
619
If an C, C, or C query is given, options will automatically
620
be passed to B.
621
622
If I<$DBhandle> does not reference a current active database connection, B
623
will automatically by called.
624
625
=back
626
627
=cut
628
629
sub sql_query {
630
my ($self,$opt1,$opt2) = @_;
631
my $row;
632
633
my $opts = {};
634
635
if (ref($opt1) eq "HASH") {
636
$opts = $opt1;
637
} elsif (ref($opt2) eq "HASH") {
638
$opts = $opt2;
639
$opts->{stmt} = $opt1;
640
} else {
641
$opts->{stmt} = $opt1;
642
$opts->{dbh} = $opt2;
643
}
644
# Set some defaults...
645
$opts->{stmt} = '' if (!defined $opts->{stmt}); # The query to execute.
646
$opts->{dbh} = 'A' if (!defined $opts->{dbh}); # the label used for dbh indentification.
647
$opts->{init} = 0 if (!defined $opts->{init}); # If 1, Stop before attempting first record grab.
648
649
my $stmt = $opts->{stmt};
650
my $dbh = $opts->{dbh};
651
652
# If dbh has not been defined, connect to DB.
653
$self->sql_connect($dbh) if (!defined $self->{_sql}{$dbh} or $self->{_sql}{$dbh}{connected}<1);
654
655
return $self->sql_execute($opts) if ($stmt =~ /^update|^insert|^delete/i);
656
657
# Check if this run is an iteration.
658
if (defined $self->{_sql}{$dbh}{last_stmt}) {
659
660
# Last stmt is set is but no sth, must have finished...
661
if (!defined $self->{_sql}{$dbh}{sth}) {
662
# stmt is not blank, and statement differs from last_stmt, clear and move on.
663
if ($stmt ne '' and $stmt ne $self->{_sql}{$dbh}{last_stmt}) {
664
delete $self->{_sql}{$dbh}{last_stmt};
665
delete $self->{_sql}{$dbh}{rows};
666
delete $self->{_sql}{$dbh}{row};
667
delete $self->{_sql}{$dbh}{sth};
668
669
# stmt is blank or same, but query already finished, clear and exit.
670
} elsif ($stmt eq '' or $stmt eq $self->{_sql}{$dbh}{last_stmt}) {
671
$self->debug(9,'sql_query',"DBH %-6s [iteration] already sent last row for this query, sending undef and exiting.",$dbh);
672
delete $self->{_sql}{$dbh}{last_stmt};
673
delete $self->{_sql}{$dbh}{rows};
674
delete $self->{_sql}{$dbh}{row};
675
return undef;
676
}
677
}
678
679
if (defined $self->{_sql}{$dbh}{sth}) {
680
# They current and previous run differ, clear and run new stmt.
681
if ($stmt ne '' and $stmt ne $self->{_sql}{$dbh}{last_stmt}) {
682
$self->debug(9,'sql_query',"DBH %-6s [iteration] last_stmt and stmt differ, clearing and moving on.",$dbh);
683
$self->{_sql}{$dbh}{sth}->finish();
684
delete $self->{_sql}{$dbh}{last_stmt};
685
delete $self->{_sql}{$dbh}{rows};
686
delete $self->{_sql}{$dbh}{row};
687
delete $self->{_sql}{$dbh}{sth};
688
689
# stmt is blank, so lets set it to the last_stmt.
690
} elsif ($stmt eq '' or $stmt eq $self->{_sql}{$dbh}{last_stmt}) {
691
$self->debug(9,'sql_query',"DBH %-6s [iteration] stmt blank or same as last_stmt, moving on.",$dbh);
692
$self->{_sql}{$dbh}{last_stmt} = $stmt;
693
}
694
}
695
}
696
697
# If connected to DB and sth has not been defined, issue query.
698
if (defined $self->{_sql}{$dbh}{dbh} and !defined $self->{_sql}{$dbh}{sth}) {
699
$self->debug(5,'sql_query',"DBH %-6s [execute] STMT: %s",$dbh, $stmt);
700
$self->{_sql}{$dbh}{sth} = $self->{_sql}{$dbh}{dbh}->prepare($stmt) or $self->sql_onfail(" -- OSDial: sql_query $dbh: ERROR " . $self->{_sql}{$dbh}{dbh}->errstr);
701
$self->{_sql}{$dbh}{sth}->execute or $self->sql_onfail(" -- OSDial: sql_query $dbh: ERROR " . $self->{_sql}{$dbh}{dbh}->errstr);
702
$self->{_sql}{$dbh}{rows} = 0;
703
$self->{_sql}{$dbh}{last_stmt} = $stmt;
704
delete $self->{_sql}{$dbh}{row};
705
}
706
707
# If sth is defined, start record grab.
708
if (defined $self->{_sql}{$dbh}{sth}) {
709
# Get row counts if we havent yet.
710
if (!defined $self->{_sql}{$dbh}{row}) {
711
$self->{_sql}{$dbh}{row} = 0;
712
$self->{_sql}{$dbh}{rows} = $self->{_sql}{$dbh}{sth}->rows();
713
$self->debug(5,'sql_query',"DBH %-6s [row_count] %s",$dbh, $self->{_sql}{$dbh}{row});
714
}
715
716
# Test if we were just initializing or if we are running.
717
if ($opts->{init} > 0) {
718
$self->debug(9,'sql_query',"DBH %-6s [init] Init is set, returning before getting first row.",$dbh);
719
return $self->{_sql}{$dbh}{rows};
720
} else {
721
# Get the record and increment count if we find one.
722
$self->debug(6,'sql_query',"DBH %-6s [fetch_row] Getting row, iteration # %s.",$dbh, $self->{_sql}{$dbh}{row});
723
$row = $self->{_sql}{$dbh}{sth}->fetchrow_hashref;
724
$row->{ROW} = ++$self->{_sql}{$dbh}{row} if ($row);
725
}
726
727
# If row count and current row are equal destroy sth and return row if there is one.
728
if ($self->{_sql}{$dbh}{row} == $self->{_sql}{$dbh}{rows}) {
729
$self->debug(7,'sql_query',"DBH %-6s [last_row] Reached last row, exiting.",$dbh);
730
$self->{_sql}{$dbh}{sth}->finish();
731
delete $self->{_sql}{$dbh}{sth};
732
}
733
}
734
return $row;
735
}
736
737
738
739
=over 4
740
741
=item B - disconnect from SQL server.
742
743
Execute the given statement in I<$query>.
744
745
# Example Insert.
746
$osdial->sql_execute("INSERT INTO table SET row='value';");
747
748
# Example Update.
749
$osdial->sql_execute("UPDATE table SET row='value' WHERE key='id';");
750
751
# Example Delete.
752
$osdial->sql_execute("DELETE FROM table WHERE key='id';");
753
754
If an C or C query is given, options will automatically
755
be passed to B.
756
757
If I<$DBhandle> does not reference a current active database connection, B
758
will automatically by called.
759
760
=back
761
762
=cut
763
764
sub sql_execute {
765
my ($self,$opt1,$opt2) = @_;
766
my $row;
767
768
my $opts = {};
769
770
if (ref($opt1) eq "HASH") {
771
$opts = $opt1;
772
} elsif (ref($opt2) eq "HASH") {
773
$opts = $opt2;
774
$opts->{stmt} = $opt1;
775
} else {
776
$opts->{stmt} = $opt1;
777
$opts->{dbh} = $opt2;
778
}
779
# Set some defaults...
780
$opts->{stmt} = '' if (!defined $opts->{stmt}); # The query to execute.
781
$opts->{dbh} = 'A' if (!defined $opts->{dbh}); # the label used for dbh indentification.
782
$opts->{init} = 0 if (!defined $opts->{init}); # If 1, Stop before attempting first record grab.
783
784
my $stmt = $opts->{stmt};
785
my $dbh = $opts->{dbh};
786
787
# If dbh has not been defined, connect to DB.
788
$self->sql_connect($dbh) if (!defined $self->{_sql}{$dbh} or $self->{_sql}{$dbh}{connected}<1);
789
790
return $self->sql_query($opts) if ($stmt =~ /^select|^show/i);
791
792
$self->debug(5,'sql_query',"DBH %-6s [execute] STMT: %s",$dbh, $stmt);
793
$self->{_sql}{$dbh}{rows} = $self->{_sql}{$dbh}{dbh}->do($stmt) or $self->sql_onfail(" -- OSDial: sql_execute $dbh: ERROR " . $self->{_sql}{$dbh}{dbh}->errstr);
794
return $self->{_sql}{$dbh}{rows};
795
}
796
797
798
799
=over 4
800
801
=item B - returns properly escaped string in single-quotes.
802
803
Returns escaped strings for inclusion in queries. Returned string is already enclosed
804
within single-quotes.
805
806
$test = $osdial->sql_quote("Here's a test.");
807
# Result: $test = "'Here\'s a test.'";
808
809
Aliases for B include B and B.
810
811
=back
812
813
=cut
814
815
sub sql_quote {
816
my ($self,$string) = @_;
817
my $dbh = 'A';
818
# If dbh has not been defined, connect to DB.
819
$self->sql_connect($dbh) if (!defined $self->{_sql}{$dbh} or $self->{_sql}{$dbh}{connected}<1);
820
return $self->{_sql}{$dbh}{dbh}->quote($string);
821
}
822
sub quote { return sql_quote(@_); }
823
sub mres {
824
my $dequote = sql_quote(@_);
825
$dequote =~ s/^'|'$//g;
826
return $dequote;
827
}
828
829
830
sub sql_onfail {
831
my ($self,$string) = @_;
832
if ($self->{VARDB_onfail} eq 'warn') {
833
warn $string;
834
} else {
835
die $string;
836
}
837
}
838
839
840
=over 4
841
842
=item B - returns the dbh handle.
843
844
Returns the maximum allowed packet size that the SQL server will except.
845
846
$dbhandle = $osdial->sql_dbh($dbh);
847
848
=back
849
850
=cut
851
852
sub sql_dbh {
853
my ($self, $dbh) = @_;
854
$dbh = 'A' unless ($dbh);
855
# If dbh has not been defined, connect to DB.
856
$self->sql_connect($dbh) if (!defined $self->{_sql}{$dbh} or $self->{_sql}{$dbh}{connected}<1);
857
return $self->{_sql}{$dbh}{dbh};
858
}
859
860
861
=over 4
862
863
=item B - returns the last insert id.
864
=item B - returns the last insert id.
865
=item B - returns the last insert id.
866
=item B - returns the last insert id.
867
868
Returns the last insert ID.
869
870
$insertid = $osdial->sql_last_insert_id($dbh);
871
$insertid = $osdial->sql_last_insertid($dbh);
872
$insertid = $osdial->sql_last_id($dbh);
873
$insertid = $osdial->sql_insert_id($dbh);
874
875
=back
876
877
=cut
878
879
sub sql_last_insert_id {
880
my ($self, $dbh) = @_;
881
$dbh = 'A' unless ($dbh);
882
# If dbh has not been defined, connect to DB.
883
$self->sql_connect($dbh) if (!defined $self->{_sql}{$dbh} or $self->{_sql}{$dbh}{connected}<1);
884
return $self->sql_dbh($dbh)->{'mysql_insertid'};
885
}
886
sub sql_last_insertid { return sql_last_insert_id(@_); }
887
sub sql_last_id { return sql_last_insert_id(@_); }
888
sub sql_insert_id { return sql_last_insert_id(@_); }
889
890
891
=over 4
892
893
=item B - returns maximum packet allowed.
894
895
Returns the maximum allowed packet size that the SQL server will except.
896
897
$max_packet = $osdial->sql_max_packet();
898
899
=back
900
901
=cut
902
903
sub sql_max_packet {
904
my ($self) = @_;
905
if (!defined $self->{_sql_max_allowed_packet}) {
906
my $sret = $self->sql_query("SHOW variables LIKE 'max_allowed_packet';");
907
$self->{_sql_max_allowed_packet} = $sret->{'Value'};
908
}
909
$self->debug(5,'sql_max_packet',"SQL Max Packet Size: %s",$self->{_sql_max_allowed_packet});
910
return $self->{_sql_max_allowed_packet};
911
}
912
913
914
915
=head1 METHODS - OSDial
916
917
General methods for OSDial that help with everyday functions.
918
919
=over 4
920
921
=item B - Send debug output to STDERR.
922
923
If I<$level> matches the current Debug Level set by I, then output a debug statement to STDERR.
924
The name of the calling module should be specified in I<$module>. The outputted string is taken
925
in the same format as B in the form of I<$sprintf_string> and I<@sprintf_params>.
926
927
$osdial->debug(1,'main', 'The %s function failed!', $var);
928
929
=back
930
931
=cut
932
933
sub debug {
934
my ($self, $lev, $mod, $string, @params) = @_;
935
if($self->{DB}>=$lev) {
936
my $p = 2+$lev;
937
my @sprint = (' ',$mod,@params);
938
$string .= "\n" unless($string =~ /\n$/);
939
print STDERR sprintf('%'.$p.'s-- OSDial [%s]: '.$string,@sprint);
940
}
941
}
942
943
944
945
=over 4
946
947
=item B - Send event to logfile.
948
949
Sends an event, I<$string>, to the logfile in C, named I<$logfile>.YYYY-MM-DD.
950
951
$osdial->event_logger('eventlog','An event was triggered.');
952
953
=back
954
955
=cut
956
957
sub event_logger {
958
my ($self,$type,$string) = @_;
959
if ($type and $string) {
960
my $logfile = $self->{PATHlogs} . '/' . $type . '.' . $self->get_date();
961
open(LOG, '>>' . $logfile) or die ' -- OSDial: event_logger: Error opening ' . $logfile . "\n";
962
print LOG sprintf("\%s|\%s|\%s\n",$self->get_datetime(),$$,$string);
963
close(LOG);
964
}
965
}
966
967
968
969
=over 4
970
971
=item B
972
973
Returns B or I<$time>, if given, in the format: YYYY-MM-DD HH:MM:SS
974
975
$osdial->get_datetime();
976
977
=back
978
979
=cut
980
981
sub get_datetime {
982
my($self,$tms) = @_;
983
$tms = time() unless ($tms);
984
my ($s,$m,$h,$D,$M,$Y,$wday,$yday,$isdst) = localtime($tms);
985
$Y += 1900;
986
return sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', $Y, ++$M, $D, $h, $m, $s);
987
}
988
989
990
991
=over 4
992
993
=item B
994
995
Returns B or I<$time>, if given, in the format: YYYY-MM-DD
996
997
$osdial->get_date();
998
999
=back
1000
1001
=cut
1002
1003
sub get_date {
1004
my($self,$tms) = @_;
1005
return substr($self->get_datetime($tms),0,10);
1006
}
1007
1008
1009
1010
1011
=over 4
1012
1013
=item B
1014
1015
All files in I<$directory> are scaned and loaded into the databsae if they do not already exist in it.
1016
1017
The I<$pattern> variable allows for a regex expression to be applied against the filename. The default I<$patter> is C<.*>.
1018
1019
If the file exists in the database and I<$update_data> is true, the data is updated. The default action
1020
is to skip files which are already present.
1021
1022
=back
1023
1024
=cut
1025
1026
sub media_add_files {
1027
my ($self,$dir,$pattern,$updatedata) = @_;
1028
$dir = '.' unless ($dir);
1029
$updatedata = 0 unless ($updatedata);
1030
$pattern = '.*' unless ($pattern);
1031
1032
$self->debug(3,'media_add_files',"Adding Directory:%s Pattern:%s Update:%s",$dir,$pattern, $updatedata);
1033
my @files;
1034
return @files if (!-d $dir );
1035
opendir(MAFDIR,$dir);
1036
foreach my $filename (readdir(MAFDIR)) {
1037
if ($filename ne '.' and $filename ne '..' and $filename =~ /$pattern/ and not -d $filename) {
1038
my $file = $dir.'/'.$filename;
1039
1040
my $mime = $filename;
1041
$mime =~ s/.*\.//;
1042
1043
my $extension = $filename;
1044
$extension =~ s/.*\/|\..*$//;
1045
$extension = '' unless ($extension =~ /^\d+$/);
1046
1047
my $addfile = $self->media_add_file($file, $self->{'_mimemap'}{lc($mime)}, $filename, $extension, $updatedata);
1048
push @files, $addfile if ($addfile);
1049
}
1050
}
1051
closedir(MAFDIR);
1052
return @files;
1053
}
1054
1055
1056
1057
=over 4
1058
1059
=item B
1060
1061
This function opens the media file I<$filepath> and splits the binary data into segments which are
1062
small enough to be sent to the SQL server without exceeding the C size.
1063
1064
If I<$mimetype> is not given, it will be guessed using the extension of I<$filepath>.
1065
1066
g722 => 'audio/G722'
1067
g729 => 'audio/G729'
1068
gsm => 'audio/GSM'
1069
ogg => 'audio/ogg'
1070
ulaw => 'audio/PCMU'
1071
alaw => 'audio/PCMA'
1072
siren7 => 'audio/siren7'
1073
siren14 => 'audio/siren14'
1074
sln => 'audio/sln'
1075
sln16 => 'audio/sln-16'
1076
mp3 => 'audio/mpeg'
1077
wav => 'audio/x-wav'
1078
1079
If I<$description> is not given, the filename is stripped off of I<$filepath> and used.
1080
1081
If I<$extension> is not given and the filename is not numeric, it is left blank. If the filename will
1082
be used if it is numeric.
1083
1084
If the file exists in the database and I<$update_data> is true, the data is updated. The default action
1085
is to skip files which are already present.
1086
1087
=back
1088
1089
=cut
1090
1091
sub media_add_file {
1092
my ($self,$file,$mimetype,$description,$extension,$updatedata) = @_;
1093
my $filename=$file;
1094
$filename =~ s/.*\///;
1095
unless ($mimetype) {
1096
my $mime = $filename;
1097
$mime =~ s/.*\.//;
1098
$mimetype = $self->{'_mimemap'}{lc($mime)};
1099
}
1100
$description = $filename unless ($description);
1101
unless ($extension) {
1102
$extension = $filename;
1103
$extension =~ s/.*\/|\..*$//;
1104
$extension = '' unless ($extension =~ /^\d+$/);
1105
}
1106
$updatedata = 0 unless ($updatedata);
1107
1108
$self->debug(3,'media_add_file'," Adding File:%s Name:%s Mime:%s Desc:%s Ext:%s Update:%s", $file, $filename, $mimetype, $description, $extension, $updatedata);
1109
return '!'.$filename unless (-e $file);
1110
1111
1112
my $sret = $self->sql_query(sprintf('SELECT count(*) fncnt FROM osdial_media WHERE filename=%s;',$self->quote($filename)),'MAF');
1113
if ($sret->{fncnt}==0) {
1114
$self->sql_execute(
1115
sprintf('INSERT INTO osdial_media SET filename=%s,mimetype=%s,description=%s,extension=%s;',
1116
$self->quote($filename), $self->quote($mimetype), $self->quote($description), $self->quote($extension) ),'MAF' );
1117
} else {
1118
my $sret = $self->sql_query(sprintf('SELECT count(*) fncnt FROM osdial_media_data WHERE filename=%s;',$self->quote($filename)),'MAF');
1119
if ($sret->{fncnt}>0) {
1120
if ($updatedata>0) {
1121
$self->media_delete_filedata($filename);
1122
} else {
1123
$self->sql_disconnect('MAF');
1124
return '*'.$filename;
1125
}
1126
}
1127
}
1128
1129
1130
my $data="";
1131
my $max_packet = $self->sql_max_packet() - 120_000;
1132
open(MAF, '<'.$file);
1133
binmode(MAF);
1134
while (read(MAF, $data, $max_packet ) ) {
1135
$self->sql_execute( sprintf('INSERT INTO osdial_media_data SET filename=%s,filedata=%s;', $self->quote($filename), $self->quote($data) ),'MAF' ) if ($data);
1136
}
1137
close(MAF);
1138
$self->sql_disconnect('MAF');
1139
return '='.$filename if ($updatedata);
1140
return '+'.$filename;
1141
}
1142
1143
1144
1145
=over 4
1146
1147
=item B
1148
1149
Removes all entries in the C table associated with I<$filename>.
1150
1151
=back
1152
1153
=cut
1154
1155
sub media_delete_filedata {
1156
my ($self, $filename) = @_;
1157
$self->debug(3,'media_delete_filedata'," Deleting Filedata:%s", $filename);
1158
$self->sql_execute( sprintf('DELETE FROM osdial_media_data WHERE filename=%s;', $self->quote($filename) ),'MDFD' );
1159
$self->sql_disconnect('MDFD');
1160
}
1161
1162
1163
1164
=over 4
1165
1166
=item B
1167
1168
Combines all of the entries in the C table associated with I<$filename> and returns the binary data.
1169
1170
=back
1171
1172
=cut
1173
1174
sub media_get_filedata {
1175
my ($self, $filename) = @_;
1176
$self->debug(3,'media_get_filedata'," Get Filedata:%s", $filename);
1177
my $filedata;
1178
while (my $sret = $self->sql_query( sprintf("SELECT filedata FROM osdial_media_data WHERE filename=%s;", $self->quote($filename) ), 'MGFD' ) ) {
1179
$filedata .= $sret->{filedata};
1180
}
1181
$self->sql_disconnect('MGFD');
1182
return $filedata;
1183
}
1184
1185
1186
1187
=over 4
1188
1189
=item B
1190
1191
Export entry matching I<$filename> and save into the given I<$directory>.
1192
File is skipped and is not overwitten unless I<$overwrite> is true.
1193
1194
=back
1195
1196
=cut
1197
1198
sub media_save_file {
1199
my ($self,$dir,$filename,$overwrite) = @_;
1200
$dir = '.' unless ($dir);
1201
$overwrite = 0 unless ($overwrite);
1202
unless (-e $dir) {
1203
mkdir($dir,oct('0777'));
1204
my ($login,$pass,$uid,$gid) = getpwnam('asterisk');
1205
chown($uid,$gid,$dir);
1206
}
1207
chmod(oct('0777'),$dir);
1208
1209
my $file = $dir.'/'.$filename;
1210
$self->debug(3,'media_save_file'," Adding File:%s Dir:%s Name:%s Overwrite:%s", $file, $dir, $filename, $overwrite);
1211
return '*'.$filename if (-e $file and $overwrite==0);
1212
1213
my $filedata = $self->media_get_filedata($filename);
1214
return '!'.$filename unless ($filedata);
1215
1216
open(MSF, '>'.$file);
1217
binmode(MSF);
1218
print MSF $filedata;
1219
close(MSF);
1220
my ($login,$pass,$uid,$gid) = getpwnam('asterisk');
1221
chown($uid,$gid,$file);
1222
chmod(oct('0666'),$file);
1223
1224
return '='.$filename if ($overwrite);
1225
return '+'.$filename;
1226
}
1227
1228
1229
1230
=over 4
1231
1232
=item B
1233
1234
All files matching the regex I<$patten> are exported and saved into the given I<$directory>.
1235
The default I<$pattern> is C<.*>. Files are skipped and not overwitten unless I<$overwrite> is true.
1236
1237
=back
1238
1239
=cut
1240
1241
sub media_save_files {
1242
my ($self,$dir,$pattern,$overwrite) = @_;
1243
$dir = '.' unless ($dir);
1244
$overwrite = 0 unless ($overwrite);
1245
$pattern = '.*' unless ($pattern);
1246
$self->debug(3,'media_save_files',"Adding Files:%s Pattern:%s Overwrite:%s", $dir, $pattern, $overwrite);
1247
unless (-e $dir) {
1248
mkdir($dir,oct('0777'));
1249
my ($login,$pass,$uid,$gid) = getpwnam('asterisk');
1250
chown($uid,$gid,$dir);
1251
}
1252
chmod(oct('0777'),$dir);
1253
1254
my @files;
1255
while (my $sret = $self->sql_query("SELECT * FROM osdial_media;", "MSF")) {
1256
if ($sret->{filename} =~ /$pattern/) {
1257
push @files, $self->media_save_file($dir, $sret->{filename}, $overwrite);
1258
chmod(oct('0666'),$dir.'/'.$sret->{filename});
1259
}
1260
}
1261
$self->sql_disconnect('MSF');
1262
return @files;
1263
}
1264
1265
1266
1267
=over 4
1268
1269
=item B
1270
=item B$host, port=>$port, user=>$user, pass=>$pass, to=>$to, from=>$from, subject=>$subject, $html=>$html, text=>$text })>
1271
1272
Sends out an email using the given parameters. Returns 1 on success, 0 on failure.
1273
1274
=back
1275
1276
=cut
1277
1278
sub send_email {
1279
my ($self, $opt1, $port, $user, $pass, $to, $from, $subject, $html, $text) = @_;
1280
1281
my $host='';
1282
1283
if (ref($opt1) =~ /HASH/) {
1284
$host = $opt1->{'host'} if (exists($opt1->{'host'}));
1285
$port = $opt1->{'port'} if (exists($opt1->{'port'}));
1286
$user = $opt1->{'user'} if (exists($opt1->{'user'}));
1287
$pass = $opt1->{'pass'} if (exists($opt1->{'pass'}));
1288
$to = $opt1->{'to'} if (exists($opt1->{'to'}));
1289
$from = $opt1->{'from'} if (exists($opt1->{'from'}));
1290
$subject = $opt1->{'subject'} if (exists($opt1->{'subject'}));
1291
if (exists($opt1->{'message'})) {
1292
$text=$opt1->{'message'};
1293
$html="".$text.' ';
1294
} else {
1295
$html = $opt1->{'html'} if (exists($opt1->{'html'}));
1296
$text = $opt1->{'text'} if (exists($opt1->{'text'}));
1297
}
1298
} else {
1299
$host = $opt1;
1300
}
1301
1302
$host='localhost' if (!defined($host) or $host eq '');
1303
$port='25' if (!defined($port) or $port eq '');
1304
1305
my $transparams = { 'host' => $host, 'port' => $port };
1306
if (defined($user) and $user ne '') {
1307
$transparams->{'sasl_username'} = $user;
1308
$transparams->{'sasl_password'} = $pass;
1309
}
1310
1311
my $transport = Email::Sender::Transport::SMTP->new($transparams);
1312
1313
my $email = Email::Stuffer->to($to)
1314
->from($from)
1315
->subject($subject)
1316
->text_body($text)
1317
->html_body($html)
1318
->transport($transport);
1319
1320
my $eres = $email->send();
1321
1322
return 1 if (ref($eres) =~ /^Email::Sender::Success/);
1323
return 0;
1324
}
1325
1326
1327
1328
=over 4
1329
1330
=item B$server_ip, unqiueid=>$unqiueid, callerid=>$callerid, user=>$user, campaign_id=>$campaign_id, group_id=>$group_id, lead_id=>$lead_id, event=>$event, data1=>$data1, data2=>$data2, data3=>$data3, data4=>$data4, data5=>$data5, data6=>$data6 })>
1331
1332
Records the given data into the osdial_events table.
1333
1334
=back
1335
1336
=cut
1337
1338
sub osdevent {
1339
my ($self,$optref) = @_;
1340
my $opts = {};
1341
if (ref($optref) eq "HASH") {
1342
$opts = $optref;
1343
}
1344
my $oelsql = '';
1345
foreach my $opt (sort keys %{$opts}) {
1346
$oelsql .= sprintf("%s=%s,",$opt,$self->quote($opts->{$opt}));
1347
}
1348
chop($oelsql);
1349
if (length($oelsql)>0) {
1350
$self->sql_execute(sprintf('INSERT INTO osdial_events SET %s;', $oelsql),'OEL');
1351
return $self->sql_last_insert_id('OEL');
1352
}
1353
return 0;
1354
}
1355
1356
1357
1358
sub server_process_tracker {
1359
my ($self,$prog,$server_ip,$pid,$allow_multiple) = @_;
1360
my $pcount=0;
1361
my $ret=1;
1362
my $procs = {};
1363
while (my $sret = $self->sql_query(sprintf("SELECT id,name,server_ip,pid,IF(UNIX_TIMESTAMP(last_checkin)>UNIX_TIMESTAMP()-180 AND pid>0,1,0) AS is_alive FROM server_keepalive_processes WHERE name='%s' ORDER BY last_checkin DESC;",$self->mres($prog)))) {
1364
if (!defined($procs->{$prog})) {
1365
$procs->{$prog} = { 'id'=>$sret->{id}, 'server_ip' => $sret->{server_ip}, 'pid' => $sret->{pid}, 'is_alive' => $sret->{is_alive} };
1366
}
1367
$pcount++;
1368
}
1369
if ($pcount==0) {
1370
my $sret = $self->sql_query(sprintf("SELECT id FROM server_keepalive_processes WHERE name='%s' AND server_ip='%s' ORDER BY last_checkin DESC LIMIT 1;",$self->mres($prog),$self->mres($server_ip)));
1371
if (defined($sret->{ROW}) and $sret->{ROW} > 0) {
1372
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($sret->{id})));
1373
} else {
1374
$self->sql_execute(sprintf("INSERT INTO server_keepalive_processes SET server_ip='%s',name='%s',pid='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid)));
1375
}
1376
$ret=0;
1377
} else {
1378
foreach my $name (keys %{$procs}) {
1379
if ($procs->{$name}{is_alive}>0) {
1380
if ($procs->{$name}{server_ip} eq $server_ip) {
1381
if ($procs->{$name}{pid} eq $pid) {
1382
if ($procs->{$name}{pid}>0 and pexists($procs->{$name}{pid})) {
1383
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($procs->{$name}{id})));
1384
} else {
1385
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres('0'),$self->mres($procs->{$name}{id})));
1386
}
1387
$ret=0;
1388
} else {
1389
if ($procs->{$name}{pid}>0 and pexists($procs->{$name}{pid})) {
1390
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($procs->{$name}{pid}),$self->mres($procs->{$name}{id})));
1391
} else {
1392
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($procs->{$name}{id})));
1393
}
1394
$ret=0;
1395
}
1396
} else {
1397
if ($allow_multiple>0) {
1398
my $sret = $self->sql_query(sprintf("SELECT id FROM server_keepalive_processes WHERE name='%s' AND server_ip='%s' ORDER BY last_checkin DESC LIMIT 1;",$self->mres($prog),$self->mres($server_ip)));
1399
if (defined($sret->{ROW}) and $sret->{ROW} > 0) {
1400
1401
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($sret->{id})));
1402
} else {
1403
$self->sql_execute(sprintf("INSERT INTO server_keepalive_processes SET server_ip='%s',name='%s',pid='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid)));
1404
}
1405
$ret=0;
1406
}
1407
}
1408
} else {
1409
if ($procs->{$name}{server_ip} eq $server_ip) {
1410
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($procs->{$name}{id})));
1411
$ret=0;
1412
} else {
1413
if ($allow_multiple>0) {
1414
my $sret = $self->sql_query(sprintf("SELECT id FROM server_keepalive_processes WHERE name='%s' AND server_ip='%s' ORDER BY last_checkin DESC LIMIT 1;",$self->mres($prog),$self->mres($server_ip)));
1415
if (defined($sret->{ROW}) and $sret->{ROW} > 0) {
1416
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($sret->{id})));
1417
} else {
1418
$self->sql_execute(sprintf("INSERT INTO server_keepalive_processes SET server_ip='%s',name='%s',pid='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid)));
1419
}
1420
$ret=0;
1421
} else {
1422
$self->sql_execute(sprintf("UPDATE server_keepalive_processes SET server_ip='%s',name='%s',pid='%s',last_checkin=NOW() WHERE id='%s';",$self->mres($server_ip),$self->mres($prog),$self->mres($pid),$self->mres($procs->{$name}{id})));
1423
$ret=0;
1424
}
1425
}
1426
}
1427
}
1428
}
1429
return $ret;
1430
}
1431
1432
1433
1434
1435
1436
# Make sure we do a little cleanup before exiting.
1437
sub DESTROY {
1438
my $self = shift;
1439
foreach my $dbh (keys %{$self->{_sql}}) {
1440
$self->sql_disconnect($dbh) if ($self->{_sql}{$dbh}{connected}>0);
1441
}
1442
}
1443
1444
1445
1;
1446
__END__