: Title: Add City to World Clock Widget
# Filename: add2clockwidget
# Version: 1.0
# By: John Gaver
# http://www.ActionAmerica.org/
# License: Freeware
# Description: This script adds a city to the Apple World Clock Widget. It is
#              a static script that requires 5 or 6 variables to be defined,
#              before it will run. It's primary purpose is to provide a means
#              to easily and CORRECTLY add one city to the W/C Widget and then
#              be able to repeat the process, each time an Apple update
#              overwrites the changes that you made to the earlier version.
#              Reinserting your changes into each new version is preferable,
#              to replacing the old one, since replacing would undo the upgrade.
# Purpose: Too many wrong or at least incomplete methods of adding a city to
#          the World Clock Widget are floating around on the various forums.
#          This script is copiously commented, to explain what needs to be done
#          and why and then automates that process. Also, since the first update
#          to Tiger, undid any changes that users made to the original widget,
#          this makes adding those changes back into future versions a snap.
#          Part of the reason for it's extensiveness and many comments, is to
#          give Mac users some idea of the awesome power of UNIX shell scripts.
# Disclaimer: This is freeware. It has no warranty. It is designed to work with
#             The Apple World Clock Widget, as supplied with the original
#             release of Tiger. It should work with future versions, as long as
#             Apple doesn't make too significant changes in the World Clock
#             widget. That isn't likely, but it could happen. The author has
#             attempted to take this into consideration, so if Apple should
#             make such changes, the script should fail gracefully, but there
#             is no guarantee of this. If you do not set the variables, as per
#             these instructions, it could have undesired effects on the
#             operation of the World Clock widget, particularly in the area of
#             Dayoight savings Time. It is the user's responsibility to make
#             sure that the variables are set correctly.
#
# Other Mac Freeware from Action America: Gun Self Defense Counter Widget

