option to skip SSL validation for http export, RT#29298
[freeside.git] / FS / FS / part_export / freeswitch.pm
1 package FS::part_export::freeswitch;
2 use base qw( FS::part_export );
3
4 use vars qw( %info ); # $DEBUG );
5 #use Data::Dumper;
6 use Tie::IxHash;
7 use Text::Template;
8 use FS::Record qw( qsearch ); #qsearchs );
9 use FS::svc_phone;
10 #use FS::Schema qw( dbdef );
11
12 #$DEBUG = 1;
13
14 tie my %options, 'Tie::IxHash',
15   'user'  => { label => 'SSH username', default=>'root', },
16   'directory' => { label   => 'Directory to store FreeSWITCH account XML files (one file per domain)',
17                    default => '/usr/local/freeswitch/conf/directory/',
18                  },
19   #'domain'    => { label => 'Optional fixed SIP domain to use, overrides svc_phone domain', },
20   'reload'    => { label   => 'Reload command',
21                    default => '/usr/local/freeswitch/bin/fs_cli -x reloadxml',
22                  },
23   'header_template' => { label   => 'Domain XML configuration header',
24                          type    => 'textarea',
25                          default => <<'END',
26 <?xml version="1.0"?>
27 <include>
28   <domain name="<% $domain %>">
29     <groups>
30       <group name="default">
31         <users>
32 END
33                        },
34   'user_template'   => { label   => 'User XML configuration template',
35                          type    => 'textarea',
36                          default => <<'END',
37           <user id="<% $phonenum %>">
38             <params>
39               <param name="password" value="<% $sip_password %>"/>
40             </params>
41           </user>
42
43 END
44                        },
45   'footer_template' => { label   => 'Domain XML configuration footer',
46                          type    => 'textarea',
47                          default => <<'END',
48         </users>
49       </group>
50     </groups>
51   </domain>
52 </include>
53 END
54                        },
55 ;
56
57 %info = (
58   'svc'     => 'svc_phone',
59   'desc'    => 'Provision phone services to FreeSWITCH XML configuration files',
60   'options' => \%options,
61   'notes'   => <<'END',
62 Export XML account configuration files to FreeSWITCH, one per domain.
63 <br><br>
64 You will need to enable the svc_phone-domain configuration setting and
65 <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.9:Documentation:Administration:SSH_Keys">setup SSH for unattended operation</a>.
66 END
67 );
68
69 sub rebless { shift; }
70
71 sub _export_insert {
72   my( $self, $svc_phone ) = ( shift, shift );
73
74   $self->_export_rebuild_domain($svc_phone);
75
76 }
77
78 sub _export_replace {
79   my( $self, $new, $old ) = ( shift, shift, shift );
80
81   my $error = $self->_export_rebuild_domain($new);
82   return $error if $error;
83
84   if ( $new->domsvc ne $old->domsvc && $old->domsvc ) {
85     $error = $self->_export_rebuild_domain($old);
86     return $error if $error;
87   }
88
89   '';
90 }
91
92 sub _export_delete {
93   my( $self, $svc_phone ) = ( shift, shift );
94
95   $self->_export_rebuild_domain($svc_phone);
96 }
97
98 sub _export_rebuild_domain {
99   my($self, $svc_phone) = ( shift, shift );
100
101   eval "use Net::SCP;";
102   die $@ if $@;
103
104   #create and copy over file
105
106   my $tempdir = '%%%FREESIDE_CONF%%%/cache.'. $FS::UID::datasrc;
107
108   my $domain = $svc_phone->domain or return "domain required";
109
110   my $fh = new File::Temp(
111     TEMPLATE => "$tempdir/freeswitch.$domain.XXXXXXXX",
112     DIR      => $dir,
113     #UNLINK   => 0,
114   );
115
116   print $fh $self->freeswitch_template_fillin( $domain, 'header' )
117     or die "print to freeswitch template failed: $!";
118
119   my @dom_svc_phone = qsearch( 'svc_phone', { 'domsvc'=>$svc_phone->domsvc } );
120
121   foreach my $dom_svc_phone (@dom_svc_phone) {
122
123     print $fh $self->freeswitch_template_fillin( $dom_svc_phone, 'user' )
124       or die "print to freeswitch template failed: $!";
125
126   }
127
128   print $fh $self->freeswitch_template_fillin( $domain, 'footer' )
129     or die "print to freeswitch template failed: $!";
130
131   $fh->flush;
132
133   my $scp = new Net::SCP;
134   my $user = $self->option('user')||'root';
135   my $host = $self->machine;
136   my $dir = $self->option('directory');
137
138   $scp->scp( $fh->filename, "$user\@$host:$dir/$domain.xml" )
139     or return $scp->{errstr};
140
141   #signal freeswitch to reload config
142   $self->freeswitch_ssh( command => $self->option('reload') );
143
144   '';
145
146 }
147
148 sub freeswitch_template_fillin {
149   my( $self, $svc_phone_or_dom, $template ) = (shift, shift, shift);
150
151   $template ||= 'user'; #?
152
153   #cache a %tt hash?
154   my $tt = new Text::Template (
155     TYPE       => 'STRING',
156     SOURCE     => $self->option($template.'_template'),
157     DELIMITERS => [ '<%', '%>' ],
158   );
159
160   #false lazinessish w/phone_shellcommands::_export_command
161   my %hash = ref($svc_phone_or_dom)
162    ? ( map { $_ => $svc_phone_or_dom->getfield($_) } $svc_phone_or_dom->fields )
163    : ( 'domain' => $svc_phone_or_dom );
164
165   #might as well do em all, they're all going in an XML file as attribs
166   foreach ( keys %hash ) {
167     $hash{$_} =~ s/'/&apos;/g;
168     $hash{$_} =~ s/"/&quot;/g;
169   }
170
171   $tt->fill_in(
172     HASH => \%hash,
173   );
174 }
175
176 ##a good idea to queue anything that could fail or take any time
177 #sub shellcommands_queue {
178 #  my( $self, $svcnum ) = (shift, shift);
179 #  my $queue = new FS::queue {
180 #    'svcnum' => $svcnum,
181 #    'job'    => "FS::part_export::freeswitch::ssh_cmd",
182 #  };
183 #  $queue->insert( @_ );
184 #}
185
186 sub freeswitch_ssh { #method
187   my $self = shift;
188   ssh_cmd( user    => $self->option('user')||'root',
189            host    => $self->machine,
190            @_,
191          );
192 }
193
194 sub ssh_cmd { #subroutine, not method
195   use Net::OpenSSH;
196   my $opt = { @_ };
197   open my $def_in, '<', '/dev/null' or die "unable to open /dev/null";
198   my $ssh = Net::OpenSSH->new( $opt->{'user'}.'@'.$opt->{'host'},
199                                default_stdin_fh => $def_in,
200                              );
201   die "Couldn't establish SSH connection: ". $ssh->error if $ssh->error;
202   my ($output, $errput) = $ssh->capture2( #{stdin_discard => 1},
203                                           $opt->{'command'}
204                                         );
205   die "Error running SSH command: ". $ssh->error if $ssh->error;
206
207   #who the fuck knows what freeswitch reload outputs, probably a fucking
208   # ascii advertisement for cluecon
209   #die $errput if $errput;
210   #die $output if $output;
211
212   '';
213 }
214
215 1;