#!/usr/bin/perl # # add_user # # Add one or more users to the XML directory # # use strict; use warnings; use Getopt::Long; use Data::Dumper; ## Useful items my $path_sep; my $config_path; my @dir_elem; my $user_template = &get_user_template; my $new_user_count = 0; ## Command line args my $users; my $domain; my $dirpath; my $help; ## Misc items somewhat related to cmd line args my $start; my $end; my $user; ## Check for Windows vs. *nix if ( $^O =~ m/^win/i ) { ## Detected Windows (probably) $path_sep = "\\"; # single backslash (\) use File::Spec::Win32; } else { $path_sep = '/'; # single slash (/) use File::Spec; } GetOptions( 'h' => \$help, 'help' => \$help, 'domain=s' => \$domain, 'users=s' => \$users, 'confpath=s' => \$config_path, ); if ( $help ) { usage(); exit(0); } if ( ! $domain ) { $domain='default'; } ## Validate users if specified on command line if ( $users ) { ($start,$end) = split /-/,$users; if ( ! $start && ! $end ) { die "Please specify both a start and end range, separated by a hyphen:\n add_user --users=xxxx-yyyy\n"; } unless ( $start =~ m/[1-9]\d+/ ) { die "Start of range '$start' is not numeric or is too short\n"; } unless ( $end =~ m/[1-9]\d+/ ) { die "End of range '$end' is not numberic or is too short\n"; } if ( $end <= $start ) { die "End of range needs to be greater than start of range\n"; } } else { ## Look for user id in $ARGV[0] if ( ! $ARGV[0] ) { die "You must specify user id as a command line argument to add user, or use the --users option.\n"; } unless ( $ARGV[0] =~ m/^[1-9]\d+$/ ) { die "User id must be numeric, be at least 2 digits long, and cannot begin with the digit zero.\n" } $user = $ARGV[0]; } if ( ! $config_path ) { $config_path = '/usr/local/freeswitch/conf'; } ## Check to make sure the directories in question exists unless ( -d $config_path ) { die "Configuration path '$config_path' does not exist.\n"; } my $directory_path = $config_path . $path_sep . 'directory'; unless ( -d $directory_path ) { die "Directory path '$directory_path' does not exist.\n"; } ## Now check domain pathname and test existence if ( ! $domain ) { $domain = 'default'; } ## Full directory path includes the domain name my $full_dir_path = $directory_path . $path_sep . $domain; unless ( -d $full_dir_path ) { die "Full path to directory and domain '$full_dir_path' does not exist. \n"; } unless ( -w $full_dir_path ) { die "This user does not have write access to '$full_dir_path'.\n"; } print "\n"; ## Regexp assemble items to show user what a PCRE might look like for his new users my $ra_present; my $ra_new; my $ra_all; eval { require Regexp::Assemble; }; if ( ! $@ ) { ## If Regexp::Assemble is available flag it for later building regexes $ra_present = 'true'; $ra_new = Regexp::Assemble->new( # new user regex reduce => 1, flags => 0, ); $ra_all = Regexp::Assemble->new( # all users regex w/ new users thrown in reduce => 1, flags => 0, ); } ## If we're this far then we can read in the existing users and put them in a hash ## Later we can check hash to avoid adding duplicate users my %current_users; my @CURRENT_USER_FILES = glob($full_dir_path . $path_sep . '*.xml'); foreach ( @CURRENT_USER_FILES ) { #print "User: $_\n"; open(FILEIN,'<',$_); while() { next unless m/user id|number-alias/; m/user id="(\d+)"/; my $user_id = $1; if ( ! $user_id ) { m/alias="(\d+)"/; $user_id = $1; } next unless $user_id; $current_users{$user_id}++; if ( $ra_present && $user_id =~ m/^\d+$/ ) { #print "Adding $user_id to \$re_all...\n"; $ra_all->add($user_id)->anchor_line_begin->anchor_line_end; } last; } close(FILEIN); } #print Dumper(%current_users) . "\n"; if ( $start && $end ) { ## Add range of users foreach $user ($start .. $end) { &add_user($user); } } else { ## Add single user &add_user($user); } print "\nOperation complete. "; if ( $new_user_count == 0 ) { print "No users added.\n"; exit(0); } else { printf "%d user%s added.\n", $new_user_count, $new_user_count==1 ? "" : "s"; print "Be sure to reloadxml.\n\n"; } if ( $ra_present ) { print "Regular expression information:\n\n"; ## Regexp::Assemble adds some stuff we really don't need ## These lines just make the regexp pattern a bit more readable my $tmp = $ra_new->as_string; $tmp =~ s/\?://g; $tmp =~ s/^\(\?\-xism:\^/^(/; $tmp =~ s/\$\)$/)\$/; $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d print " Sample regex for all new users: " . $tmp . "\n"; $tmp = $ra_all->as_string; $tmp =~ s/\?://g; $tmp =~ s/^\(\?\-xism:\^/^(/; $tmp =~ s/\$\)$/)\$/; $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d print "Sample regex for all new AND current users: " . $tmp . "\n\n"; print "In the default configuration you can modify the expression in the condition for 'Local_Extension'.\n"; print "" } else { print "If CPAN module Regexp::Assemble were installed this program would be able to suggest a regex for your new users.\n" } exit(0); sub add_user { my $user_id = shift; if ( exists( $current_users{$user_id} ) ) { warn "User id $user_id already exists, skipping...\n"; } else { my $new_user = $user_template; $new_user =~ s/__USERID__/$user_id/g; #print "Adding user id '$user_id' with this XML:\n"; #print $new_user . "\n"; ## Attempt to create the user file my $user_file_name = $full_dir_path . $path_sep . $user_id . '.xml'; ## Does it already exist? if ( -f $user_file_name ) { warn "$user_file_name exists, skipping...\n"; } my $fh; open($fh,'>',$user_file_name); if ( ! $fh ) { warn "Unable to open '$user_file_name' - $!\n"; warn "Skipping...\n"; next; } print $fh $new_user; close($fh); print "Added $user_id in file $user_file_name \n"; $new_user_count++; if ( $ra_present ) { $ra_new->add($user_id)->anchor_line_begin->anchor_line_end; $ra_all->add($user_id)->anchor_line_begin->anchor_line_end; } } } sub get_user_template { my $templ = < ENDUSERTEMPLATE return $templ; } sub usage { print < [--domain=] [--confpath=] add_user --users=- [--domain=] [--confpath=] In its simplest form, add_user will simply add the user_id specified at the command line. By default, users are added to the "default" domain. Use the --domain option to specify a different domain for the user(s) that are added. To specify a range of user IDs use the --users option. Separate the beginning and end of the range with a hyphen (-) character. By default add_user will look for the XML directory in its default location of /usr/local/freeswitch/conf/directory. Use the --confpath (configuration path) option to specify an alternate directory location. NOTES: add_user assumes User IDs must be numeric and cannot begin with zero. User IDs must be at least two digits long and have no specific length limit. If a user ID exists it will be skipped. If a domain specified does not exist no users will be created. ENDUSAGE }