##########  I M P O R T A N T  ##########
#
# READ AND UNDERSTAND THIS BEFORE MODIFYING VARIABLES OR RUNNING SCRIPT !!!
#
# CAUTION: Due to the fact that Apple has set the ownership of the World Clock
# widget to "root", this shell script must be run as "root". What does this
# mean to you?
#
# IF YOU DON'T UNDERSTAND WHAT THIS SCRIPT DOES, THEN DON'T RUN IT !!!!!
#
# SECURITY RANT ---
# The above statement is not so much aimed at this script, as it is at ALL
# shell scripts that must be run as "root". That's because when you run a shell
# script as "root", you are effectively giving it permission to do anything to
# your system. Therefore, you must know that it is not going to do anything
# that you don't want it to do.
#
# There are very few executable lines in this script (about 65) and they are
# copiously documented, so even a novice should be able to understand what it
# does. Just be aware that because a script that runs as "root" can do ANYTHING
# to your system, you should read through the entire script and understand what
# it does, before running it. This applies to ANY script that runs as "root",
# not just this one...  OK. End of security rant.
#
# To see just the executable portion of this file without all of the comments 
# and empty lines, execute the following command on the command line. Be aware
# that since there are beeps in the error messages that are part of this file,
# you may, depending upon your settings, hear several beeps that can be
# ignored, when displaying the executable lines in this manner. This command
# simply displays this file, but eliminates lines starting with "#" and blank
# lines and pages the output (press space bar to page through the output and
# press "q" to get back to the command line).
#
#    grep -v ^# add2clockwidget | grep -v ^$ | more
#
# The only part of this shell script that is interactive is the verification
# of the information that you want added. It is expected that most people will
# only want to use it to add one city and that they will want to do so each
# time an Apple update changes the World Clock, thus overwriting their changes.
# Therefore, you will have to insert the appropriate data into this file, for
# each of 5 or 6 main variables. Don't worry. It's very easy. But, there is one
# very important caveat, having to do with timezones, that I will explain in a
# moment.
#
# All of the variables that you will have to deal with are immediately below
# this introduction. This script will not make any changes to the World Clock
# widget, until you have updated those variables with your data. Those
# variables are:
#
#   mycity = The name of the city that you want to add
#   offset = The number of minutes that city is from GMT
#   timezone = The timezone of that city - READ THE DISCUSSION BELOW!
#   citybelow = Tells script where to place your city on the list (more below)
#   backupuser = Tells the script on which user's Desktop to place the backup
#
# I will explain exactly what needs to go into each one of those variables.
# Once you have inserted the proper data into those variables, you should not
# have to make any modifications to this file again. All that you should ever
# have to do after that, is to simply run the script, as specified below.
#
# There are other variables that you should never have to deal with, unless
# Apple changes the path to the widget directory or makes other such unlikely
# changes to the system or to the World Clock and even then, you should not
# make any changes to them or any other part of this script, unless you are a
# UNIX propellerhead. The area containing those other variables is well marked.
#
# Here is what goes in each variable (you might want to write them all down,
# before you start adding them into this file.:
#
# ---- mycity ----
# Enter the name of the city that you want to add to the World Clock widget.
# This is pretty straight forward, but there is one caveat. If the city name
# contains an apostrophe, such as in "St. John's", then the apostrophe must be
# escaped with a backslash (\). Therefore, "St. John's" would have to read
# "St. John\'s". You can also insert special accented characters, if you know
# the proper keystroke combination.
#
# ---- offset ----
# Enter the number of minutes the new city is ahead/behind GMT. For example,
# Houston, Texas is in CST, which is 5 hours behind GMT, so the offset would
# be "-300" minutes. Venice, Italy is 2 hours ahead of GMT, so the offset
# would be "120" minutes. You should be able to figure it out from there.
#
# ---- timezone ----
# #### PAY ATTENTION ####
# This isn't tricky - just important - and for most people, it will not even
# be an issue. This is what most of the forum postings fail to tell you about.
# This has to do with how your new city deals with daylight savings time, in
# the World Clock widget. So, if you don't follow the right procedure, your
# new city's daylight savings itime could end up being off an hour or maybe
# even two in the widget. For most people, it will be simple. But, it can be
# rather convoluted for some people, such as those in Indiana or Arizona, where
# some parts of the state observe daylight savings time and others don't. Then,
# there is the fact that daylight savings time goes opposite directions in
# each hemisphere. Think about it...
#
# I said that it's simple and it is. Apple has already done most of the work
# for us. They have included at least one city in every time zone in the world
# in their existing list of cities. So, to determine a valid timezone name, all
# that you need to do, is find another city that is not only in the same
# timezone, but one that uses (or ignores) daylight savings time in exactly the
# same way as your new city and use the time zone name for that city, as the
# timezone for your new city. It may have another city's name as part of the
# timezone name, but that won't show up. It is just an identifier.
#
# So, to find a matching timezone, you will have to look through a file with
# all of the existing cities. It's a JavaScript file, but don't worry if you
# don't know JavaScript. What you are looking for will be quite obvious.
# When you get to that point and page through the file, you will see the
# cities listed by continent. All that you will need to do is to find a city
# in that list that matches the daylight savings time criteria of your new
# city and use the same timezone.
#
# To view the file and find the timezone, type or cut and paste the following
# command and then press spacebar to page through file, till you find a city in
# your timezone (press "q" to get back to the command line):
#
#	more /Library/Widgets/World\ Clock.wdgt/WorldClock.js
#
# Once you find the line with a city in your timezone, then look for thr word
# "timezone:" in that line. The timezone that you need to input for your
# timezone variable is a slight modification of the text between the
# apostrophes, following "timezone:", on that line. The modification is easy.
# Notice that all of the time zones have a slash (/) in the middle of them.
# That slash must be escaped with a backslash (\). So, for example, "US/Central"
# would have to become "US\/Central", when you put it into the timezone field.
# If you were adding Houston, TX, then the timezone field would simply be
# "US\/Central" (note the backslash). But, if you are in Arizona or Indiana,
# as well as some other parts of the world, your timezone would have to match
# that of some other city that recognizes the same daylight savings time as
# the city that you are adding. Is that perfectly confusing? Just try it.
# You'll see that if you follow these steps, it will make sense. Remember, o
# get out of the file that you were paging through, just press the letter "q".
#
# ---- citybelow ----
# Using the World Clock widget, flip it over and Look on the current list of
# cities. Find the name of the city that you want to appear on the line
# AFTER your city and use it in the "citybelow" field. So, if your new city
# is "Metropolis" and you want it to appear in alphabetic order, you would
# choose "Mexico City" (based on the list of cities in the initial release).
# This would place "Metropolis" between "Memphis" and "Mexico City" On the
# other hand, if you wanted your new city to appear at the top of the list
# for North America, then you would choose Adak. There is one caveat, though.
# Due partially to my own laziness and the fact that I didn't want to put any
# more work into something that I'm not getting paid for, it will not work
# right if you try to place your city at the bottom of the list. In other
# words, using this script, Yuma could not appear in alphabetic order and
# would have to appear somewhere above Winnipeg. You can place your city in
# alphabetical order, at the top of the list or anywhere else, except at the
# bottom. If the city name has any special characters, such as the "é" in
# Montréal, then you will have to use the proper keystroke to place that
# special character into the variable (See Apple Special Characters). As in
# the "mycity" field above, any apostrophes in the city name must be escaped.
#
# ---- backupuser ----
# Your existing World Clock Widget will be backed up to the Desktop of the
# user name that you enter here. The default is "owner". The name of the
# backup file will be "World Clocknnnnn.wdgt" where "nnnnn" will be a pseudo-
# random number (it's actually the job number assigned to the task by OS-X).
# When you run the script, you will be given the exact file name. After
# running the script, you should verify that the World Clock Widget works as
# it is supposed to. If there is any problem, you will have a backup of the
# widget on this user's Desktop. After verifying that the widget is performing
# as expected, you may want to either archive or delete the backup that you
# find on this user's Desktop.
#
# ----------
# Once you are ready with your five variables, enter them in the following
# lines and be extra carefull of the spelling and capitalization. Also, if your
# language is other than English, then there is an additional variable that
# you will want to change, just below these five.

