PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/squirrelmail/contrib/flat2sql.pl

#
Perl | 432 lines | 329 code | 56 blank | 47 comment | 39 complexity | af8b4bda3ec74d1aef4354e087966a7f MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. #!/usr/bin/perl
  2. #
  3. # Converts file-based preferences into SQL statements.
  4. #
  5. # WARNING: this script is experimental. We recommend that
  6. # you not use it when logged in as a privileged user (such
  7. # as root). Also, ALWAYS back up your data directory before
  8. # using this script.
  9. #
  10. # Copyright (c) 2002, Michael Blandford and Tal Yardeni
  11. # Copyright (c) 2005-2012 The SquirrelMail Project Team
  12. #
  13. # This script is licensed under the GNU Public License (GPL).
  14. # See: http://opensource.org/licenses/gpl-license.php
  15. # $Id: flat2sql.pl 14249 2012-01-02 02:09:17Z pdontthink $
  16. #
  17. ##### Default values #####
  18. # TODO: expose the database type as a CLI option, but first need more sections in sub escape_sql_string()
  19. my $dbtype = 'mysql';
  20. my $abookdb = "squirrelmail";
  21. my $prefdb = "squirrelmail";
  22. my $abook_table = "address";
  23. my $abook_owner="owner";
  24. my $abook_nickname="nickname";
  25. my $abook_firstname="firstname";
  26. my $abook_lastname="lastname";
  27. my $abook_email="email";
  28. my $abook_label="label";
  29. my $pref_table = "userprefs";
  30. my $pref_user = "user";
  31. my $pref_key = "prefkey";
  32. my $pref_value = "prefval";
  33. ##### ##### #####
  34. use Getopt::Long;
  35. my (%opts, $verbose, $data_dir);
  36. &GetOptions( \%opts, qw( abook data_dir:s delete h help v verbose pref sig user:s abookdb:s prefdb:s pref_table:s abook_table:s abook_owner:s abook_nickname:s abook_firstname:s abook_lastname:s abook_email:s abook_label:s pref_user:s pref_key:s pref_value:s) );
  37. &Usage if ( defined $opts{h} or defined $opts{help} );
  38. unless ( defined $opts{abook} or defined $opts{pref} or defined $opts{sig}) {
  39. $opts{abook}='TRUE';
  40. $opts{pref}='TRUE';
  41. $opts{sig}='TRUE';
  42. }
  43. if ( defined $opts{verbose} or defined $opts{v} ) {
  44. $verbose = 1;
  45. }
  46. if ( defined $opts{abookdb} and $opts{abookdb} ) {
  47. $abookdb = $opts{abookdb};
  48. }
  49. if ( defined $opts{prefdb} and $opts{prefdb} ) {
  50. $prefdb = $opts{prefdb};
  51. }
  52. if ( defined $opts{pref_table} and $opts{pref_table} ) {
  53. $pref_table = $opts{pref_table};
  54. }
  55. if ( defined $opts{pref_user} and $opts{pref_user} ) {
  56. $pref_user = $opts{pref_user};
  57. }
  58. if ( defined $opts{pref_key} and $opts{pref_key} ) {
  59. $pref_key = $opts{pref_key};
  60. }
  61. if ( defined $opts{pref_value} and $opts{pref_value} ) {
  62. $pref_value = $opts{pref_value};
  63. }
  64. if ( defined $opts{abook_table} and $opts{abook_table}) {
  65. $abook_table = $opts{abook_table};
  66. }
  67. if ( defined $opts{abook_owner} and $opts{abook_owner} ) {
  68. $abook_owner = $opts{abook_owner};
  69. }
  70. if ( defined $opts{abook_nickname} and $opts{abook_nickname} ) {
  71. $abook_nickname = $opts{abook_nickname};
  72. }
  73. if ( defined $opts{abook_firstname} and $opts{abook_firstname} ) {
  74. $abook_firstname = $opts{abook_firstname};
  75. }
  76. if ( defined $opts{abook_lastname} and $opts{abook_lastname} ) {
  77. $abook_lastname = $opts{abook_lastname};
  78. }
  79. if ( defined $opts{abook_email} and $opts{abook_email} ) {
  80. $abook_email = $opts{abook_email};
  81. }
  82. if ( defined $opts{abook_label} and $opts{abook_label} ) {
  83. $abook_label = $opts{abook_label};
  84. }
  85. # Get data directory option and display help if it is not defined
  86. if ( defined $opts{data_dir} and $opts{data_dir} ) {
  87. $data_dir = $opts{data_dir};
  88. } else {
  89. &Usage;
  90. }
  91. # Are we looking for specific users or all users?
  92. # There has to be a better way to do this - Below
  93. my @user_list = split ( /,/, $opts{user} ) if defined $opts{user};
  94. inspect_files($data_dir);
  95. # All done. Below are functions
  96. # Finds needed user files in the given directory
  97. # and recurses any nested data directories as needed
  98. #
  99. sub inspect_files {
  100. my ($data_dir) = @_;
  101. my ($filename, $username, $ext);
  102. local *DIR;
  103. # Here we go
  104. # If no arguments are passed, and we cant open the dir, we should
  105. # get a usage.
  106. opendir(DIR, $data_dir) or
  107. die "DIRECTORY READ ERROR: Could not open $data_dir!!\n";
  108. while ( $filename = readdir DIR ) {
  109. next if ( $filename eq "." or $filename eq ".." );
  110. if ($verbose) { print STDERR "; INSPECTING: $data_dir/$filename\n"; }
  111. # recurse into nested (hashed) directories
  112. #
  113. if ($filename =~ /^[0123456789abcdef]$/ && -d "$data_dir/$filename") {
  114. inspect_files("$data_dir/$filename");
  115. }
  116. next unless $filename =~ /(.*)\.(.*)/;
  117. $username = $1;
  118. next unless $username;
  119. # Deal with the people
  120. # There has to be a better way to do this - Above
  121. next if (defined $opts{user} and !grep($username eq $_, @user_list));
  122. # Deal with the extension files
  123. $ext = $2;
  124. next unless $ext;
  125. &abook("$data_dir/$filename", $username)
  126. if ( $ext eq "abook" and defined $opts{abook} );
  127. &pref("$data_dir/$filename", $username)
  128. if ( $ext eq "pref" and defined $opts{pref} );
  129. &sig("$data_dir/$filename", $username)
  130. if ( $ext =~ /si([g\d])$/ and defined $opts{sig});
  131. }
  132. closedir ( DIR );
  133. }
  134. # Process a user address file
  135. sub abook {
  136. my ($filepath, $username) = @_;
  137. if ($verbose) { print STDERR "; PARSING ADDRESS BOOK DATA FROM: $filepath\n"; }
  138. if ( defined $opts{delete} ) {
  139. print "DELETE FROM $abookdb.$abook_table WHERE $abook_owner = '"
  140. . escape_sql_string($username,'TRUE')
  141. . "';\n"
  142. }
  143. open(ABOOK, "<$filepath") or
  144. die "FILE READ ERROR: Could not open $filepath!!\n";
  145. while (my $line = <ABOOK> ) {
  146. chomp $line;
  147. my ( $nickname,$firstname,$lastname,$email,$label ) = split(/\|/, $line);
  148. print "INSERT INTO $abookdb.$abook_table "
  149. . "($abook_owner, $abook_nickname, $abook_firstname, $abook_lastname, $abook_email, $abook_label) "
  150. . "VALUES ('"
  151. . escape_sql_string($username) . "', '"
  152. . escape_sql_string($nickname) . "', '"
  153. . escape_sql_string($firstname) . "', '"
  154. . escape_sql_string($lastname) . "', '"
  155. . escape_sql_string($email) . "', '"
  156. . escape_sql_string($label) . "');\n";
  157. }
  158. close(ABOOK);
  159. }
  160. # Process a user preference file
  161. sub pref {
  162. my ($filepath, $username) = @_;
  163. if ($verbose) { print STDERR "; PARSING PREFERENCE DATA FROM: $filepath\n"; }
  164. if ( defined $opts{delete} ) {
  165. print "DELETE FROM $prefdb.$pref_table "
  166. . "WHERE $pref_user = '"
  167. . escape_sql_string($username,'TRUE')
  168. . "' AND $pref_key NOT LIKE '\\_\\_\\_sig%\\_\\_\\_';\n"
  169. }
  170. open(PREFS, "<$filepath") or
  171. die "FILE READ ERROR: Could not open $filepath!!\n";
  172. while (my $line = <PREFS> ) {
  173. chomp $line;
  174. my ( $prefkey, $prefval ) = split(/=/, $line, 2);
  175. print "INSERT INTO $prefdb.$pref_table "
  176. . "($pref_user, $pref_key, $pref_value) "
  177. . "VALUES ('"
  178. . escape_sql_string($username) . "', '"
  179. . escape_sql_string($prefkey) . "', '"
  180. . escape_sql_string($prefval) . "');\n";
  181. }
  182. close(PREFS);
  183. }
  184. # Process a user signature file
  185. sub sig {
  186. my ($filepath, $username) = @_;
  187. if ($verbose) { print STDERR "; PARSING SIGNATURE DATA FROM: $filepath\n"; }
  188. my $del_ext = $1;
  189. $del_ext = "nature" if ( $del_ext eq "g" );
  190. if ( defined $opts{delete} ) {
  191. print "DELETE FROM $prefdb.$pref_table "
  192. . "WHERE $pref_user = '"
  193. . escape_sql_string($username,'TRUE')
  194. . "' AND $pref_key = '___sig"
  195. . escape_sql_string($del_ext,'TRUE')
  196. . "___';\n"
  197. }
  198. open(SIG, "<$filepath") or
  199. die "FILE READ ERROR: Could not open $filepath!!\n";
  200. my @lines = <SIG>;
  201. close(SIG);
  202. $filepath =~ /.*\.si([g,\d])$/;
  203. my $prefkey = "___sig";
  204. if ( $1 eq "g" ) {
  205. $prefkey .= "nature___";
  206. } else {
  207. $prefkey .= "$1___";
  208. }
  209. print "INSERT INTO $prefdb.$pref_table ($pref_user, $pref_key, $pref_value) "
  210. . "VALUES ('"
  211. . escape_sql_string($username) . "', '"
  212. . escape_sql_string($prefkey) . "', '"
  213. . escape_sql_string(join("", @lines)) . "');\n";
  214. }
  215. # Escapes sql strings
  216. # MySQL escaping:
  217. # http://dev.mysql.com/doc/refman/5.0/en/string-syntax.html
  218. # full - \x00 (null), \n, \r, \, ', " and \x1a (Control-Z)
  219. # add % and _ in pattern matching expressions.
  220. # short - only character used for quoting and backslash should be escaped
  221. # PostgreSQL
  222. # Oracle
  223. # Sybase - different quoting of '
  224. sub escape_sql_string() {
  225. my ($str,$isPattern) = @_;
  226. if ($dbtype eq 'mysql'){
  227. # escape \, ' and "
  228. $str =~ s/(['"\\])/\\$1/g;
  229. # escape \x1a
  230. $str =~ s/([\x1a])/\\Z/g;
  231. # escape ascii null
  232. $str =~ s/([\x00])/\\0/g;
  233. # escape line feed
  234. $str =~ s/([\n])/\\n/g;
  235. # escape cr
  236. $str =~ s/([\r])/\\r/g;
  237. if ($isPattern) {
  238. $str =~ s/([%_])/\\$1/g;
  239. }
  240. } else {
  241. die "ERROR: Unsupported database type";
  242. }
  243. return $str;
  244. }
  245. # Print out the usage screen
  246. sub Usage {
  247. $0 =~ /.*\/(.*)/;
  248. my $prog = $1;
  249. print <<EOL;
  250. This program generates SQL statements that aid in importing
  251. SquirrelMail user configuration settings from files to
  252. those in a database.
  253. WARNING: this script is experimental. We recommend that
  254. you not use it when logged in as a privileged user (such
  255. as root). Also, ALWAYS back up your data directory before
  256. using this script.
  257. Usage: $prog --data_dir=<path to data directory> \\
  258. [--delete] \\
  259. [--abook] [--sig] [--pref] \\
  260. [--user=<username1[,username2[,username3]...]>] \\
  261. [--abookdb=<database>] \\
  262. [--abook_table=<table name>] \\
  263. [--abook_owner=<field name>] \\
  264. [--abook_nickname=<field name>] \\
  265. [--abook_firstname=<field name>] \\
  266. [--abook_lastname=<field name>] \\
  267. [--abook_email=<field name>] \\
  268. [--abook_label=<field name>] \\
  269. [--prefdb=<database>] \\
  270. [--pref_table=<table name>] \\
  271. [--pref_user=<field name>] \\
  272. [--pref_key=<field name>] \\
  273. [--pref_value=<field name>] \\
  274. [--verbose] [-v]
  275. [--help] [-h]
  276. When none of --abook, --sig or --pref is specified, all three
  277. will be assumed.
  278. If --user is not specified, data for all users will be extracted.
  279. --data_dir is not optional and must define the path to the
  280. SquirrelMail data directory. If it is not given,
  281. this help message is displayed.
  282. --delete causes the inclusion of SQL statements that remove all
  283. previous setting values from the database for each user.
  284. This setting obeys --user, --abook, --pref and --sig.
  285. This setting is useful when re-importing settings.
  286. --abook causes the inclusion of SQL statements that import user
  287. address book data.
  288. --sig causes the inclusion of SQL statements that import user
  289. (email) signature data.
  290. --pref causes the inclusion of SQL statements that import all
  291. other general user preference data.
  292. --user can be used to limit the users for which to extract data.
  293. One or more (comma-separated) usernames can be given.
  294. --abookdb can be used to specify a custom database name for the
  295. address book database. If not given, "squirrelmail"
  296. is used.
  297. --abook_table can be used to specify a custom address book table
  298. name. If not given, "address" is used.
  299. --abook_owner can be used to specify a custom field name for the
  300. "owner" field in the address book database table
  301. (the username goes in this field). If not given,
  302. "owner" is used.
  303. --abook_nickname can be used to specify a custom field name for the
  304. "nickname" field in the address book database table.
  305. If not given, "nickname" is used.
  306. --abook_firstname can be used to specify a custom field name for the
  307. "firstname" field in the address book database table.
  308. If not given, "firstname" is used.
  309. --abook_lastname can be used to specify a custom field name for the
  310. "lastname" field in the address book database table.
  311. If not given, "lastname" is used.
  312. --abook_email can be used to specify a custom field name for the
  313. email field in the address book database table
  314. (the actual email address goes in this field). If
  315. not given, "email" is used.
  316. --abook_label can be used to specify a custom field name for the
  317. "label" field in the address book database table.
  318. If not given, "label" is used.
  319. --prefdb can be used to specify a custom database name for the
  320. user preferences database. If not given, "squirrelmail"
  321. is used.
  322. --pref_table can be used to specify a custom preference table
  323. name. If not given, "userprefs" is used.
  324. --pref_user can be used to specify a custom field name for the
  325. "user" field in the preferences database table
  326. (the username goes in this field). If not given,
  327. "user" is used.
  328. --pref_key can be used to specify a custom field name for the
  329. key field in the preferences database table (the
  330. preference name goes in this field). If not given,
  331. "prefkey" is used.
  332. --pref_value can be used to specify a custom field name for the
  333. value field in the preferences database table
  334. (the preference value goes in this field). If not
  335. given, "prefval" is used.
  336. --verbose Displays extra diagnostic output on STDERR. If you
  337. redirect standard output to a file, verbose output
  338. will not interfere with other normal output.
  339. -v Same as --verbose.
  340. --help Displays this usage information.
  341. -h Same as --help.
  342. EOL
  343. exit 1;
  344. }