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