# Note: If you pass this script on to others, after modifying it for your use,
# please change "mycity" back to "not defined". This effectively resets the
# city, so the other user will be required to input their own city info.

mycity="not defined"

offset="-300"

timezone="US\/Central"

citybelow="not defined"

backupuser="owner"

# If your language is other than English, then there is one other variable
# that you might want to change. It will help define the path to the directory
# that holds the localizedStrings file. This is where you change languages. The
# choices are English, Dutch, French, German, Italian, Japanese & Spanish. Note
# that the language name begins with an initial capital letter.

lang="English"

# UNIX propellerheads already know that there are many ways to run a script
# like this. But, here is the easiest way. Place the prepared script in a
# convenient directory (ex.: /Users/owner) and use the cd command to get to
# that directory. Then just type:
#
#    sh add2clockwidget
#
# If the script is in a different directory, then you will, of course, have to
# type the entire path to that file, instead of just the filename. There are
# other ways, including changing permissions and even placing it in a location
# where it is recognized as an authorized executable file. But, if you don't
# already know how to do that, don't even think about trying it.
#
# If you have any questions or feedback, please use our Feedback Form on
# the Action America web site (http://www.ActionAmerica.org/).
#
###################################################
###################################################
###                                             ###
###   DO NOT CHANGE ANYTHING BELOW THIS LINE.   ###
###                                             ###
###################################################
###################################################

# Check to see if the user is "root" and if not, display a gotchagram,
# explaining that he needs to be logged in as root.

if [[ `whoami` != "root" ]]
then
  echo "





Because Apple has set the ownership of the World Clock Widget to
\"root\", you must be logged in as \"root\" to use this shell script.
Please login as \"root\". You may have to enable the \"root\" login,
by assigning a password to that account, if you have not already done
so. If you don't know how to do that, you may want to consider getting
a technoweenie friend to help, as you may be in over your head and you
don't want to fool around as \"root\", if you don't know what you are
doing.

Security Rant: Although the author of this script has no interest in
running any malevolent code on your system, we wish to remind the user
that prudence dictates that before running any shell script that
requires \"root\" privileges, even one from a trusted source, you
should scan through the shell script yourself, to be sure that it will
do only what you want it to do and that nothing bad was added to it,
in transit to you.    End of security Rant...
"
  exit
fi

# Check to see of the user has set his own variables and if not, display a
# gotchagram, explaining what to do.

if [[ $mycity == "not defined" ]]
then
  echo "













Oops\! You must set certain variables within this shell script,
before it will run. The script is copiously commented, detailing
how to set these variables. Just follow those instructions. It's 
easy. It is best to edit the script with the UNIX \"vi\" editor,
as the Mac \"TextEdit\" editor can change some special characters.
Once you have told the script what city to add and other pertinent 
info, then you may come back here and it should run.
"
  exit
fi

# Set the path to the widget directory. Should Apple ever move the
# base widget directory, this is what you change.

widgetDir="/Library/Widgets"

# Set the path to the World Clock widget. Should Apple ever move
# this particular widget or rename it, this is what you change.

WCdir="$widgetDir/World Clock.wdgt"

# Set the path to the WorldClock.js file

WCjs="$WCdir/WorldClock.js"

# Set the Language Strings directory

lproj="$WCdir/$lang.lproj"

