#!/usr/bin/perl # Script to get and share netscape/mozilla bookmarks from # a single central server. # # Placed in public domain by Jason Duell, January 4, 2001 # # Problem: I want to use nightly builds from Mozilla, but I also # may need to use older Mozilla milestones (when nightly build # is broken), and/or good ol' Netscape 4.7 (for SSL especially). # I also want to use all these both at home and at work. I want # the same set of bookmarks for all of these, and to be able to # update that set of bookmarks without much fuss. # # Old solution: use "roaming profiles" from Netscape 4.7. Alas, # these don't work with Mozilla (at least yet). Plus, they involve # dragging the full set of bookmarks (250K+ in my case) off some # server every time you fire up the browser. # # This solution: this Perl script, which automates storing my # bookmarks on a single central machine, getting and setting # those bookmarks, and making sure that the bookmarks are shared # among any mozilla/netscape instance I launch. # # The script is designed to be configured as a set of # linked files on my machine: it know what task to perform based # on the filename you invoke it with: # # 1) 'get_bookmarks': uses SSH's 'scp' command to grab a copy of # the master bookmark file from a central server (which you specify # via the $bookmark_server, $server_dir, and $bookmarks_file # variables below). [Note that you can avoid having to type your # SSH password in each time you do this if you use ssh-agent to # launch your X session ("ssh-agent startx"). You could also use # an '.shosts' file. See 'man ssh' for more info. If you don't want # to use SSH, you can use an ftp server by invoking the 'ncftpget' # command (see usage in another part of this script)]. The bookmarks # copied from the master server are stored in a directory of your # choice ($local_cache_dir: do NOT use .netscape or .mozilla, and # you must create the directory by hand if it does not already exist). # # 2) "mz", "milez", and "ns". These commands invoke my nightly # build of Mozilla, the latest stable milestone of Mozilla, and # netscape 4.7, respectively. Set the $netscape4_dir, # $mozilla_nightly_install_dir, and $mozilla_milestone_install_dir # variables appropriately. These three commands all work the same # way with regard to the bookmark file: they attempt to lock the # bookmark file in the cache directory, then they copy the bookmark # file to the appropriate directory (~/.mozilla/default or # ~/.netscape) for the browser, which is then launched. The script # cd's into the directory you provide, so the browser does not # need to be in your PATH. When the browser closes, its bookmark # file is moved to the local cache file if the lock for the # bookmark file was gained: otherwise it is simply deleted. This # enforces a regime in which the first instance of netscape/mozilla # has the right to update the bookmarks file, while other simultaneous # instances are 'slaves' whose bookmarks are discarded. # # 3) 'put_bookmarks': This uses scp to copy the local cache's # bookmarks file to the master server, where it will become the new # master bookmark file. The local copy of the cached bookmarks is # deleted, so that it will be loaded again from the master server # when you launch mozilla the next time. # # 4) 'get_mozilla_nightly': this part of the script is meant to be # called from a crontab entry, so that it gets called once a day # in the middle of the night. It uses ncftpget to go grab the # tarball for latest nightly build of the mozilla browser for linux. # The tarball is stored in $mozilla_night_download_dir, and then # un-tar'd into $mozilla_nightly_install_dir, so you will wake up # each day to the freshest bits from ftp.mozilla.org. If the nightly # build happens to be a total dud, you've got the latest milestone # (which you installed by hand, of course) to fall back on. # # EVERYDAY USAGE: # # A couple of things were omitted from the above descriptions. # First, running 'mz', 'milez', or 'ns' will wind up calling # 'get_bookmarks' if there is no copy of the bookmarks in the # local cache (this will be the case if you last called # 'put_bookmarks'). So this lends itself to the following # simple usage pattern: # # 1) Arrive at your computer at work. # 2) At some point run mozilla: latest bookmarks are # loaded from central server the first time, then # stored and updated on your local machine as you # browse. # 3) Before you quit for the day, do a 'put_bookmarks'. # Your bookmarks are saved to the central server. # 4) At home, fire up mozilla. Bookmarks last updated at # work are loaded from server. Before bedtime, use # 'put_bookmarks' to save any changes to server. # # BACKUP BOOKMARKS # # To avoid not having any bookmarks at all if you cannot # reach the central server, this script stores a backup file # ($backup_file) in the local cache directory every time you # call 'put_bookmarks'. If the script fails to get the # bookmarks from the central server the next time you lauch # mozilla, it will complain (to the console) and get the # bookmarks from the backup file. Note that the script is not # smart enough to keep trying to get the central server's # bookmarks--once it has reverted to the backup bookmarks, # they are the local master bookmarks. So if you genuinely # need the central server's bookmarks, you'll need to # manually issue a 'get_bookmarks' when the server is back up. # # BOOKMARK FORKS # # Obviously, if you don't use 'put_bookmarks' when you switch # computers, you risk forking your bookmarks. Often you won't # care, and can just decide to use one set as the new master. # Otherwise, it's cut and paste time. Don't say I didn't warn you. # # INSTALLATION INSTRUCTIONS # # To set this up, you need: # # 1) A login (SSH or ftp) to a machine that is accessible to # all your other machines. I.e., it must be accessible from # the Internet, and not hidden behind a firewall. This may # disqualify a lot of people. Sorry! # # 2) For security reasons, I recommend using SSH instead of # ftp/telnet on any box accessible from the internet. The # 'scp' program I use in this script comes with any # SSH 1 compatible distro (like http://www.openssh.com). # But you can use an ftp site if you want to--just modify # the 'get/put_bookmarks' commands to use ncftpget/put, like # it's used in the 'get_mozilla_nightly' section. # If you use SSH, I highly recommend you use one of the methods # for avoiding having to type your SSH password in all the time. # See the ssh-agent, ssh-add, and .slogin sections of the SSH # man pages. # # 3) Stick this script on your machine in a directory that is # in your PATH (I use ~/bin). Store it as 'get_bookmarks', then # create links to the other commands via: # ln get_bookmarks get_mozilla_nightly # ln get_bookmarks mz # ln get_bookmarks milez # ln get_bookmarks ns # ln get_bookmarks put_bookmarks # Also, 'chmod +x get_bookmarks' to make the file executable. # # 4) Edit the script with your favorite text editor (i.e., vi) # and change the hardcoded variables at the top so that they # point to the directories that you want to use for storing the # bookmarks, your browsers' directories, etc. Note that all # directories must be pre-created, and you must have write access # to all of the one that you'll write to (duh). # # 5) Copy the set of bookmarks you want to use as your starting # set to the local cache directory you specify. Do a # 'put_bookmarks' to load them to the server. Then try typing # 'mz' from a shell to launch your browser. You should see scp # telling you it is getting the bookmarks from the server, and # then mozilla will launch. # # 6) If you want to download the nightly build of mozilla each # night. stick an entry like this in your crontab file (adjust # the path to your machine, of course): # # 25 5 * * * /home/jduell/bin/get_mozilla_nightly # # Happy browsing! # # Jason Duell jduell@alumni.princeton.edu Dec 1, 2000 use strict; my %config; ################### local settings ############## my $bookmarks_file; my $local_cache_dir; my $backup_file; my $bookmark_server; my $scp_flags; my $server_dir; my $netscape4_dir; my $mozilla_milestone_install_dir; my $mozilla_nightly_install_dir; my $mozilla_nightly_download_dir; sub read_config { my $home = $ENV{HOME} or die "HOME environment variable not defined"; open(CONFIG, "$home/.uzillity") or die "Can't open config file ~/.uzillity"; while () { next if /^\s*\#/; if (/^(\w+)\s*=\s*"([^"]+)"/) { $config{$1} = $2; } } close CONFIG; # while (my ($k, $v) = each %config) { # print "$k=$v\n"; # } # hack: we've got these old hardcoded variable references scattered everywhere, so # instead of switching them all to $config{whatever} we just assign them all here $bookmarks_file = $config{bookmarks_file} or die "Config missing 'bookmarks_file'"; $local_cache_dir = $config{local_cache_dir} or die "Config missing 'local_cache_dir'"; $backup_file = $config{backup_file} or die "Config missing 'backup_file'"; $bookmark_server = $config{bookmark_server} or die "Config missing 'bookmark_server'"; $scp_flags = $config{scp_flags} or die "Config missing 'scp_flags'"; $server_dir = $config{server_dir} or die "Config missing 'server_dir'"; $netscape4_dir = $config{netscape4_dir} or die "Config missing 'netscape4_dir"; $mozilla_milestone_install_dir = $config{mozilla_milestone_install_dir} or die "Config missing 'mozilla_milestone_install_dir'"; $mozilla_nightly_install_dir = $config{mozilla_nightly_install_dir} or die "Config missing 'mozilla_nightly_install_dir'"; $mozilla_nightly_download_dir = $config{mozilla_nightly_download_dir} or die "Config missing 'mozilla_nightly_download_dir'"; } # these are the directory/filename at ftp.mozilla.org my $ftp_site = "ftp.mozilla.org"; my $mozilla_nightly_ftp_dir = "/pub/mozilla/nightly/latest"; my $mozilla_tarball = "mozilla-i686-pc-linux-gnu.tar.gz"; my @ncftp_errs = ( "Success", "Could not connect to remote host", "Could not connect to remote host - timed out", "Transfer failed", "Transfer failed - timed out", "Directory change failed", "Directory change failed - timed out", "Malformed URL", "Usage error", "Error in login configuration file", "Library initialization failed", "Session initialization failed" ); ############ "MAIN " ########################### read_config(); eval { # switch behavior on name by which we were invoked if ($0 =~ /get_bookmarks$/) { get_bookmarks_from_server(); } elsif ($0 =~ /put_bookmarks$/) { put_bookmarks_on_server(); } elsif ($0 =~ /milez$/) { run_mozilla_version("$mozilla_milestone_install_dir/package", "mozilla", "~/.mozilla/default/bookmarks.html"); } elsif ($0 =~ /mz$/) { run_mozilla_version("$mozilla_nightly_install_dir/mozilla", "mozilla", "~/.mozilla/default/bookmarks.html"); } elsif ($0 =~ /ns$/) { run_mozilla_version("$netscape4_dir", "netscape", "~/.netscape/bookmarks.html"); } elsif ($0 =~ /get_mozilla_nightly$/) { print "-----------", `date`; grab_nightly_build(); install_nightly_build(); print "Mozilla nightly tarball installed\n"; } elsif ($0 =~ /uzillity$/) { install_uzillities(); } else { die "Must be invoked as 'mz', 'nb', 'get_bookmarks' 'put_bookmarks'\n"; } }; if ($@) { die "$@\n"; } ################################################# sub get_bookmarks_from_server { if (system("scp $scp_flags $bookmark_server:$server_dir/$bookmarks_file $local_cache_dir")) { if (-f "$local_cache_dir/$backup_file") { if (system("cp -f $local_cache_dir/$backup_file $local_cache_dir/$bookmarks_file")) { die "Couldn't revert to backup file\n"; } else { die "Couldn't get bookmarks from server: reverting to cached copy\n"; } } } else { # copied OK system("cp -f $local_cache_dir/$bookmarks_file $local_cache_dir/$backup_file") and die "Couldn't make backup file\n"; } } sub put_bookmarks_on_server { my $errs; system("scp $scp_flags $local_cache_dir/$bookmarks_file $bookmark_server:$server_dir/$bookmarks_file") and $errs .= "Couldn't copy $local_cache_dir/$bookmarks_file to $bookmark_server:$server_dir/$bookmarks_file\n"; #make backup copy system("cp -f $local_cache_dir/$bookmarks_file $local_cache_dir/$backup_file") and $errs .= "\nCouldn't make backup file\n"; die $errs if $errs; # remove main copy, so we'll know to get them from server next time system("rm -f $local_cache_dir/$bookmarks_file") and $errs .= "Couldn't delete main bookmarks file\n"; die $errs if $errs; } sub run_mozilla_version { my ($bin_dir, $binary, $bookmark_location) = @_; my $have_bookmark_lock = 0; my $errs; if ($ARGV[0] =~ /backup/) { print "Using backup bookmarks\n"; system("cp -f $local_cache_dir/$backup_file $local_cache_dir/$bookmarks_file") and die "Can't copy $local_cache_dir/$backup_file to $local_cache_dir/$bookmarks_file!"; } else { if (! -f "$local_cache_dir/$bookmarks_file") { print "Getting bookmarks from server\n"; eval { get_bookmarks_from_server(); }; #print "Attempt to get bookmarks from server failed:\n" if $@; die "Attempt to get bookmarks from server failed:\n" if $@; } } # get rid of local copy of bookmarks, if any system("rm -f $bookmark_location"); if (-f "$local_cache_dir/$bookmarks_file") { # if we get lock, our copy is the master # nonblocking = 4 and exclusive = 2. ORing makes 6 # Note that perl flock returns 1/0 for success/fail: opposite of C if (open(FDESC, "$local_cache_dir/$bookmarks_file") && flock(FDESC, 6)) { print "Got bookmark lock\n"; $have_bookmark_lock = 1; } system("cp -f $local_cache_dir/$bookmarks_file $bookmark_location") and die "Can't copy bookmarks from shared location to $bookmark_location!"; } else { # no master bookmarks available from server: try backup copy system("cp -f $local_cache_dir/$backup_file $bookmark_location") and die "Can't copy backup bookmarks from shared location to $bookmark_location!"; print "Using backup copy of bookmarks\n"; } chdir($bin_dir) or die "Couldn't chdir to '$bin_dir'\n"; system($binary); if ($have_bookmark_lock) { system("cp -f $bookmark_location $local_cache_dir/$bookmarks_file") and die "Can't copy bookmarks from $bookmark_location to $local_cache_dir/$bookmarks_file!"; print "Copied bookmarks to local master file\n"; } # get rid of local copy system("rm -f $bookmark_location"); # lock goes away if we have it when we exit die $errs if $errs; } sub grab_nightly_build { my $err; if (-f "$mozilla_nightly_download_dir/$mozilla_tarball") { $err = system("rm -f $mozilla_nightly_download_dir/$mozilla_tarball") and die "Couldn't remove existing mozilla_tarball: $err"; } $err = system("ncftpget $ftp_site $mozilla_nightly_download_dir $mozilla_nightly_ftp_dir/$mozilla_tarball") and die "Couldn't grab nightly build from mozilla: $ncftp_errs[$err>>8]"; } sub install_nightly_build { my $err; chdir($mozilla_nightly_install_dir) or die "Can't cd to $mozilla_nightly_install_dir: $err"; if (-d "$mozilla_nightly_install_dir/mozilla") { $err = system("rm -rf $mozilla_nightly_install_dir/mozilla") and die "Couldn't remove existing directory $mozilla_nightly_install_dir/mozilla: $err"; } $err = system("tar zxf $mozilla_nightly_download_dir/$mozilla_tarball") and die "Error while untarring $mozilla_nightly_download_dir/$mozilla_tarball into $mozilla_nightly_install_dir: $err"; } sub install_uzillities { my ($dir) = $0 =~ m@^(.*)/[^/]+$@; chdir($dir) or die "Can't change directory to $dir!"; foreach ( "mz", "milez", "ns", "get_mozilla_nightly", "get_bookmarks", "put_bookmarks" ) { if (-e) { system("rm -f $_") and die "Could not remove existing file $_"; } system("ln -s uzillity $_") and die "Could not make symlink to $_"; } print <