File Coverage

blib/lib/OSDial.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


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
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__