# Make sure that the Language Strings directory exists and if
# not, display a gotchagram, explaining what needs to be done.

if [[ -d "$lproj" ]]
then
  break
else
  echo "









The language that you selected, "$lang", does not have
a matching directory in the World Clock Widget. Please check
the variables that you defined in the script and make sure that
you correctly spelled the name of the language and that you
capitalized only the first letter. Though unlikely, this
message might also appear, if Apple has made changes in the
file/directory structure of the World Clock Widget.
"
  exit
fi

# Set the path to the localizedStrings file. Should Apple ever change
# the location of the localizedStrings file, this is what you change.

locStrings="$lproj/localizedStrings.js"

# Check existence of citybelow and if not found, display gotchagram, explaining
# what to do.

belowok=`grep -c $citybelow "$WCjs"`

if [[ $belowok == 1 ]]
then
  break
else
  echo "













The city that you named in the "citybelow" variable, which your
new city is to appear just above, was

  $citybelow

That city does not exist in the existing widget files. Please
check to make sure that you spelled the name of that city exactly
as it is spelled in the dropdown list on the back side of the
widget. Be careful of capitalizations, accented characters,
spaces and apostrophes. Remember that apostrophes must be escaped
with a backslash (\\).
"
  exit
fi

# Define backup directory.

backupdir="/Users/$backupuser/Desktop"

# Check to see if backup directory exists.

if [[ -d "$backupdir" ]]
then
  break
else
  echo "











The backup directory, \"$backupdir\", does not exist.
This was defined by your selection of backupuser, \"$backupuser\".
Please check the variables that you defined in the script and
make sure that you correctly spelled the name of the backupuser,
whose Desktop is to be the target for the backup file.
"
  exit
fi

# Get process number of this job, to use as unique identifier, for next step.

procnum=$$

# Set the backup file path.

backupfile="$backupdir/World Clock$procnum.wdgt"

# Make sure that a file does not already exist by the same name as the
# backup file. If it does, then display a gotchagram, explaining what to do.

if [[ -e "$backupfile" ]]
then
  echo "















The file \"$backupfile\" already exists.
The chances of this happening are extremely small, since the
number in the backup file name changes with each execution of
thie script. Therefore, all that you should have to do, is
re-run this script.
"
  exit
fi

# Prompt the user, showing what is to be done and ask for confirmation.

echo -n "









You are about to add a city to the World Clock Widget, using the following
parameters.

City name: $mycity
Offset minutes: $offset
Timezone: $timezone
Place above city: $citybelow
Backup to: "$backupfile"
Language is: $lang

Is this what you want to do? [Y|N] "

read yn

# If the answer is "Y" or "y", then skip ahead to make changes. Otherwise exit.

case $yn in
  (Y|y) break;;
    (*) echo "Aborted"
        exit;;
esac

# Make backup file

cp -R "$WCdir" "$backupfile"

# This is the replacement text for WorldClock.js, based on the variables
# that you defined above. This will be picked up by a sed command, later.

repltext1="	\{city:\'$mycity\', offset:$offset, timezone:\'$timezone\'\},\\
&"

# This is the replacement text for localizedStrings.js, based on the variables
# that you defined above. This will be picked up by a sed command, later.

repltext2="localizedCityNames['$mycity'] = '$mycity';\\
&"

# This is the sed script that finds "$citybelow" in WorldClock.js and
# inserts the replacement text in front of it. The changes are stored to
# a temporary file.

sed -e "/	{city:'$citybelow'/s//$repltext1/" < "$WCjs" > tmp1$procnum

# Move the temporary file back to its proper place in the widget directory,
# overwriting the original file.

mv -f tmp1$procnum "$WCjs"

# This is the sed script that finds "$citybelow" in localizedStrings.js and
# inserts the replacement text in front of it. The changes are stored to
# a temporary file.

sed -e "/localizedCityNames\['$citybelow'\]/s//$repltext2/" < "$locStrings" > tmp2$procnum

# Move the temporary file back to its proper place in the widget directory,
# overwriting the original file.

mv -f tmp2$procnum "$locStrings"

echo "








Your World Clock Widget has been updated to include the city:

  $mycity.

If for any reason, the World Clock Widget does not work, the
original World Clock Widget was backed up to:

  $backupfile

*************************************************************
*  Remember that you logged in as \"root\" to execute this    *
*  script. You might want to give some serirous thought to  *
*  logging out of \"root\", before you do anything else.      *
*************************************************************

"

