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