[Pkg-gtkpod-devel] r280 - in gtkpod/tags: . 0.99.10-5 0.99.10-5/debian 0.99.10-5/debian/patches 0.99.10-5/scripts 0.99.10-5/src

nion at alioth.debian.org nion at alioth.debian.org
Tue Nov 20 13:46:36 UTC 2007


Author: nion
Date: 2007-11-20 13:46:35 +0000 (Tue, 20 Nov 2007)
New Revision: 280

Added:
   gtkpod/tags/0.99.10-5/
   gtkpod/tags/0.99.10-5/README
   gtkpod/tags/0.99.10-5/debian/changelog
   gtkpod/tags/0.99.10-5/debian/control
   gtkpod/tags/0.99.10-5/debian/patches/
   gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch
   gtkpod/tags/0.99.10-5/debian/rules
   gtkpod/tags/0.99.10-5/scripts/sync-abook.sh
   gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh
   gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh
   gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh
   gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh
   gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh
   gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh
   gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh
   gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh
   gtkpod/tags/0.99.10-5/src/mp3file.c
   gtkpod/tags/0.99.10-5/src/prefs.c
Removed:
   gtkpod/tags/0.99.10-5/README
   gtkpod/tags/0.99.10-5/debian/NEWS
   gtkpod/tags/0.99.10-5/debian/changelog
   gtkpod/tags/0.99.10-5/debian/control
   gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch
   gtkpod/tags/0.99.10-5/debian/rules
   gtkpod/tags/0.99.10-5/scripts/sync-abook.sh
   gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh
   gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh
   gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh
   gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh
   gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh
   gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh
   gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh
   gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh
   gtkpod/tags/0.99.10-5/src/mp3file.c
   gtkpod/tags/0.99.10-5/src/prefs.c
Log:
tagging 0.99.10-5

Copied: gtkpod/tags/0.99.10-5 (from rev 259, gtkpod/trunk)

Deleted: gtkpod/tags/0.99.10-5/README
===================================================================
--- gtkpod/trunk/README	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/README	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,1116 +0,0 @@
-iPod, iTunes, Mac, Macintosh, iBook are trademarks of Apple Computer,
-Inc., registered in the U.S. and other countries.
-
-
-
-Donations are welcome: please go to
-https://sourceforge.net/project/project_donations.php?group_id=67873
-for details.
-
-
-*----------------------------------*
-|                                  |
-|            Contents              |
-|                                  |
-*----------------------------------*
-
-
-  - Using gtkpod
-  - Features
-     - Tracks
-     - Filter Tabs
-     - Playlists
-     - Drag and Drop
-     - Duplicate Detection
-     - Preferences File
-     - Startup and Shutdown scripts
-     - Load iPod and eject iPod scripts
-     - Extended Information File
-     - Refresh (Update) Track Info From File
-     - Synchronize Directories
-     - Volume Normalization
-     - Podcasts
-     - Export of Tracks (Copy from iPod)
-     - Encoding of ID3 tags (charsets)
-     - Extracting tag information from the filename
-     - Checking iPod's files
-     - Restoring your iPod after file system error
-     - Playcounts & Rating
-     - About filenames
-  - Icons for window managers
-  - Connecting iPod to a Linux box:
-  - Sick of loading the sbp2 modules by hand? (an example of how to
-    use startup/shutdown scripts)
-
-*----------------------------------*
-|                                  |
-|          Using gtkpod            |
-|                                  |
-*----------------------------------*
-
-
-1) If your iPod is not mounted automatically when connecting it to
-   your computer follow steps 1-7 in the "Connecting your iPod to a
-   Linux box" (basically you need to get the iPod partition mounted to
-   /media/ipod).  In most cases this should not be necessary any more
-   these days.
-
-2) If you are using GNOME, starting with V1.0 of gtkpod your iPod will
-   be automatically loaded and displayed within gtkpod once you
-   connect it to your box. Otherwise:
-
-   - Use "Load iPods" to import the contents of your old iTunesDB (you
-     may have to specify the correct mountpoint: right-button click on
-     the "iPod" repository, select "Edit iPod's Properties" and change
-     the mountpoint).
-
-3) Use "Add Files", "Add Directories" or DND to add files or
-   directories.
-
-4) Use "Eject iPod" in the context menu or click on the icon to the
-   left of the iPod name to write the added files to the iPod and
-   create a new iTunesDB and unload the iPod from gtkpod.
-
-5) Unmount your iPod. The easiest way is to use the windowmanager. If
-   this is not an option for you continue with step 8-11 of the
-   "Connecting your iPod to a Linux box" section (basically describing
-   how to unmount and disconnect your iPod).
-
-   You can automate the unmounting by adding creating a
-   ~/.gtkpod/gtkpod.eject file with the following line in it (without
-   the quotation marks): "eject $1"
-
-
-*----------------------------------*
-|                                  |
-|            Features              |
-|                                  |
-*----------------------------------*
-
-Tracks
------
-
-- You can add individual tracks, entire directories recursively, or
-  existing playlists using "Add Files". A file selection dialogue will
-  appear. By default existing tracks (same full filename) will be skipped.
-- You can add directories recursively using "Add Dirs". A directory
-  selection dialogue will appear.
-- You can add existing playlists using "Add Playlists"
-- You can delete tracks by marking them and pressing the "Ctrl-d" . If
-  you delete tracks from the master playlist (the topmost playlist,
-  called "gtkpod" by default).  You can also delete tracks by selecting them,
-  and using "Delete Track" in the Edit menu or from the context menu.
-- You can update ID3 tags of selected tracks in gtkpod from the mp3
-  file by pressing "Ctrl-u" or choose "Update track info from file" in
-  the Edit menu or from the context menu.
-- You can rename ID3 tags by editing the fields in gtkpod. You can
-  change an entire group of ID3 tags by editing an entry in the sort
-  tab (or mark several tracks and edit the first).
-- You can specify which tags to display in the preferences window
-- You can specify (in the prefs window) if the ID3 tags of the
-  corresponding mp3 file(s) should also be updated
-
-
-Filter Tabs
------------
-
-- The two notebooks above the track display are called "Filter Tabs"
-- They allow you to filter which tracks to display
-- If you edit an entry in the filter tab, the corresponding entry in all
-  associated tracks will be updated as well. When writing the tags to
-  disk as well, updating of a large number of tracks may take a while
-
-
-Playlists
----------
-
-- You can create playlists with "New Playlist" or pressing "Ctrl-n" in
-  the playlist listview.
-- You can also create playlists by adding an existing playlist file
-  with "Add file" or "Add playlist".
-- You can add tracks to playlists by marking the tracks you want to add,
-  and then dragging them onto the playlist.
-- You can rename playlists.
-- You can delete playlists by selecting the desired playlist and pressing
-  "Ctrl-D", or by selecting "Delete Playlist" from the Edit menu.
-
-
-Drag and Drop
--------------
-
-Drag and Drop can be used in several ways:
-
-1) gtkpod internal
-
-- Playlists, entries of a filter tab, and tracks can be dragged.
-
-- A drop _onto_ an existing playlist will add the tracks to that
-  playlist
-
-- A drop _between_ two existing playlists or behind the last playlist
-  will create a new playlist to which the tracks are added.
-
-- The default action for the drop is either move or copy as appears
-  appropriate (e.g. playlists are moved within a database ('local' or
-  'iPod/Shuffle'), but copied when dragged across different
-  databases).  The applicable action is displayed within the drag
-  icon and can be changed by pressing the control key during the drop. 
-
-2) between external file browser and gtkpod
-
-- Tracks, directories or playlist files can be dropped onto the
-  playlist view or track view. Drops between two existing playlists
-  create a new playlist.
-
-
-Preferences File
-----------------
-
-On startup gtkpod will read the preferences from ~/.gtkpod/prefs (or
-/etc/gtkpod/prefs if the former doesn't exist).
-
-
-Startup and Shutdown Scripts
-----------------------------
-
-After reading the preferences file gtkpod will try to execute
-~/.gtkpod/gtkpod.in (or /etc/gtkpod/gtkpod.in if the former doesn't
-exist) during startup.
-
-Just before exiting the program, gtkpod will try to execute
-~/.gtkpod/gtkpod.out (or /etc/gtkpod/gtkpod.out if the former doesn't
-exist).
-
-Please see the section "Sick of loading the sbp2 modules by hand?" for
-an example of how to use this functionality.
-
-
-
-Load iPod and eject iPod scripts
---------------------------------
-
-Before loading the contents of an iPod, gtkpod will call
-~/.gtkpod/gtkpod.load with the iPod's mountpoint as the only
-command line argument. Put any commands here needed to access the
-iPod, for example if you need to mount the iPod manually.
-
-When ejecting an iPod, gtkpod will call ~/.gtkpod/gtkpod.eject
-with the the iPod's mountpoint as the only command line argument. Put
-any commands here you want to execute after gtkpod has written the
-changes to the iPod. One major candidate will probably be 
-
-sudo eject $1
-
-gtkpod will not attempt to do any magic of it's own to
-mount/unmount/eject the iPod.
-
-
-
-Duplicate Detection
--------------------
-
-You can instruct gtkpod (in the prefs window) to use
-file-size-dependent SHA1 checksums to prevent the same file from
-being copied to your iPod twice.
-
-If a duplicate is detected, gtkpod will print out the the filenames
-of the duplicate files. If the filename of the already existing file
-is not available (it is not stored in the iTunes database, see
-"Extended Information File" below), other available information of
-the track is printed.
-
-
-Extended Information File
--------------------------
-
-Some (I believe) essential information is not stored in Apple's iTunes
-database. You can therefore instruct gtkpod to write an additional
-file (iTunesDB.ext) with extended information. For each track it stores
-
-  - SHA1 hash
-  - filename in the locale's encoding
-  - filename in UTF8 encoding
-  - hostname where the file was added (not used for anything yet)
-  - filename of an associated converted file (for example an .mp3 for
-    a .flac file)
-  - if the file is present in the local database a reference to there
-    in order for playcounts to work on the local database as well
-  - last modification time
-  - the charset used for the file when adding it
-
-Since the extended information file is only valid with the
-corresponding standard iTunes database, a checksum of the iTunes
-database is also stored in the extended information file.
-
-Using an extended information file will considerably speed up the
-import of an existing iTunes database when using duplicate detection,
-since the SHA1 checksums do not have to be re-calculated.
-
-Using an extended information file will also allow modification of ID3
-tags in the track files after the initial import, because the full
-filenames are still available.
-
-
-Refresh (Update) Track Info From File
-------------------------------------
-
-If you have changed the ID3 tags of your original file, you can update
-the ID3 tags stored in gtkpod without removing and re-adding the
-track. Simply select the track to be updated and press "Ctrl-u" or
-choose "Update Track Info From File" from the Edit menu. Since gtkpod
-needs to know the filename of the track, the "Extended Information
-File" (see above) is needed.
-
-"Update" will also re-read the replay-gain tags from disk, if
-available, and set the soundcheck field. If no replay-gain tag is
-available, the soundcheck field will be erased.
-
-You can also select entries in the filter tab or entire playlists for
-refresh.
-
-
-Synchronize with Directories
-----------------------------
-
-If you have added files to directories or changed files in directories
-you have previously added tracks from, you can use the "Synchronize
-Dirs" utility to update your iTunesDB.
-
-"Synchronize with Dir(s)" will use the selected tracks to make a list
-of directories to update, so you should activate the "Write Extended
-Information" option in the export section of the preferences dialogue.
-
-It will then add all non-existing tracks in those directories and
-update (see "Refresh") all existing tracks. The tracks are also added to
-the currently selected playlist, if they aren't already a member.
-
-Tracks that have been removed from the directory will only be removed
-from the iTunesDB if this option is checked in the option dialogue.
-
-For best results you should also activate duplicate detection. This
-avoids unnecessary copying of unchanged tracks.
-
-
-
-Volume Normalization
---------------------
-
-There are two fields in the iTunesDB that allow to adjust the volume
-of an individual track: the volume field (a signed integer) and the
-soundcheck field (in dB). The volume is always active, whereas the
-soundcheck field is only active when you select 'soundcheck' on the
-iPod. Further, the soundcheck field only affects the earphone output
-but not the line output of the iPod.
-
-gtkpod will set the soundcheck according to the replay-gain tag set in
-your mp3 file. Newer versions of 'lame' automatically include the
-replay-gain tag when encoding. In that case the soundcheck field will
-be filled in when you first import a track.
-
-If no replay-gain tag is set, you can use the function 'Normalize
-Volume' to call mp3gain (mp3gain.sourceforge.net) to calculate the
-gain and write a replay-gain tag. Since this procedure is very time
-consuming, it is not done automatically during import. You need to
-install mp3gain in the default path or set the full path in the
-'Tools' section of the preferences dialog. If the iPod is connected,
-the tag is written to the file stored on the iPod.
-
-At this time "album gain" functionality is not supported. "Album gain"
-means that the volume of all tracks of one album is adjusted by the
-same gain, such that the relative volume level remains the same. It is
-planned to realize this in one of the next versions.
-
-Also, please be aware that tracks are not normalized on a 'per
-playlist' fashion. If a track is normalized, it's normalized in all
-playlists it is a member of.
-
-Once the replay-gain tag has been read, it is stored in the extended
-information file 'iTunesDB.ext'. When you call 'Normalize volume'
-again, the stored value will be used to re-populate the soundcheck
-field. Use 'Update Track' to re-read the tag from the file.
-
-
-Podcasts
---------
-
-You have to download podcasts using a third party tool like bashpodder
-(http://linc.homeunix.org:8080/scripts/bashpodder/) or gpodder
-(http://perli.net/projekte/gpodder/)
-
-Podcasts should be added directly into the 'Podcasts' playlist of the
-iPod repository, for example by selecting the Podcasts playlist before
-manually adding files/directories. Podcasts will then appear only in
-the Podcasts section on the iPod.
-
-If you add podcasts to the main playlist 'gtkpod/iPod' or any other
-iPod playlist first and then drag them over to the Podcasts playlist,
-the podcasts will appear in the Podcasts section on the iPod, as well
-as in the normal music section.
-
-The podcast 'repository' is a local repository (like 'Local') where
-you can keep all local podcasts. No mechanism exists to automatically
-synchronize the iPod repository with the Podcast repository at this
-time. You have to drag the podcasts over manually.
-
-
-Export of Tracks (Copy from iPod)
----------------------------------
-
-- mark the tracks you want to export and select "Export Tracks from
-  Database" from the file menu (or use the context sensitive menu)
-- A file selection dialog window appears and you can choose the directory
-  you'd like the selected files to be written to.
-- You can specify the output filename in the prefs dialog by
-  specifying a template (e.g. "%A/%a - %t"). You can specify multiple
-  templates for different file formats by separating them by a
-  semicolon (e.g. "%A/%a - %t.mp3;%t.wav"). See the tooltip in the
-  prefs dialog for a list of identifiers.
-
-
-Encoding of ID3 tags (charsets)
--------------------------------
-If you use correctly written unicode ID3V2 tags you don't have to
-worry about the charset setting.
-
-Otherwise you must specify the charset to be used for representing ID3
-tags in the preferences menu. The default is "System Charset", which
-is the charset associated with the locale gtkpod is running under. If
-your tags are stored in a different encoding, you should set it
-appropriately.
-
-Please note that if necessary you can change the charset each time you
-add files or directories: the iTunesDB itself is using UTF16, so once
-tags are imported correctly, changing the charset has no influence.
-
-If you chose "Japanese (automatic detection)", gtkpod will try to
-determine if the string is in ISO-2022-JP, Shift_JIS, or EUC-JP
-(Hankaku Katakana (1-byte Katakana) may not be recognized correctly --
-specify the correct encoding if you run into this problem). The actual
-encoding used for the ID tags will be stored and will be used when
-writing tags or doing updates/syncs. Check the "Use selected charset
-also when updating or syncing tracks" and "Use selected charset when
-writing tags" options if you want to specify a particular character
-set when writing or updating/syncing. The default charset is "EUC-JP"
--- it will be used when the charset cannot be autodetected, as well as
-when writing tags if a specific charset could not be determined
-before.
-
-gtkpod will recognize ID3V2 tags encoded in unicode automatically and
-ignore your charset setting when necessary.
-
-
-Extracting tag information from the filename
---------------------------------------------
-Tags can also be extracted from the filename if you activate the
-option 'Use this template to parse filename for tag information' and
-supply a template that explains how the filenames are constructed.
-
-For filenames like 
-    music/new/latin1/alan_jackson - drive/01 drive_for_daddy_gene.mp3
-you could use
-    %a - %A/%T %*.mp3
-
-to extract artist, album, track number and title.
-
-The following character sequences are supported:
-
-    %t: title
-    %a: artist
-    %A: album
-    %c: composer
-    %t: title
-    %g: genre
-    %T: track number
-    %C: CD number
-    %*: placeholder, ignore data
-    %%: the character '%'
-
-You cannot supply a template like "%a%t.mp3" because gtkpod would not
-know how to separate artist and title. "%a_%t.mp3" would be correct,
-if artist and title are separated by an underscore.
-
-You can also omit the trailing ".mp3" if you want the template to
-apply to all files instead of only to mp3 files.
-
-
-Checking iPod's Files
----------------------
-For whatever reason -- it may happen that tracks are present in your
-iTunesDB that are no longer present on the iPod (dangling tracks), or
-that tracks are on the iPod but not in the iTunesDB (orphaned
-tracks).
-
-The function "Checking iPod's Files" under the "File" menu will
-identify both types and take the following actions:
-
-Orphaned tracks:
-A new playlist "[Orphaned]" will be created with all orphaned tracks
-in it. The only exception are orphaned tracks that would become
-duplicates (if duplicate detection is activated). Those are marked for
-deletion with the next sync.
-
-Dangling tracks:
-These tracks will be marked for deletion with the next sync unless the
-original PC file is still available. In that case you can have them
-restored with the next sync.
-
-
-Restoring your iPod after file system error
--------------------------------------------
-If iPod's file system gets corrupted and you need to reformat your
-iPod, there is a way to restore the contents semi-automatically if you
-have been using the "write extended information file" (iTunesDB.ext)
-options:
-
- - If the directory structure on the iPod doesn't exist yet,
-   load the iPod in gtkpod and have it created for you. Then unload
-   the iPod again.
-
- - copy your backup files in .gtkpod/ (usually iTunesDB and
-   iTunesDB.ext) to your iPod (usually
-   <mountpoint>/iPod_Control/iTunes/
-   On the iPod the files must be named iTunesDB and iTunesDB.ext.
-
- - load the iPod in gtkpod
-
- - select the iPod repository and start "Check iPod's files" from the
-   File menu
-
- - unload the iPod (or save changes)
-
-This should restore your iPod to what it was before, provided you
-didn't move or remove any of the original tracks on your harddrive, and
-the charset information was stored correctly.
-
-
-Playcounts & Rating
--------------------
-
-Whenever you play a track completely on the iPod (firmware version 1.3
-or higher) a counter in the "Play Counts" file will be increased by
-one. The same file also contains the rating you can set with the 3rd
-generation iPods.
-
-This file appears to be deleted whenever the iPod resets itself --
-e.g. because you disconnect it from the computer. Therefore, be
-careful... Charging the iPod seems to do no harm.
-
-When gtkpod is started, it will also read this file and incorporate
-the information into the iTunesDB that can be written back to the
-iPod.
-
-There have been several requests to also register playcounts when
-playing a track on the local machine. This is possible by calling
-gtkpod as "gtkpod -p <filename>".
-
-If gtkpod is already running, the playcount of that track there will
-be increased by one. If gtkpod is not already running, the playcount
-will be registered in ~/.gtkpod/offline_playcount. This file will be
-read the next time you import the iTunesDB from your iPod, and the
-playcounts will be updated accordingly.
-
-Please note that if you start several instances of gtkpod, only the
-first instance will register playcounts through "gtkpod -p".
-
-Now all you have to do is tell your favorite player to call gtkpod
-with the filename of the played track.
-
-For xmms this is possible as of July 18th, 2004 (CVS
-version). Versions before that (including 1.2.10) only allow you to
-have an external program called at the beginning of a track. Our patch
-allows to have an external program called also at the end of a track.
-
-In each case you will need to activate the "General Plugin" called
-"song_change" and configure it to call 'gtkpod -p "%f"'.
-
-
-About filenames (excerpt from the GTK2 release notes):
-------------------------------------------------------
-* The assumption of GLib and GTK+ by default is that filenames on the
-  filesystem are encoded in UTF-8 rather than the encoding of the locale;
-  The GTK+ developers consider that having filenames whose interpretation
-  depends on the current locale is fundamentally a bad idea.
-
-  If you have filenames encoded in the encoding of your locale, then
-  you may want to set the G_BROKEN_FILENAMES environment variable:
-  
-   G_BROKEN_FILENAMES=1
-   export G_BROKEN_FILENAMES
-
-  Best integration of GTK+-2.0 with the environment is achieved by 
-  using a UTF-8 locale.
-
------- end of excerpt
-
-It is my feeling that many people use filenames encoded in the
-encoding of the locale. The "Add directories" dialogue already takes
-care of this and assumes the filenames to be in the same encoding as
-you have specified for the ID3 tags (see above). You can therefore
-forget about the excerpt above.
-
-However, the "Add Files" and "Add Playlists" dialogue (at the moment)
-uses the standard GTK+-2.0 file selection dialogue. Therefore I have
-no access on the conversion functions used, and a warning is printed
-when filenames are encountered that are encoded in an encoding other
-than the one of the current locale. ID3 tags are still read correctly
-(according to the charset set in the preference dialogue).
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Environment variables		           |
-|                                                  |
-*--------------------------------------------------*
-
-The following environment variables can be set if needed:
-
-IPOD_MOUNTPOINT: Defines the mountpoint of the iPod. This overwrites
-the value stored in the prefs, but is overwritten by the command line
-argument "-m" or "--mountpoint".
-
-GTKPOD_DF_COMMAND: Only used on systems without statvfs(). Defines the
-"df" command to be used for probing the free space on the iPod
-including command line arguments. Default is "df -k -P". On some
-systems it may be necessary to remove the "-P" option. The mount point
-is added to this command line automatically. You can switch off calls
-to df by setting this environment variable to an empty string.
-
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Icons for window managers		           |
-|                                                  |
-*--------------------------------------------------*
-
-Should you require an icon for your window manager you can use those
-provided in $(datadir)/pixmaps (usually
-/usr/local/share/gtkpod/pixmaps or
-/usr/share/gtkpod/pixmaps).
-
-Currently the following files are available:
-
-  gtkpod-icon-32.png
-  gtkpod-icon-32x32.png
-  gtkpod-icon-32x32-2.png
-  gtkpod-icon-48.png
-  gtkpod-icon-48x48.png
-  gtkpod-icon-64x64.png
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Connecting iPod to a Linux box	           |
-|  (kernel 2.6.6)                                  |
-|  (should also work with earlier 2.6 kernels)     |
-|                                                  |
-*--------------------------------------------------*
-
-This describes how to set up the iPod together with the automounter in
-kernel V2.6.6 (some minor changes in the kernel configuration may be
-necessary for older V2.6 versions).
-
-1) It appears to be possible to use HFS-formatted (Apple)
-   iPods. However, this short guide assumes you have a Windows
-   (VFAT) iPod. For conversion from HFS to VFAT please see 
-
-   http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
-
-2) I'm using the following kernel configuration options (I'm only
-   using FireWire -- so the USB options are just educated
-   guesses. Please let me know if it works).
-
-   I'm not using modules, simply because what's compiled in can't fail
-   loading.
-
-    * General Setup  -> Support for hot-pluggable devices - y
-    * Device Drivers -> SCSI device support - y
-    *                -> SCSI device support -> SCSI disk support - y
-    *                -> SCSI device support -> SCSI generic support - y
-For FireWire:
-    *                -> IEEE1394 (FireWire) support - y
-    *                -> IEEE1394 (FireWire) support -> OHCI-1394 support - y
-    *                -> IEEE1394 (FireWire) support -> SBP-2 support - y
-For USB:
-    *                -> USB support -> Support for Host-side USB - y
-    *                                       -> EHCI HCD support - y
-    *                                       -> OHCI HCD support - y
-    *                                       -> UHCI HCD support - y
-    *                                       -> USB Mass Storage support - y
-For USB and FireWire:
-    * Filesystems    -> DOS/FAT/NT Filesystems - y
-    *                -> DOS/FAT/NT Filesystems -> VFAT fs support - y
-    *                -> Kernel automounter version 4 support - y
-    *                -> Native Language Support
-    *                            -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
-    *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
-
-
-
-(for iPods formatted with the HFS filesystem choose
-    * Filesystems -> Miscellaneous filesystems
-			   -> Apple Extended HFS filesystem support)
-
-At least for the new 4Gs and iPod minis you should _disable_
-(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
-    * File Systems -> Partition Types -> Advanced Partition Selection
-		   -> EFI GUID Partition support
-
-3) You need to install the following external packages:
-
-   hotplug and udev (http://linux-hotplug.sourceforge.net/)
-   autofs (ftp.kernel.org:/pub/linux/daemons/autofs)
-
-   Most likely packages are available for your distribution.
-
-4) Write rules for udev (/etc/udev/udev.rules, add at the beginning)
-   to recognize your iPod automatically (mind the spaces within
-   "iPod...", and be aware that some distributions require a double
-   equal after the BUS keyword (BUS=="scsi"...)):
-
-BUS="scsi", SYSFS{model}="iPod            ", KERNEL="sd?2", NAME="%k", SYMLINK="ipod"
-
-   This will map /dev/sd?2 to /dev/ipod everytime you plug in your
-   iPod. That even works if you own more than one USB/Firewire device
-   that shows up as a harddisk, independent of the order in which you
-   connect the devices.
-
-   (You need to replace "sd?2" with "sd?1" (or maybe just "sd?") for
-   HFS formatted iPods.)
-
-   For more information on how to write udev rules please refer to
-   http://www.gamingclones.com/Howtos/udevrules.html. That document
-   gives an easy-to-understand introduction
-
-5) Set up autofs to automatically mount the iPod when you access it
-   and unmount it after 2 seconds of inactivity. In /etc/auto.master
-   add:
-
-/var/autofs/removable   /etc/auto.removable     --timeout=2,sync,nodev,nosuid,gid=autofs,umask=007
-
-   Adjust the gid,umask (and uid) values to whatever you need -- in this
-   example all users in the group "autofs" have read/write access, and
-   I have added all users that may access the iPod to the autofs group.
-
-   In /etc/auto.removable add
-
-ipod            -fstype=vfat            :/dev/ipod
-
-   (Obviously you need to change the filesystem type from 'vfat' to
-   'hfsplus' when you use an HFS formatted iPod.)
-
-   Then simply add a link from /media/ipod:
-
-   ln -s /var/autofs/removable/ipod /media/ipod
-
-
-Now your system is configured to mount the iPod every time you access
-/media/ipod and to unmount it again after two seconds of inactivity. You
-won't have to worry about doing mounting/unmouting yourself any more.
-
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Connecting iPod to a Linux box (IEEE 1394)      |
-|  (kernel 2.4.21)                                 |
-|  (may also work with 2.4.20, but I didn't try)   |
-|  (instructions for 2.4.20 can be found below)    |
-|                                                  |
-*--------------------------------------------------*
-
-1) You need a Windows iPod. See e.g.
-
-http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
-
-for information about how to convert your mac iPod to a windows iPod.
-
-Alternatively, I have received a report that Alan Cox's patches
-(2.4.21-rc8-ac1, but 2.4.21-ac1 should work as well) include hfsplus
-support. That should allow you to use hfs formatted iPods. But beware:
-hfsplus support is still beta.
-
-2) Get kernel source and configure
-Needed configuration:
-
-    * Code maturity level options - y
-    * SCSI support - y
-    * SCSI disk support - y
-    * IEEE1394 (FireWire)/IEEE 1394 (FireWire) support (Experimental) - y
-    * OHCI-1394 support - y
-    * SBP-2 support - m (important to use module -- if someone finds
-      out how to use hotplug with sbp2 compiled in, let me know)
-      (With 2.6.1 compiling sbp2 in seems to work fine.)
-At least for the new 4Gs and iPod minis you should _disable_
-(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
-    * File Systems -> Partition Types -> Advanced Partition Selection
-		   -> EFI GUID Partition support
-    *              -> Native Language Support
-    *                            -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
-    *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
-
-
-3) Create /media/ipod:
-
-   mkdir /media/ipod
-
-4) Add a line to /etc/fstab. You should edit uid to match your user
-   id. Also, /dev/sda2 may not be appropriate, if you have other scsi
-   devices.
-
-/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
-
-   (For HFS this line should read
-
-/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
-
-    please note that it's just '/dev/sda')
-
-
-NOTE: Some users have had problems with newer versions of mount(newer than
-mount-2.11h) The following fstab entry might work better for you.
-
-/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
-
-5) Install the hotplug utilities
-   (http://linux-hotplug.sourceforge.net/, debian package: 'hotplug')
-
-   (If you don't want to use the hotplug utilities, you must call the
-   rescan-scsi-bus.sh (see below) by hand after loading the sbp2
-   module. This is different from 2.4.20.)
-
-5a) Add the ieee1394 hotplug support (described at
-    http://www.linux1394.org/faq.html#hotplug):
-
-   - copy ieee1394.agent to /etc/hotplug/ from
-     http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/linux-hotplug/admin/etc/hotplug/
-   - mkdir /etc/hotplug/ieee1394
-   - create /etc/hotplug/ieee1394/sbp2:
-       #!/bin/bash
-       if [ "${ACTION}" = "add" ]; then
-	 . /etc/hotplug/ieee1394/rescan-scsi-bus.sh
-       else
-	 . /etc/hotplug/ieee1394/rescan-scsi-bus.sh -r
-       fi
-   - chmod +rx /etc/hotplug/ieee1394/sbp2
-   - copy rescan-scsi-bus.sh to /etc/hotplug/ieee1394 from
-     http://www.garloff.de/kurt/linux/rescan-scsi-bus.sh
-   - just to be sure: restart hotplug:
-	/etc/init.d/hotplug restart
-
-6) Connect your iPod to your computer and wait until you see something
-   like the following on your system log (you can use the 'dmesg'
-   command to check).
-
-Jun 15 17:13:53 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
-Jun 15 17:13:55 hatarakibachi kernel: ieee1394: Node 01:1023 changed to 00:1023
-Jun 15 17:13:57 hatarakibachi kernel: ieee1394: sbp2: Logged into SBP-2 device
-Jun 15 17:13:57 hatarakibachi kernel: ieee1394: Device added: Node[00:1023]  GUID[000a2700020680b5]  [Apple Computer, Inc.]
-Jun 15 17:13:57 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
-Jun 15 17:13:57 hatarakibachi kernel: scsi singledevice 0 0 0 0
-Jun 15 17:13:57 hatarakibachi kernel:   Vendor: Apple     Model: iPod              Rev: 1.30
-Jun 15 17:13:57 hatarakibachi kernel:   Type:   Direct-Access                      ANSI SCSI revision: 02
-Jun 15 17:13:57 hatarakibachi kernel: Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0
-Jun 15 17:13:57 hatarakibachi kernel: SCSI device sda: 39062520 512-byte hdwr sectors (20000 MB)
-Jun 15 17:13:57 hatarakibachi kernel: sda: test WP failed, assume Write Enabled
-Jun 15 17:13:58 hatarakibachi kernel:  sda: sda1 sda2
-Jun 15 17:13:58 hatarakibachi kernel: scsi singledevice 0 0 1 0
-...
-
-7) Mount the iPod hard drive
-
-   mount /media/ipod
-
-8) do whatever you need to do (e.g. start gtkpod, see below)
-
-9) Unmount the iPod:
-
-    umount /media/ipod
-
-10) Unload the module sbp2 (as most likely as root):
-
-    rmmod sbp2
-
-11) Disconnect the iPod from your computer (ignore the "Do not
-    disconnect" message -- as long as you wait for the 'unmount' to
-    command to finish properly, everything should be fine).
-
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Connecting iPod to a Linux box using IEEE 1394  |
-|  (kernel 2.4.20)                                 |
-|  (connecting to 2.4.21 seems to work slightly    |
-|   differently -- see above)                      |
-|                                                  |
-*--------------------------------------------------*
-
-1) You need a Windows iPod. See e.g.
-
-http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
-
-for information about how to convert your mac iPod to a windows iPod.
-
-Alternatively, I have received a report that Alan Cox's patches
-(2.4.21-rc8-ac1, but 2.4.21-ac1 should work as well) include hfsplus
-support. That should allow you to use hfs formatted iPods. But beware:
-hfsplus support is still beta.
-
-2) Get kernel source and configure
-Needed configuration:
-
-    * Code maturity level options - y
-    * SCSI support - y
-    * SCSI disk support - m
-    * IEEE1394 (FireWire)/IEEE 1394 (FireWire) support (Experimental) - y
-    * OHCI-1394 support - y
-    * SBP-2 support - m
-At least for the new 4Gs and iPod minis you should _disable_
-(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
-    * File Systems -> Partition Types -> Advanced Partition Selection
-    *	   	   -> EFI GUID Partition support
-    *              -> Native Language Support
-    *                          -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
-    *                          -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
-
-3) Create /media/ipod:
-
-   mkdir /media/ipod
-
-4) Add a line to /etc/fstab. You should edit uid to match your user
-   id. Also, /dev/sda2 may not be appropriate, if you have other scsi
-   devices.
-
-/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime 0 0
-
-   (For HFS this line should read
-
-/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
-
-    please note that it's just '/dev/sda')
-
-
-NOTE: Some users have had problems with newer versions of mount(newer than
-mount-2.11h) The following fstab entry might work better for you.
-
-/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
-
-NOTE: You can add ",umask=0" to the options to make the iPod
-readable/writable for all users.
-
-5) Connect your iPod to your computer and wait until you see something
-   like the following on your system log (you can use the 'dmesg'
-   command to check).
-
-Nov 28 21:58:06 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
-Nov 28 21:58:09 hatarakibachi kernel: ieee1394: Node 01:1023 changed to 00:1023
-Nov 28 21:58:12 hatarakibachi kernel: ieee1394: NodeMgr: hotplug policy returned -2
-Nov 28 21:58:12 hatarakibachi kernel: ieee1394: Device added: Node[00:1023]  GUID[000a2700020680b5]  [Apple Computer, Inc.]
-Nov 28 21:58:12 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
-
-6) Load the sbp2 module (most likely as root):
-
-   modprobe sbp2
-
-   You should see something like the following on your system log:
-
-Nov 28 21:58:38 hatarakibachi kernel: ieee1394: sbp2: Logged into SBP-2 device
-Nov 28 21:58:38 hatarakibachi kernel: scsi0 : IEEE-1394 SBP-2 protocol driver (host: ohci1394)
-Nov 28 21:58:38 hatarakibachi kernel: $Rev$ James Goodwin <jamesg at filanet.com>
-Nov 28 21:58:38 hatarakibachi kernel: SBP-2 module load options:
-Nov 28 21:58:38 hatarakibachi kernel: - Max speed supported: S400
-Nov 28 21:58:38 hatarakibachi kernel: - Max sectors per I/O supported: 255
-Nov 28 21:58:38 hatarakibachi kernel: - Max outstanding commands supported: 8
-Nov 28 21:58:38 hatarakibachi kernel: - Max outstanding commands per lun supported: 1
-Nov 28 21:58:38 hatarakibachi kernel: - Serialized I/O (debug): no
-Nov 28 21:58:38 hatarakibachi kernel: - Exclusive login: yes
-Nov 28 21:58:38 hatarakibachi kernel:   Vendor: Apple     Model: iPod              Rev: 1.21
-Nov 28 21:58:38 hatarakibachi kernel:   Type:   Direct-Access                      ANSI SCSI revision: 02
-Nov 28 21:58:38 hatarakibachi kernel: Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0
-Nov 28 21:58:38 hatarakibachi kernel: SCSI device sda: 39062520 512-byte hdwr sectors (20000 MB)
-Nov 28 21:58:38 hatarakibachi kernel: sda: test WP failed, assume Write Enabled
-Nov 28 21:58:39 hatarakibachi kernel:  sda: sda1 sda2
-
-7) Mount the iPod hard drive
-
-   mount /media/ipod
-
-8) do whatever you need to do (e.g. start gtkpod, see below)
-
-9) Unmount the iPod:
-
-    umount /media/ipod
-
-10) Unload the module sbp2 (as most likely as root):
-
-    rmmod sbp2
-
-11) Disconnect the iPod from your computer.
-
-
-*--------------------------------------------------*
-|                                                  |
-|  Connecting iPod to a Linux box (USB)            |
-|                                                  |
-*--------------------------------------------------*
-
-I don't have much information about this so far (I don't own a third
-generation iPod). Please help me to fill in the gaps.
-
-Stephen Drye sent me the following note:
-
-"I've figured out how to get a USB-connected iPod recognized...:
-
-The trick to it is that you have to 
-
-- plug the iPod in
-
-- it'll fail to be recognized by the SCSI subsystem
-
-- now, even though your ipod says not to, unplug the USB cord and
-  immediately plug it back in.
-
-- since the iPod's hdd was already spun up, the SCSI subsystem now
-  recognizes it and mounts it as /dev/sda
-
-- You can then mount /dev/sda2 to /media/ipod as normal."
-
-On the other hand: with my 4G iPod under 2.6.9 and 2.6.10 I never had
-any problem whatsoever getting the iPod to work. With IEEE it was
-awful (would work some times, would not some other time).
-
-
-*----------------------------------*
-|                                  |
-|     Sick of loading the sbp2     |
-|         modules by hand?         |
-|                                  |
-|         Corey Donohoe            |
-|     <atmos at atmos dot org>     |
-|         March 22nd 2003          |
-|                                  |
-*----------------------------------*
-
-Sick of loading the sbp2 modules by hand every time you want to use your
-ipod?  Are you sick of mounting it too?  Using sudo gtkpod can make manually
-interacting with the ipod filesystem a thing of the past.  Note that you
-should have your ipod working with gtkpod before attempting this automated
-method, see the README that came with gtkpod in order to get things up and
-running.
-
-Here's a brief example of how I'm using gtkpod now in 8 easy steps.
-
-(Remark: the hotplug facility of new kernels can also load and unload
-the sbp2 module for you.)
-
-/**********/
- * Step 1 *
-/**********/
-Using sudo allow users to load/remove the sbp2 module
-Example /etc/sudoers
-------------------------------- Begin Here ---------------------------------
-
-# Cmnd alias specification
-Cmnd_Alias IPOD=/sbin/modprobe sbp2 sbp2_force_inquiry_hack=1, /sbin/rmmod sbp2
-# User privilege specification
-atmos   ALL=(ALL) ALL
-atmos   ALL= NOPASSWD : IPOD
-
-------------------------------- End Here -----------------------------------
-I use the force inquiry hack cause I have an older iPod, if you normally can
-get by with /sbin/modprobe sbp2 then ignore the inquiry hack stuff.  Note
-that explicitly specifying which module to probe/remove keeps the user from
-being able to add/remove arbitrary modules.  This allows us to keep gtkpod
-as a user process, and execute commands the user wouldn't usually have
-enough rights to.
-
-/**********/
- * Step 2 *
-/**********/
-Add a line similar to the below to your /etc/fstab, this will enable users
-to mount the ipod with read/write capabilities.  Example line assumes your
-ipod mount point is /media/ipod and your ipod is detected as /dev/sda
-
-------------------------------- Begin Here ---------------------------------
-/dev/sda2       /media/ipod       vfat    rw,user,noauto          0       0
-------------------------------- End Here -----------------------------------
-
-
-/**********/
- * Step 3 *
-/**********/
-Then setup your /etc/gtkpod/gtkpod.in file to load the module when gtkpod is
-started.
-Example /etc/gtkpod/gtkpod.in
-------------------------------- Begin Here ---------------------------------
-
-sudo /sbin/modprobe sbp2 sbp2_force_inquiry_hack=1
-
-------------------------------- End Here -----------------------------------
-
-/**********/
- * Step 4 *
-/**********/
-
-Then setup your /etc/gtkpod/gtkpod.out file to unload the module when gtkpod
-is exited.
-Example /etc/gtkpod/gtkpod.out
-------------------------------- Begin Here ---------------------------------
-
-sudo /sbin/rmmod sbp2 
-
-------------------------------- End Here -----------------------------------
-
-/**********/
- * Step 5 *
-/**********/
-Then enable ipod automounting in the gtkpod prefs(in the misc tab).
-
-/**********/
- * Step 6 *
-/**********/
-You're now ready to use gtkpod in a much nicer fashion.  Start by
-plugging in your ipod.  You should get a check mark with "OK to disconnect"
-displayed on your ipod.
-
-/**********/
- * Step 7 *
-/**********/
-Start gtkpod, your ipod should be accessible(i.e. autoimport should work)
-A "Do Not Disconnect" message is displayed on your ipod while gtkpod is
-running.
-
-/**********/
- * Step 8 *
-/**********/
-After you exit gtkpod, the "OK to disconnect" message should be displayed
-again.  It's ok to unplug your ipod now.  
-
-Good Luck. 
-
-
-
-*----------------------------------*
-|                                  |
-|           Known bugs             |
-|                                  |
-*----------------------------------*
-
-
-- Display of large number of tracks is awfully slow (mainly because of
-  the use of the standard GTK2 tree views) -> deactivate "Automatically
-  select "All" in first filter tab" and/or deactivate "Automatically
-  select master playlist". You could also "block the display" to speed
-  up the display update. Further, decreasing the window size
-  considerably speeds up the display.
-
-  I also want to point out that updating the info window takes up a
-  considerable amount of time. Update may become more intelligent in
-  the future -- until then close the info window for more speed.
-
-- When changing selections in the filter tabs while importing the
-  iTunesDB, sometimes the interface freezes. I tried to track this
-  problem down but only found out that gtk+ does not return control
-  back to gtkpod. Selecting the "All" filter tabs seems to unfreeze the
-  interface again.

Copied: gtkpod/tags/0.99.10-5/README (from rev 269, gtkpod/trunk/README)
===================================================================
--- gtkpod/tags/0.99.10-5/README	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/README	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,1116 @@
+iPod, iTunes, Mac, Macintosh, iBook are trademarks of Apple Computer,
+Inc., registered in the U.S. and other countries.
+
+
+
+Donations are welcome: please go to
+https://sourceforge.net/project/project_donations.php?group_id=67873
+for details.
+
+
+*----------------------------------*
+|                                  |
+|            Contents              |
+|                                  |
+*----------------------------------*
+
+
+  - Using gtkpod
+  - Features
+     - Tracks
+     - Filter Tabs
+     - Playlists
+     - Drag and Drop
+     - Duplicate Detection
+     - Preferences File
+     - Startup and Shutdown scripts
+     - Load iPod and eject iPod scripts
+     - Extended Information File
+     - Refresh (Update) Track Info From File
+     - Synchronize Directories
+     - Volume Normalization
+     - Podcasts
+     - Export of Tracks (Copy from iPod)
+     - Encoding of ID3 tags (charsets)
+     - Extracting tag information from the filename
+     - Checking iPod's files
+     - Restoring your iPod after file system error
+     - Playcounts & Rating
+     - About filenames
+  - Icons for window managers
+  - Connecting iPod to a Linux box:
+  - Sick of loading the sbp2 modules by hand? (an example of how to
+    use startup/shutdown scripts)
+
+*----------------------------------*
+|                                  |
+|          Using gtkpod            |
+|                                  |
+*----------------------------------*
+
+
+1) If your iPod is not mounted automatically when connecting it to
+   your computer follow steps 1-7 in the "Connecting your iPod to a
+   Linux box" (basically you need to get the iPod partition mounted to
+   /mnt/ipod).  In most cases this should not be necessary any more
+   these days.
+
+2) If you are using GNOME, starting with V1.0 of gtkpod your iPod will
+   be automatically loaded and displayed within gtkpod once you
+   connect it to your box. Otherwise:
+
+   - Use "Load iPods" to import the contents of your old iTunesDB (you
+     may have to specify the correct mountpoint: right-button click on
+     the "iPod" repository, select "Edit iPod's Properties" and change
+     the mountpoint).
+
+3) Use "Add Files", "Add Directories" or DND to add files or
+   directories.
+
+4) Use "Eject iPod" in the context menu or click on the icon to the
+   left of the iPod name to write the added files to the iPod and
+   create a new iTunesDB and unload the iPod from gtkpod.
+
+5) Unmount your iPod. The easiest way is to use the windowmanager. If
+   this is not an option for you continue with step 8-11 of the
+   "Connecting your iPod to a Linux box" section (basically describing
+   how to unmount and disconnect your iPod).
+
+   You can automate the unmounting by adding creating a
+   ~/.gtkpod/gtkpod.eject file with the following line in it (without
+   the quotation marks): "eject $1"
+
+
+*----------------------------------*
+|                                  |
+|            Features              |
+|                                  |
+*----------------------------------*
+
+Tracks
+-----
+
+- You can add individual tracks, entire directories recursively, or
+  existing playlists using "Add Files". A file selection dialogue will
+  appear. By default existing tracks (same full filename) will be skipped.
+- You can add directories recursively using "Add Dirs". A directory
+  selection dialogue will appear.
+- You can add existing playlists using "Add Playlists"
+- You can delete tracks by marking them and pressing the "Ctrl-d" . If
+  you delete tracks from the master playlist (the topmost playlist,
+  called "gtkpod" by default).  You can also delete tracks by selecting them,
+  and using "Delete Track" in the Edit menu or from the context menu.
+- You can update ID3 tags of selected tracks in gtkpod from the mp3
+  file by pressing "Ctrl-u" or choose "Update track info from file" in
+  the Edit menu or from the context menu.
+- You can rename ID3 tags by editing the fields in gtkpod. You can
+  change an entire group of ID3 tags by editing an entry in the sort
+  tab (or mark several tracks and edit the first).
+- You can specify which tags to display in the preferences window
+- You can specify (in the prefs window) if the ID3 tags of the
+  corresponding mp3 file(s) should also be updated
+
+
+Filter Tabs
+-----------
+
+- The two notebooks above the track display are called "Filter Tabs"
+- They allow you to filter which tracks to display
+- If you edit an entry in the filter tab, the corresponding entry in all
+  associated tracks will be updated as well. When writing the tags to
+  disk as well, updating of a large number of tracks may take a while
+
+
+Playlists
+---------
+
+- You can create playlists with "New Playlist" or pressing "Ctrl-n" in
+  the playlist listview.
+- You can also create playlists by adding an existing playlist file
+  with "Add file" or "Add playlist".
+- You can add tracks to playlists by marking the tracks you want to add,
+  and then dragging them onto the playlist.
+- You can rename playlists.
+- You can delete playlists by selecting the desired playlist and pressing
+  "Ctrl-D", or by selecting "Delete Playlist" from the Edit menu.
+
+
+Drag and Drop
+-------------
+
+Drag and Drop can be used in several ways:
+
+1) gtkpod internal
+
+- Playlists, entries of a filter tab, and tracks can be dragged.
+
+- A drop _onto_ an existing playlist will add the tracks to that
+  playlist
+
+- A drop _between_ two existing playlists or behind the last playlist
+  will create a new playlist to which the tracks are added.
+
+- The default action for the drop is either move or copy as appears
+  appropriate (e.g. playlists are moved within a database ('local' or
+  'iPod/Shuffle'), but copied when dragged across different
+  databases).  The applicable action is displayed within the drag
+  icon and can be changed by pressing the control key during the drop. 
+
+2) between external file browser and gtkpod
+
+- Tracks, directories or playlist files can be dropped onto the
+  playlist view or track view. Drops between two existing playlists
+  create a new playlist.
+
+
+Preferences File
+----------------
+
+On startup gtkpod will read the preferences from ~/.gtkpod/prefs (or
+/etc/gtkpod/prefs if the former doesn't exist).
+
+
+Startup and Shutdown Scripts
+----------------------------
+
+After reading the preferences file gtkpod will try to execute
+~/.gtkpod/gtkpod.in (or /etc/gtkpod/gtkpod.in if the former doesn't
+exist) during startup.
+
+Just before exiting the program, gtkpod will try to execute
+~/.gtkpod/gtkpod.out (or /etc/gtkpod/gtkpod.out if the former doesn't
+exist).
+
+Please see the section "Sick of loading the sbp2 modules by hand?" for
+an example of how to use this functionality.
+
+
+
+Load iPod and eject iPod scripts
+--------------------------------
+
+Before loading the contents of an iPod, gtkpod will call
+~/.gtkpod/gtkpod.load with the iPod's mountpoint as the only
+command line argument. Put any commands here needed to access the
+iPod, for example if you need to mount the iPod manually.
+
+When ejecting an iPod, gtkpod will call ~/.gtkpod/gtkpod.eject
+with the the iPod's mountpoint as the only command line argument. Put
+any commands here you want to execute after gtkpod has written the
+changes to the iPod. One major candidate will probably be 
+
+sudo eject $1
+
+gtkpod will not attempt to do any magic of it's own to
+mount/unmount/eject the iPod.
+
+
+
+Duplicate Detection
+-------------------
+
+You can instruct gtkpod (in the prefs window) to use
+file-size-dependent SHA1 checksums to prevent the same file from
+being copied to your iPod twice.
+
+If a duplicate is detected, gtkpod will print out the the filenames
+of the duplicate files. If the filename of the already existing file
+is not available (it is not stored in the iTunes database, see
+"Extended Information File" below), other available information of
+the track is printed.
+
+
+Extended Information File
+-------------------------
+
+Some (I believe) essential information is not stored in Apple's iTunes
+database. You can therefore instruct gtkpod to write an additional
+file (iTunesDB.ext) with extended information. For each track it stores
+
+  - SHA1 hash
+  - filename in the locale's encoding
+  - filename in UTF8 encoding
+  - hostname where the file was added (not used for anything yet)
+  - filename of an associated converted file (for example an .mp3 for
+    a .flac file)
+  - if the file is present in the local database a reference to there
+    in order for playcounts to work on the local database as well
+  - last modification time
+  - the charset used for the file when adding it
+
+Since the extended information file is only valid with the
+corresponding standard iTunes database, a checksum of the iTunes
+database is also stored in the extended information file.
+
+Using an extended information file will considerably speed up the
+import of an existing iTunes database when using duplicate detection,
+since the SHA1 checksums do not have to be re-calculated.
+
+Using an extended information file will also allow modification of ID3
+tags in the track files after the initial import, because the full
+filenames are still available.
+
+
+Refresh (Update) Track Info From File
+------------------------------------
+
+If you have changed the ID3 tags of your original file, you can update
+the ID3 tags stored in gtkpod without removing and re-adding the
+track. Simply select the track to be updated and press "Ctrl-u" or
+choose "Update Track Info From File" from the Edit menu. Since gtkpod
+needs to know the filename of the track, the "Extended Information
+File" (see above) is needed.
+
+"Update" will also re-read the replay-gain tags from disk, if
+available, and set the soundcheck field. If no replay-gain tag is
+available, the soundcheck field will be erased.
+
+You can also select entries in the filter tab or entire playlists for
+refresh.
+
+
+Synchronize with Directories
+----------------------------
+
+If you have added files to directories or changed files in directories
+you have previously added tracks from, you can use the "Synchronize
+Dirs" utility to update your iTunesDB.
+
+"Synchronize with Dir(s)" will use the selected tracks to make a list
+of directories to update, so you should activate the "Write Extended
+Information" option in the export section of the preferences dialogue.
+
+It will then add all non-existing tracks in those directories and
+update (see "Refresh") all existing tracks. The tracks are also added to
+the currently selected playlist, if they aren't already a member.
+
+Tracks that have been removed from the directory will only be removed
+from the iTunesDB if this option is checked in the option dialogue.
+
+For best results you should also activate duplicate detection. This
+avoids unnecessary copying of unchanged tracks.
+
+
+
+Volume Normalization
+--------------------
+
+There are two fields in the iTunesDB that allow to adjust the volume
+of an individual track: the volume field (a signed integer) and the
+soundcheck field (in dB). The volume is always active, whereas the
+soundcheck field is only active when you select 'soundcheck' on the
+iPod. Further, the soundcheck field only affects the earphone output
+but not the line output of the iPod.
+
+gtkpod will set the soundcheck according to the replay-gain tag set in
+your mp3 file. Newer versions of 'lame' automatically include the
+replay-gain tag when encoding. In that case the soundcheck field will
+be filled in when you first import a track.
+
+If no replay-gain tag is set, you can use the function 'Normalize
+Volume' to call mp3gain (mp3gain.sourceforge.net) to calculate the
+gain and write a replay-gain tag. Since this procedure is very time
+consuming, it is not done automatically during import. You need to
+install mp3gain in the default path or set the full path in the
+'Tools' section of the preferences dialog. If the iPod is connected,
+the tag is written to the file stored on the iPod.
+
+At this time "album gain" functionality is not supported. "Album gain"
+means that the volume of all tracks of one album is adjusted by the
+same gain, such that the relative volume level remains the same. It is
+planned to realize this in one of the next versions.
+
+Also, please be aware that tracks are not normalized on a 'per
+playlist' fashion. If a track is normalized, it's normalized in all
+playlists it is a member of.
+
+Once the replay-gain tag has been read, it is stored in the extended
+information file 'iTunesDB.ext'. When you call 'Normalize volume'
+again, the stored value will be used to re-populate the soundcheck
+field. Use 'Update Track' to re-read the tag from the file.
+
+
+Podcasts
+--------
+
+You have to download podcasts using a third party tool like bashpodder
+(http://linc.homeunix.org:8080/scripts/bashpodder/) or gpodder
+(http://perli.net/projekte/gpodder/)
+
+Podcasts should be added directly into the 'Podcasts' playlist of the
+iPod repository, for example by selecting the Podcasts playlist before
+manually adding files/directories. Podcasts will then appear only in
+the Podcasts section on the iPod.
+
+If you add podcasts to the main playlist 'gtkpod/iPod' or any other
+iPod playlist first and then drag them over to the Podcasts playlist,
+the podcasts will appear in the Podcasts section on the iPod, as well
+as in the normal music section.
+
+The podcast 'repository' is a local repository (like 'Local') where
+you can keep all local podcasts. No mechanism exists to automatically
+synchronize the iPod repository with the Podcast repository at this
+time. You have to drag the podcasts over manually.
+
+
+Export of Tracks (Copy from iPod)
+---------------------------------
+
+- mark the tracks you want to export and select "Export Tracks from
+  Database" from the file menu (or use the context sensitive menu)
+- A file selection dialog window appears and you can choose the directory
+  you'd like the selected files to be written to.
+- You can specify the output filename in the prefs dialog by
+  specifying a template (e.g. "%A/%a - %t"). You can specify multiple
+  templates for different file formats by separating them by a
+  semicolon (e.g. "%A/%a - %t.mp3;%t.wav"). See the tooltip in the
+  prefs dialog for a list of identifiers.
+
+
+Encoding of ID3 tags (charsets)
+-------------------------------
+If you use correctly written unicode ID3V2 tags you don't have to
+worry about the charset setting.
+
+Otherwise you must specify the charset to be used for representing ID3
+tags in the preferences menu. The default is "System Charset", which
+is the charset associated with the locale gtkpod is running under. If
+your tags are stored in a different encoding, you should set it
+appropriately.
+
+Please note that if necessary you can change the charset each time you
+add files or directories: the iTunesDB itself is using UTF16, so once
+tags are imported correctly, changing the charset has no influence.
+
+If you chose "Japanese (automatic detection)", gtkpod will try to
+determine if the string is in ISO-2022-JP, Shift_JIS, or EUC-JP
+(Hankaku Katakana (1-byte Katakana) may not be recognized correctly --
+specify the correct encoding if you run into this problem). The actual
+encoding used for the ID tags will be stored and will be used when
+writing tags or doing updates/syncs. Check the "Use selected charset
+also when updating or syncing tracks" and "Use selected charset when
+writing tags" options if you want to specify a particular character
+set when writing or updating/syncing. The default charset is "EUC-JP"
+-- it will be used when the charset cannot be autodetected, as well as
+when writing tags if a specific charset could not be determined
+before.
+
+gtkpod will recognize ID3V2 tags encoded in unicode automatically and
+ignore your charset setting when necessary.
+
+
+Extracting tag information from the filename
+--------------------------------------------
+Tags can also be extracted from the filename if you activate the
+option 'Use this template to parse filename for tag information' and
+supply a template that explains how the filenames are constructed.
+
+For filenames like 
+    music/new/latin1/alan_jackson - drive/01 drive_for_daddy_gene.mp3
+you could use
+    %a - %A/%T %*.mp3
+
+to extract artist, album, track number and title.
+
+The following character sequences are supported:
+
+    %t: title
+    %a: artist
+    %A: album
+    %c: composer
+    %t: title
+    %g: genre
+    %T: track number
+    %C: CD number
+    %*: placeholder, ignore data
+    %%: the character '%'
+
+You cannot supply a template like "%a%t.mp3" because gtkpod would not
+know how to separate artist and title. "%a_%t.mp3" would be correct,
+if artist and title are separated by an underscore.
+
+You can also omit the trailing ".mp3" if you want the template to
+apply to all files instead of only to mp3 files.
+
+
+Checking iPod's Files
+---------------------
+For whatever reason -- it may happen that tracks are present in your
+iTunesDB that are no longer present on the iPod (dangling tracks), or
+that tracks are on the iPod but not in the iTunesDB (orphaned
+tracks).
+
+The function "Checking iPod's Files" under the "File" menu will
+identify both types and take the following actions:
+
+Orphaned tracks:
+A new playlist "[Orphaned]" will be created with all orphaned tracks
+in it. The only exception are orphaned tracks that would become
+duplicates (if duplicate detection is activated). Those are marked for
+deletion with the next sync.
+
+Dangling tracks:
+These tracks will be marked for deletion with the next sync unless the
+original PC file is still available. In that case you can have them
+restored with the next sync.
+
+
+Restoring your iPod after file system error
+-------------------------------------------
+If iPod's file system gets corrupted and you need to reformat your
+iPod, there is a way to restore the contents semi-automatically if you
+have been using the "write extended information file" (iTunesDB.ext)
+options:
+
+ - If the directory structure on the iPod doesn't exist yet,
+   load the iPod in gtkpod and have it created for you. Then unload
+   the iPod again.
+
+ - copy your backup files in .gtkpod/ (usually iTunesDB and
+   iTunesDB.ext) to your iPod (usually
+   <mountpoint>/iPod_Control/iTunes/
+   On the iPod the files must be named iTunesDB and iTunesDB.ext.
+
+ - load the iPod in gtkpod
+
+ - select the iPod repository and start "Check iPod's files" from the
+   File menu
+
+ - unload the iPod (or save changes)
+
+This should restore your iPod to what it was before, provided you
+didn't move or remove any of the original tracks on your harddrive, and
+the charset information was stored correctly.
+
+
+Playcounts & Rating
+-------------------
+
+Whenever you play a track completely on the iPod (firmware version 1.3
+or higher) a counter in the "Play Counts" file will be increased by
+one. The same file also contains the rating you can set with the 3rd
+generation iPods.
+
+This file appears to be deleted whenever the iPod resets itself --
+e.g. because you disconnect it from the computer. Therefore, be
+careful... Charging the iPod seems to do no harm.
+
+When gtkpod is started, it will also read this file and incorporate
+the information into the iTunesDB that can be written back to the
+iPod.
+
+There have been several requests to also register playcounts when
+playing a track on the local machine. This is possible by calling
+gtkpod as "gtkpod -p <filename>".
+
+If gtkpod is already running, the playcount of that track there will
+be increased by one. If gtkpod is not already running, the playcount
+will be registered in ~/.gtkpod/offline_playcount. This file will be
+read the next time you import the iTunesDB from your iPod, and the
+playcounts will be updated accordingly.
+
+Please note that if you start several instances of gtkpod, only the
+first instance will register playcounts through "gtkpod -p".
+
+Now all you have to do is tell your favorite player to call gtkpod
+with the filename of the played track.
+
+For xmms this is possible as of July 18th, 2004 (CVS
+version). Versions before that (including 1.2.10) only allow you to
+have an external program called at the beginning of a track. Our patch
+allows to have an external program called also at the end of a track.
+
+In each case you will need to activate the "General Plugin" called
+"song_change" and configure it to call 'gtkpod -p "%f"'.
+
+
+About filenames (excerpt from the GTK2 release notes):
+------------------------------------------------------
+* The assumption of GLib and GTK+ by default is that filenames on the
+  filesystem are encoded in UTF-8 rather than the encoding of the locale;
+  The GTK+ developers consider that having filenames whose interpretation
+  depends on the current locale is fundamentally a bad idea.
+
+  If you have filenames encoded in the encoding of your locale, then
+  you may want to set the G_BROKEN_FILENAMES environment variable:
+  
+   G_BROKEN_FILENAMES=1
+   export G_BROKEN_FILENAMES
+
+  Best integration of GTK+-2.0 with the environment is achieved by 
+  using a UTF-8 locale.
+
+------ end of excerpt
+
+It is my feeling that many people use filenames encoded in the
+encoding of the locale. The "Add directories" dialogue already takes
+care of this and assumes the filenames to be in the same encoding as
+you have specified for the ID3 tags (see above). You can therefore
+forget about the excerpt above.
+
+However, the "Add Files" and "Add Playlists" dialogue (at the moment)
+uses the standard GTK+-2.0 file selection dialogue. Therefore I have
+no access on the conversion functions used, and a warning is printed
+when filenames are encountered that are encoded in an encoding other
+than the one of the current locale. ID3 tags are still read correctly
+(according to the charset set in the preference dialogue).
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Environment variables		           |
+|                                                  |
+*--------------------------------------------------*
+
+The following environment variables can be set if needed:
+
+IPOD_MOUNTPOINT: Defines the mountpoint of the iPod. This overwrites
+the value stored in the prefs, but is overwritten by the command line
+argument "-m" or "--mountpoint".
+
+GTKPOD_DF_COMMAND: Only used on systems without statvfs(). Defines the
+"df" command to be used for probing the free space on the iPod
+including command line arguments. Default is "df -k -P". On some
+systems it may be necessary to remove the "-P" option. The mount point
+is added to this command line automatically. You can switch off calls
+to df by setting this environment variable to an empty string.
+
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Icons for window managers		           |
+|                                                  |
+*--------------------------------------------------*
+
+Should you require an icon for your window manager you can use those
+provided in $(datadir)/pixmaps (usually
+/usr/local/share/gtkpod/pixmaps or
+/usr/share/gtkpod/pixmaps).
+
+Currently the following files are available:
+
+  gtkpod-icon-32.png
+  gtkpod-icon-32x32.png
+  gtkpod-icon-32x32-2.png
+  gtkpod-icon-48.png
+  gtkpod-icon-48x48.png
+  gtkpod-icon-64x64.png
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Connecting iPod to a Linux box	           |
+|  (kernel 2.6.6)                                  |
+|  (should also work with earlier 2.6 kernels)     |
+|                                                  |
+*--------------------------------------------------*
+
+This describes how to set up the iPod together with the automounter in
+kernel V2.6.6 (some minor changes in the kernel configuration may be
+necessary for older V2.6 versions).
+
+1) It appears to be possible to use HFS-formatted (Apple)
+   iPods. However, this short guide assumes you have a Windows
+   (VFAT) iPod. For conversion from HFS to VFAT please see 
+
+   http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
+
+2) I'm using the following kernel configuration options (I'm only
+   using FireWire -- so the USB options are just educated
+   guesses. Please let me know if it works).
+
+   I'm not using modules, simply because what's compiled in can't fail
+   loading.
+
+    * General Setup  -> Support for hot-pluggable devices - y
+    * Device Drivers -> SCSI device support - y
+    *                -> SCSI device support -> SCSI disk support - y
+    *                -> SCSI device support -> SCSI generic support - y
+For FireWire:
+    *                -> IEEE1394 (FireWire) support - y
+    *                -> IEEE1394 (FireWire) support -> OHCI-1394 support - y
+    *                -> IEEE1394 (FireWire) support -> SBP-2 support - y
+For USB:
+    *                -> USB support -> Support for Host-side USB - y
+    *                                       -> EHCI HCD support - y
+    *                                       -> OHCI HCD support - y
+    *                                       -> UHCI HCD support - y
+    *                                       -> USB Mass Storage support - y
+For USB and FireWire:
+    * Filesystems    -> DOS/FAT/NT Filesystems - y
+    *                -> DOS/FAT/NT Filesystems -> VFAT fs support - y
+    *                -> Kernel automounter version 4 support - y
+    *                -> Native Language Support
+    *                            -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
+    *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
+
+
+
+(for iPods formatted with the HFS filesystem choose
+    * Filesystems -> Miscellaneous filesystems
+			   -> Apple Extended HFS filesystem support)
+
+At least for the new 4Gs and iPod minis you should _disable_
+(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
+    * File Systems -> Partition Types -> Advanced Partition Selection
+		   -> EFI GUID Partition support
+
+3) You need to install the following external packages:
+
+   hotplug and udev (http://linux-hotplug.sourceforge.net/)
+   autofs (ftp.kernel.org:/pub/linux/daemons/autofs)
+
+   Most likely packages are available for your distribution.
+
+4) Write rules for udev (/etc/udev/udev.rules, add at the beginning)
+   to recognize your iPod automatically (mind the spaces within
+   "iPod...", and be aware that some distributions require a double
+   equal after the BUS keyword (BUS=="scsi"...)):
+
+BUS="scsi", SYSFS{model}="iPod            ", KERNEL="sd?2", NAME="%k", SYMLINK="ipod"
+
+   This will map /dev/sd?2 to /dev/ipod everytime you plug in your
+   iPod. That even works if you own more than one USB/Firewire device
+   that shows up as a harddisk, independent of the order in which you
+   connect the devices.
+
+   (You need to replace "sd?2" with "sd?1" (or maybe just "sd?") for
+   HFS formatted iPods.)
+
+   For more information on how to write udev rules please refer to
+   http://www.gamingclones.com/Howtos/udevrules.html. That document
+   gives an easy-to-understand introduction
+
+5) Set up autofs to automatically mount the iPod when you access it
+   and unmount it after 2 seconds of inactivity. In /etc/auto.master
+   add:
+
+/var/autofs/removable   /etc/auto.removable     --timeout=2,sync,nodev,nosuid,gid=autofs,umask=007
+
+   Adjust the gid,umask (and uid) values to whatever you need -- in this
+   example all users in the group "autofs" have read/write access, and
+   I have added all users that may access the iPod to the autofs group.
+
+   In /etc/auto.removable add
+
+ipod            -fstype=vfat            :/dev/ipod
+
+   (Obviously you need to change the filesystem type from 'vfat' to
+   'hfsplus' when you use an HFS formatted iPod.)
+
+   Then simply add a link from /mnt/ipod:
+
+   ln -s /var/autofs/removable/ipod /mnt/ipod
+
+
+Now your system is configured to mount the iPod every time you access
+/mnt/ipod and to unmount it again after two seconds of inactivity. You
+won't have to worry about doing mounting/unmouting yourself any more.
+
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Connecting iPod to a Linux box (IEEE 1394)      |
+|  (kernel 2.4.21)                                 |
+|  (may also work with 2.4.20, but I didn't try)   |
+|  (instructions for 2.4.20 can be found below)    |
+|                                                  |
+*--------------------------------------------------*
+
+1) You need a Windows iPod. See e.g.
+
+http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
+
+for information about how to convert your mac iPod to a windows iPod.
+
+Alternatively, I have received a report that Alan Cox's patches
+(2.4.21-rc8-ac1, but 2.4.21-ac1 should work as well) include hfsplus
+support. That should allow you to use hfs formatted iPods. But beware:
+hfsplus support is still beta.
+
+2) Get kernel source and configure
+Needed configuration:
+
+    * Code maturity level options - y
+    * SCSI support - y
+    * SCSI disk support - y
+    * IEEE1394 (FireWire)/IEEE 1394 (FireWire) support (Experimental) - y
+    * OHCI-1394 support - y
+    * SBP-2 support - m (important to use module -- if someone finds
+      out how to use hotplug with sbp2 compiled in, let me know)
+      (With 2.6.1 compiling sbp2 in seems to work fine.)
+At least for the new 4Gs and iPod minis you should _disable_
+(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
+    * File Systems -> Partition Types -> Advanced Partition Selection
+		   -> EFI GUID Partition support
+    *              -> Native Language Support
+    *                            -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
+    *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
+
+
+3) Create /mnt/ipod:
+
+   mkdir /mnt/ipod
+
+4) Add a line to /etc/fstab. You should edit uid to match your user
+   id. Also, /dev/sda2 may not be appropriate, if you have other scsi
+   devices.
+
+/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
+
+   (For HFS this line should read
+
+/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
+
+    please note that it's just '/dev/sda')
+
+
+NOTE: Some users have had problems with newer versions of mount(newer than
+mount-2.11h) The following fstab entry might work better for you.
+
+/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
+
+5) Install the hotplug utilities
+   (http://linux-hotplug.sourceforge.net/, debian package: 'hotplug')
+
+   (If you don't want to use the hotplug utilities, you must call the
+   rescan-scsi-bus.sh (see below) by hand after loading the sbp2
+   module. This is different from 2.4.20.)
+
+5a) Add the ieee1394 hotplug support (described at
+    http://www.linux1394.org/faq.html#hotplug):
+
+   - copy ieee1394.agent to /etc/hotplug/ from
+     http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/linux-hotplug/admin/etc/hotplug/
+   - mkdir /etc/hotplug/ieee1394
+   - create /etc/hotplug/ieee1394/sbp2:
+       #!/bin/bash
+       if [ "${ACTION}" = "add" ]; then
+	 . /etc/hotplug/ieee1394/rescan-scsi-bus.sh
+       else
+	 . /etc/hotplug/ieee1394/rescan-scsi-bus.sh -r
+       fi
+   - chmod +rx /etc/hotplug/ieee1394/sbp2
+   - copy rescan-scsi-bus.sh to /etc/hotplug/ieee1394 from
+     http://www.garloff.de/kurt/linux/rescan-scsi-bus.sh
+   - just to be sure: restart hotplug:
+	/etc/init.d/hotplug restart
+
+6) Connect your iPod to your computer and wait until you see something
+   like the following on your system log (you can use the 'dmesg'
+   command to check).
+
+Jun 15 17:13:53 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
+Jun 15 17:13:55 hatarakibachi kernel: ieee1394: Node 01:1023 changed to 00:1023
+Jun 15 17:13:57 hatarakibachi kernel: ieee1394: sbp2: Logged into SBP-2 device
+Jun 15 17:13:57 hatarakibachi kernel: ieee1394: Device added: Node[00:1023]  GUID[000a2700020680b5]  [Apple Computer, Inc.]
+Jun 15 17:13:57 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
+Jun 15 17:13:57 hatarakibachi kernel: scsi singledevice 0 0 0 0
+Jun 15 17:13:57 hatarakibachi kernel:   Vendor: Apple     Model: iPod              Rev: 1.30
+Jun 15 17:13:57 hatarakibachi kernel:   Type:   Direct-Access                      ANSI SCSI revision: 02
+Jun 15 17:13:57 hatarakibachi kernel: Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0
+Jun 15 17:13:57 hatarakibachi kernel: SCSI device sda: 39062520 512-byte hdwr sectors (20000 MB)
+Jun 15 17:13:57 hatarakibachi kernel: sda: test WP failed, assume Write Enabled
+Jun 15 17:13:58 hatarakibachi kernel:  sda: sda1 sda2
+Jun 15 17:13:58 hatarakibachi kernel: scsi singledevice 0 0 1 0
+...
+
+7) Mount the iPod hard drive
+
+   mount /mnt/ipod
+
+8) do whatever you need to do (e.g. start gtkpod, see below)
+
+9) Unmount the iPod:
+
+    umount /mnt/ipod
+
+10) Unload the module sbp2 (as most likely as root):
+
+    rmmod sbp2
+
+11) Disconnect the iPod from your computer (ignore the "Do not
+    disconnect" message -- as long as you wait for the 'unmount' to
+    command to finish properly, everything should be fine).
+
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Connecting iPod to a Linux box using IEEE 1394  |
+|  (kernel 2.4.20)                                 |
+|  (connecting to 2.4.21 seems to work slightly    |
+|   differently -- see above)                      |
+|                                                  |
+*--------------------------------------------------*
+
+1) You need a Windows iPod. See e.g.
+
+http://www.blinkenlights.ch/gnupod/gnupod.html#SEC6
+
+for information about how to convert your mac iPod to a windows iPod.
+
+Alternatively, I have received a report that Alan Cox's patches
+(2.4.21-rc8-ac1, but 2.4.21-ac1 should work as well) include hfsplus
+support. That should allow you to use hfs formatted iPods. But beware:
+hfsplus support is still beta.
+
+2) Get kernel source and configure
+Needed configuration:
+
+    * Code maturity level options - y
+    * SCSI support - y
+    * SCSI disk support - m
+    * IEEE1394 (FireWire)/IEEE 1394 (FireWire) support (Experimental) - y
+    * OHCI-1394 support - y
+    * SBP-2 support - m
+At least for the new 4Gs and iPod minis you should _disable_
+(CONFIG_EFI_PARTITION, see Troubleshooting for more information):
+    * File Systems -> Partition Types -> Advanced Partition Selection
+    *	   	   -> EFI GUID Partition support
+    *              -> Native Language Support
+    *                          -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
+    *                          -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
+
+3) Create /mnt/ipod:
+
+   mkdir /mnt/ipod
+
+4) Add a line to /etc/fstab. You should edit uid to match your user
+   id. Also, /dev/sda2 may not be appropriate, if you have other scsi
+   devices.
+
+/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime 0 0
+
+   (For HFS this line should read
+
+/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
+
+    please note that it's just '/dev/sda')
+
+
+NOTE: Some users have had problems with newer versions of mount(newer than
+mount-2.11h) The following fstab entry might work better for you.
+
+/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
+
+NOTE: You can add ",umask=0" to the options to make the iPod
+readable/writable for all users.
+
+5) Connect your iPod to your computer and wait until you see something
+   like the following on your system log (you can use the 'dmesg'
+   command to check).
+
+Nov 28 21:58:06 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
+Nov 28 21:58:09 hatarakibachi kernel: ieee1394: Node 01:1023 changed to 00:1023
+Nov 28 21:58:12 hatarakibachi kernel: ieee1394: NodeMgr: hotplug policy returned -2
+Nov 28 21:58:12 hatarakibachi kernel: ieee1394: Device added: Node[00:1023]  GUID[000a2700020680b5]  [Apple Computer, Inc.]
+Nov 28 21:58:12 hatarakibachi kernel: ieee1394: Node 00:1023 changed to 01:1023
+
+6) Load the sbp2 module (most likely as root):
+
+   modprobe sbp2
+
+   You should see something like the following on your system log:
+
+Nov 28 21:58:38 hatarakibachi kernel: ieee1394: sbp2: Logged into SBP-2 device
+Nov 28 21:58:38 hatarakibachi kernel: scsi0 : IEEE-1394 SBP-2 protocol driver (host: ohci1394)
+Nov 28 21:58:38 hatarakibachi kernel: $Rev$ James Goodwin <jamesg at filanet.com>
+Nov 28 21:58:38 hatarakibachi kernel: SBP-2 module load options:
+Nov 28 21:58:38 hatarakibachi kernel: - Max speed supported: S400
+Nov 28 21:58:38 hatarakibachi kernel: - Max sectors per I/O supported: 255
+Nov 28 21:58:38 hatarakibachi kernel: - Max outstanding commands supported: 8
+Nov 28 21:58:38 hatarakibachi kernel: - Max outstanding commands per lun supported: 1
+Nov 28 21:58:38 hatarakibachi kernel: - Serialized I/O (debug): no
+Nov 28 21:58:38 hatarakibachi kernel: - Exclusive login: yes
+Nov 28 21:58:38 hatarakibachi kernel:   Vendor: Apple     Model: iPod              Rev: 1.21
+Nov 28 21:58:38 hatarakibachi kernel:   Type:   Direct-Access                      ANSI SCSI revision: 02
+Nov 28 21:58:38 hatarakibachi kernel: Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0
+Nov 28 21:58:38 hatarakibachi kernel: SCSI device sda: 39062520 512-byte hdwr sectors (20000 MB)
+Nov 28 21:58:38 hatarakibachi kernel: sda: test WP failed, assume Write Enabled
+Nov 28 21:58:39 hatarakibachi kernel:  sda: sda1 sda2
+
+7) Mount the iPod hard drive
+
+   mount /mnt/ipod
+
+8) do whatever you need to do (e.g. start gtkpod, see below)
+
+9) Unmount the iPod:
+
+    umount /mnt/ipod
+
+10) Unload the module sbp2 (as most likely as root):
+
+    rmmod sbp2
+
+11) Disconnect the iPod from your computer.
+
+
+*--------------------------------------------------*
+|                                                  |
+|  Connecting iPod to a Linux box (USB)            |
+|                                                  |
+*--------------------------------------------------*
+
+I don't have much information about this so far (I don't own a third
+generation iPod). Please help me to fill in the gaps.
+
+Stephen Drye sent me the following note:
+
+"I've figured out how to get a USB-connected iPod recognized...:
+
+The trick to it is that you have to 
+
+- plug the iPod in
+
+- it'll fail to be recognized by the SCSI subsystem
+
+- now, even though your ipod says not to, unplug the USB cord and
+  immediately plug it back in.
+
+- since the iPod's hdd was already spun up, the SCSI subsystem now
+  recognizes it and mounts it as /dev/sda
+
+- You can then mount /dev/sda2 to /mnt/ipod as normal."
+
+On the other hand: with my 4G iPod under 2.6.9 and 2.6.10 I never had
+any problem whatsoever getting the iPod to work. With IEEE it was
+awful (would work some times, would not some other time).
+
+
+*----------------------------------*
+|                                  |
+|     Sick of loading the sbp2     |
+|         modules by hand?         |
+|                                  |
+|         Corey Donohoe            |
+|     <atmos at atmos dot org>     |
+|         March 22nd 2003          |
+|                                  |
+*----------------------------------*
+
+Sick of loading the sbp2 modules by hand every time you want to use your
+ipod?  Are you sick of mounting it too?  Using sudo gtkpod can make manually
+interacting with the ipod filesystem a thing of the past.  Note that you
+should have your ipod working with gtkpod before attempting this automated
+method, see the README that came with gtkpod in order to get things up and
+running.
+
+Here's a brief example of how I'm using gtkpod now in 8 easy steps.
+
+(Remark: the hotplug facility of new kernels can also load and unload
+the sbp2 module for you.)
+
+/**********/
+ * Step 1 *
+/**********/
+Using sudo allow users to load/remove the sbp2 module
+Example /etc/sudoers
+------------------------------- Begin Here ---------------------------------
+
+# Cmnd alias specification
+Cmnd_Alias IPOD=/sbin/modprobe sbp2 sbp2_force_inquiry_hack=1, /sbin/rmmod sbp2
+# User privilege specification
+atmos   ALL=(ALL) ALL
+atmos   ALL= NOPASSWD : IPOD
+
+------------------------------- End Here -----------------------------------
+I use the force inquiry hack cause I have an older iPod, if you normally can
+get by with /sbin/modprobe sbp2 then ignore the inquiry hack stuff.  Note
+that explicitly specifying which module to probe/remove keeps the user from
+being able to add/remove arbitrary modules.  This allows us to keep gtkpod
+as a user process, and execute commands the user wouldn't usually have
+enough rights to.
+
+/**********/
+ * Step 2 *
+/**********/
+Add a line similar to the below to your /etc/fstab, this will enable users
+to mount the ipod with read/write capabilities.  Example line assumes your
+ipod mount point is /mnt/ipod and your ipod is detected as /dev/sda
+
+------------------------------- Begin Here ---------------------------------
+/dev/sda2       /mnt/ipod       vfat    rw,user,noauto          0       0
+------------------------------- End Here -----------------------------------
+
+
+/**********/
+ * Step 3 *
+/**********/
+Then setup your /etc/gtkpod/gtkpod.in file to load the module when gtkpod is
+started.
+Example /etc/gtkpod/gtkpod.in
+------------------------------- Begin Here ---------------------------------
+
+sudo /sbin/modprobe sbp2 sbp2_force_inquiry_hack=1
+
+------------------------------- End Here -----------------------------------
+
+/**********/
+ * Step 4 *
+/**********/
+
+Then setup your /etc/gtkpod/gtkpod.out file to unload the module when gtkpod
+is exited.
+Example /etc/gtkpod/gtkpod.out
+------------------------------- Begin Here ---------------------------------
+
+sudo /sbin/rmmod sbp2 
+
+------------------------------- End Here -----------------------------------
+
+/**********/
+ * Step 5 *
+/**********/
+Then enable ipod automounting in the gtkpod prefs(in the misc tab).
+
+/**********/
+ * Step 6 *
+/**********/
+You're now ready to use gtkpod in a much nicer fashion.  Start by
+plugging in your ipod.  You should get a check mark with "OK to disconnect"
+displayed on your ipod.
+
+/**********/
+ * Step 7 *
+/**********/
+Start gtkpod, your ipod should be accessible(i.e. autoimport should work)
+A "Do Not Disconnect" message is displayed on your ipod while gtkpod is
+running.
+
+/**********/
+ * Step 8 *
+/**********/
+After you exit gtkpod, the "OK to disconnect" message should be displayed
+again.  It's ok to unplug your ipod now.  
+
+Good Luck. 
+
+
+
+*----------------------------------*
+|                                  |
+|           Known bugs             |
+|                                  |
+*----------------------------------*
+
+
+- Display of large number of tracks is awfully slow (mainly because of
+  the use of the standard GTK2 tree views) -> deactivate "Automatically
+  select "All" in first filter tab" and/or deactivate "Automatically
+  select master playlist". You could also "block the display" to speed
+  up the display update. Further, decreasing the window size
+  considerably speeds up the display.
+
+  I also want to point out that updating the info window takes up a
+  considerable amount of time. Update may become more intelligent in
+  the future -- until then close the info window for more speed.
+
+- When changing selections in the filter tabs while importing the
+  iTunesDB, sometimes the interface freezes. I tried to track this
+  problem down but only found out that gtk+ does not return control
+  back to gtkpod. Selecting the "All" filter tabs seems to unfreeze the
+  interface again.

Deleted: gtkpod/tags/0.99.10-5/debian/NEWS
===================================================================
--- gtkpod/trunk/debian/NEWS	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/debian/NEWS	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,9 +0,0 @@
-gtkpod (0.85.0-1) unstable; urgency=low
-
-  * I have changed the default configuration of gtkpod to
-    use the mount point /media/ipod instead of /mnt/ipod.
-    You may have to change either your gtkpod configuration
-    or your /etc/fstab to get gtkpod working correctly again.
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 10 Dec 2004 02:04:02 +0100
-

Deleted: gtkpod/tags/0.99.10-5/debian/changelog
===================================================================
--- gtkpod/trunk/debian/changelog	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/debian/changelog	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,213 +0,0 @@
-gtkpod (0.99.10-3) unstable; urgency=low
-
-  * Added missing fclose() call in mp3file.c to prevent too many open
-    file descriptors (Closes: #441308).
-  * Adapted .desktop file to current freedesktop standards.
-
- -- Nico Golde <nion at debian.org>  Sun, 09 Sep 2007 20:13:31 +0200
-
-gtkpod (0.99.10-2) unstable; urgency=low
-
-  * Upload to unstable
-  * Update menu entry according to new menu policy
-  * Lintian: Don't ignore all errors from "make distclean"
-
- -- Frank Lichtenheld <djpig at debian.org>  Tue, 10 Jul 2007 00:25:04 +0200
-
-gtkpod (0.99.10-1) experimental; urgency=low
-
-  * New upstream release
-    - Allows resizing the preferences dialog (Closes: #428011)
-  * Update man page debian/gtkpod.pod
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 28 Jun 2007 02:12:56 +0200
-
-gtkpod (0.99.8-3) unstable; urgency=low
-
-  [ Frank Lichtenheld ]
-  * Upload to unstable (Closes: #391812)
-  * Change Maintainer to pkg-gtkpod-devel list. Add myself
-    and Nico as Uploaders
-  * Add Vcs-{Svn,Browser} fields
-
-  [ Nico Golde ]
-  * Added Homepage tag to control.
-  * Bumped compat level since debhelper >= 5 is in etch.
-
- -- Nico Golde <nion at debian.org>  Mon, 07 May 2007 17:40:39 +0200
-
-gtkpod (0.99.8-2) experimental; urgency=low
-
-  * Adapt for libgpod >= 0.4.2 (Patch by upstream).
-
- -- Frank Lichtenheld <djpig at debian.org>  Sat, 10 Feb 2007 14:22:53 +0100
-
-gtkpod (0.99.8-1) experimental; urgency=low
-
-  * New upstream release
-    + Update libgpod-dev build-dependency to (>= 0.4.0)
-      and remove conflict against libgpod0
-      (upload to experimental because this version isn't
-       available in unstable yet)
-    + Change /mnt/ipod to /media/ipod as usual in new scripts
-  * Bump Standards-Version to 3.7.2 (no changes).
-  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
-    (Closes: #395120)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Dec 2006 18:38:05 +0100
-
-gtkpod (0.99.4-2) unstable; urgency=low
-
-  * Add conflict against libgpod0 >= 0.4.0
-    to quiten up the BTS a bit.
-  * Bump Standards-Version to 3.7.2 (no changes).
-  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
-    (Closes: #395120)
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 30 Nov 2006 23:12:32 +0100
-
-gtkpod (0.99.4-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Frank Lichtenheld <djpig at debian.org>  Sat,  8 Apr 2006 21:45:22 +0200
-
-gtkpod (0.99.2-1) unstable; urgency=low
-
-  * New upstream release (Closes: #343856)
-    + Fixes sorting bug (Closes: #330082)
-  * Add build-depends on libgpod-dev
-  * Add build-depends on flex
-  * Add suggests on python since one of the scripts uses it
-  * Update FSF address in debian/copyright
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 29 Dec 2005 17:38:38 +0100
-
-gtkpod (0.94.0-1) unstable; urgency=low
-
-  * New upstream release (Closes: #319408)
-    - support for new iTunes and new firmware version
-      (Closes: #317701)
-  * Add watch file, by  Filippo Giunchedi (Closes: #318760)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Jul 2005 13:23:13 +0200
-
-gtkpod (0.93.1-1) unstable; urgency=low
-
-  * New upstream release (Closes: #316399)
-    - New build-dependency libglade2-dev
-  * Bump Standards-Version to 3.6.2, no changes needed
-  * Don't create glade files as absolute links as that fails miserably
-    in a packaging situation
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  1 Jul 2005 02:24:13 +0200
-
-gtkpod (0.88.2-1) unstable; urgency=low
-
-  * New upstream release
-    - Fixes typo in preferences dialog reported by Michael Shields
-      (Closes: #289087)
-    - Included additional sync script previously offered for
-      download separatly (Closes: #302361)
-  * Include typo fixes for the German translation by Jens Seidel
-    (Closes: #314053)
-  * Add build dependency on gettext even though many other build
-    dependecies already get it for us. We shouldn't rely on that
-  * Fix syntax error in sync-notes.sh and change paths from
-    /mnt/ipod to /media/ipod as usual
-  * Add Suggests on recode as it is used in the scripts
-  * Replace the outdated, buggy, and GFDL licensed man page written in
-    docbook by the former Debian maintainer with an updated, more
-    extensive, GPL licensed version written in POD by me. Replace
-    build-depends on docbook-to-man by build-depends on perl.
-  * Rework copyright file to be more precise about which file is
-    copyrighted by whom
-  * Fix path to scripts in preferences window
-  * Replace ScsiEject code in src/misc.c with my new version from the
-    eject package which uses the newer SG ioctl interface. Add new
-    header check for scsi/sg.h to configure.in and regenerate configure
-    and config.h.in.
-  
- -- Frank Lichtenheld <djpig at debian.org>  Thu, 16 Jun 2005 18:28:41 +0200
-
-gtkpod (0.88.1-1) unstable; urgency=low
-
-  * New upstream release
-    - fixes the iPod Shuffle support (Closes: #299768)
-      Thanks to Jörg Kurlbaum for pointing this out 
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 18 Mar 2005 13:15:17 +0100
-
-gtkpod (0.88-1) unstable; urgency=low
-
-  * New upstream version (Closes: #299053)
-  * Fix FTBFS with gcc-4.0; patch by Andreas Jochens
-    (Closes: #298273)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri, 11 Mar 2005 18:50:52 +0100
-
-gtkpod (0.87.3-1) unstable; urgency=low
-
-  * New upstream version
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  4 Mar 2005 14:35:13 -0800
-
-gtkpod (0.85.0-1) unstable; urgency=low
-
-  * New maintainer (Closes: #287988)
-    Acknowledge my own NMU (Closes: #264682, #268340, #230898, #275363)
-  * Apply patch by Andreas Jochens to let gtkpod compile
-    with gcc-4.0 (Closes: #286926)
-
- -- Frank Lichtenheld <djpig at debian.org>  Fri,  7 Jan 2005 01:01:58 +0100
-
-gtkpod (0.85.0-0.1) unstable; urgency=low
-
-  * NMU since maintainer is unresponsive to any contact
-    attempts for a log time now.
-  * New upstream release (Closes: #264682)
-  * debian/control:
-    + Shorten short description (Closes: #268340)
-    + Suggest mp3gain (Closes: #230898)
-    + Adjust debhelper build-dependency so that we can use dh_desktop
-  * debian/rules: Tidy up.
-  * debian/docs: Don't install empty NEWS file
-  * debian/menu:
-    + Quote values
-    + Use xpm icon created from the 32x32 icon
-  * debian/gtkpod.sgml: fix some <arg> vs. <option> mistakes
-  * debian/gtkpod.desktop: add .desktop file
-  * Change all occourences of /mnt/ipod to /media/ipod (Closes: #275363)
-    add a NEWS.Debian file to document this.
-  * Fix UTF-8 characters in several files
-  * Don't issue warning about not beeing able to "unsort" a table.
-    It's quite annyoing and the user has no possibility to fix it.
-
- -- Frank Lichtenheld <djpig at debian.org>  Thu,  9 Dec 2004 18:17:17 +0100
-
-gtkpod (0.72-2-2) unstable; urgency=low
-
-  * Fix build dependencies (libid3tag0-dev).
-  * Change priority to extra.
-
- -- Quôc Peyrot <chojin at debian.org>  Sat,  7 Feb 2004 05:14:03 +0000
-
-gtkpod (0.72-2-1) unstable; urgency=low
-
-  * New upstream release. Closes: #216155.
-  * Update policy revision to 3.6.1 (use UTF-8).
-  * Change the debian maintainer email to chojin at debian.org.
-
- -- Quôc Peyrot <chojin at debian.org>  Tue,  3 Feb 2004 07:15:04 +0000
-
-gtkpod (0.51-1) unstable; urgency=low
-
-  * New upstream release
-
- -- Quôc Peyrot <chojin at debian.org>  Sat, 17 May 2003 04:15:02 +0000
-
-gtkpod (0.50-1) unstable; urgency=low
-
-  * Initial Release. Closes: #182289.
-
- -- Quôc Peyrot <chojin at debian.org>  Tue, 22 Apr 2003 05:16:37 +0000

Copied: gtkpod/tags/0.99.10-5/debian/changelog (from rev 279, gtkpod/trunk/debian/changelog)
===================================================================
--- gtkpod/tags/0.99.10-5/debian/changelog	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/debian/changelog	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,234 @@
+gtkpod (0.99.10-5) unstable; urgency=low
+
+  * Add changing mountpoint as well in prefs.c
+    to 01_mountpoint (Closes: #452056).
+  * Removed NEWS file as its last entry was before sarge.
+
+ -- Nico Golde <nion at debian.org>  Tue, 20 Nov 2007 14:22:12 +0100
+
+gtkpod (0.99.10-4) unstable; urgency=low
+
+  * Switched from Xs-Vcs to Vcs control field, dpkg supports them now.
+  * Switched from old Homepage tag to the new Homepage control field.
+  * New dependency on dpatch as we don't want to modify the source
+    directly any longer.
+  * Added previously modified source code as dpatch patches:
+    01_mountpoint, 02_missing_fclose
+  * Included 03_itdb-set-local-to-imported.dpatch to fix inability to import
+    into local repos (Closes: #451749).
+
+ -- Nico Golde <nion at debian.org>  Tue, 13 Nov 2007 16:18:58 +0100
+
+gtkpod (0.99.10-3) unstable; urgency=low
+
+  * Added missing fclose() call in mp3file.c to prevent too many open
+    file descriptors (Closes: #441308).
+  * Adapted .desktop file to current freedesktop standards.
+
+ -- Nico Golde <nion at debian.org>  Sun, 09 Sep 2007 20:13:31 +0200
+
+gtkpod (0.99.10-2) unstable; urgency=low
+
+  * Upload to unstable
+  * Update menu entry according to new menu policy
+  * Lintian: Don't ignore all errors from "make distclean"
+
+ -- Frank Lichtenheld <djpig at debian.org>  Tue, 10 Jul 2007 00:25:04 +0200
+
+gtkpod (0.99.10-1) experimental; urgency=low
+
+  * New upstream release
+    - Allows resizing the preferences dialog (Closes: #428011)
+  * Update man page debian/gtkpod.pod
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 28 Jun 2007 02:12:56 +0200
+
+gtkpod (0.99.8-3) unstable; urgency=low
+
+  [ Frank Lichtenheld ]
+  * Upload to unstable (Closes: #391812)
+  * Change Maintainer to pkg-gtkpod-devel list. Add myself
+    and Nico as Uploaders
+  * Add Vcs-{Svn,Browser} fields
+
+  [ Nico Golde ]
+  * Added Homepage tag to control.
+  * Bumped compat level since debhelper >= 5 is in etch.
+
+ -- Nico Golde <nion at debian.org>  Mon, 07 May 2007 17:40:39 +0200
+
+gtkpod (0.99.8-2) experimental; urgency=low
+
+  * Adapt for libgpod >= 0.4.2 (Patch by upstream).
+
+ -- Frank Lichtenheld <djpig at debian.org>  Sat, 10 Feb 2007 14:22:53 +0100
+
+gtkpod (0.99.8-1) experimental; urgency=low
+
+  * New upstream release
+    + Update libgpod-dev build-dependency to (>= 0.4.0)
+      and remove conflict against libgpod0
+      (upload to experimental because this version isn't
+       available in unstable yet)
+    + Change /mnt/ipod to /media/ipod as usual in new scripts
+  * Bump Standards-Version to 3.7.2 (no changes).
+  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
+    (Closes: #395120)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Dec 2006 18:38:05 +0100
+
+gtkpod (0.99.4-2) unstable; urgency=low
+
+  * Add conflict against libgpod0 >= 0.4.0
+    to quiten up the BTS a bit.
+  * Bump Standards-Version to 3.7.2 (no changes).
+  * Remove glade file symlinks on clean. Found by Martin Zobel-Helas.
+    (Closes: #395120)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 30 Nov 2006 23:12:32 +0100
+
+gtkpod (0.99.4-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Frank Lichtenheld <djpig at debian.org>  Sat,  8 Apr 2006 21:45:22 +0200
+
+gtkpod (0.99.2-1) unstable; urgency=low
+
+  * New upstream release (Closes: #343856)
+    + Fixes sorting bug (Closes: #330082)
+  * Add build-depends on libgpod-dev
+  * Add build-depends on flex
+  * Add suggests on python since one of the scripts uses it
+  * Update FSF address in debian/copyright
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 29 Dec 2005 17:38:38 +0100
+
+gtkpod (0.94.0-1) unstable; urgency=low
+
+  * New upstream release (Closes: #319408)
+    - support for new iTunes and new firmware version
+      (Closes: #317701)
+  * Add watch file, by  Filippo Giunchedi (Closes: #318760)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 22 Jul 2005 13:23:13 +0200
+
+gtkpod (0.93.1-1) unstable; urgency=low
+
+  * New upstream release (Closes: #316399)
+    - New build-dependency libglade2-dev
+  * Bump Standards-Version to 3.6.2, no changes needed
+  * Don't create glade files as absolute links as that fails miserably
+    in a packaging situation
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  1 Jul 2005 02:24:13 +0200
+
+gtkpod (0.88.2-1) unstable; urgency=low
+
+  * New upstream release
+    - Fixes typo in preferences dialog reported by Michael Shields
+      (Closes: #289087)
+    - Included additional sync script previously offered for
+      download separatly (Closes: #302361)
+  * Include typo fixes for the German translation by Jens Seidel
+    (Closes: #314053)
+  * Add build dependency on gettext even though many other build
+    dependecies already get it for us. We shouldn't rely on that
+  * Fix syntax error in sync-notes.sh and change paths from
+    /mnt/ipod to /media/ipod as usual
+  * Add Suggests on recode as it is used in the scripts
+  * Replace the outdated, buggy, and GFDL licensed man page written in
+    docbook by the former Debian maintainer with an updated, more
+    extensive, GPL licensed version written in POD by me. Replace
+    build-depends on docbook-to-man by build-depends on perl.
+  * Rework copyright file to be more precise about which file is
+    copyrighted by whom
+  * Fix path to scripts in preferences window
+  * Replace ScsiEject code in src/misc.c with my new version from the
+    eject package which uses the newer SG ioctl interface. Add new
+    header check for scsi/sg.h to configure.in and regenerate configure
+    and config.h.in.
+  
+ -- Frank Lichtenheld <djpig at debian.org>  Thu, 16 Jun 2005 18:28:41 +0200
+
+gtkpod (0.88.1-1) unstable; urgency=low
+
+  * New upstream release
+    - fixes the iPod Shuffle support (Closes: #299768)
+      Thanks to Jörg Kurlbaum for pointing this out 
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 18 Mar 2005 13:15:17 +0100
+
+gtkpod (0.88-1) unstable; urgency=low
+
+  * New upstream version (Closes: #299053)
+  * Fix FTBFS with gcc-4.0; patch by Andreas Jochens
+    (Closes: #298273)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri, 11 Mar 2005 18:50:52 +0100
+
+gtkpod (0.87.3-1) unstable; urgency=low
+
+  * New upstream version
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  4 Mar 2005 14:35:13 -0800
+
+gtkpod (0.85.0-1) unstable; urgency=low
+
+  * New maintainer (Closes: #287988)
+    Acknowledge my own NMU (Closes: #264682, #268340, #230898, #275363)
+  * Apply patch by Andreas Jochens to let gtkpod compile
+    with gcc-4.0 (Closes: #286926)
+
+ -- Frank Lichtenheld <djpig at debian.org>  Fri,  7 Jan 2005 01:01:58 +0100
+
+gtkpod (0.85.0-0.1) unstable; urgency=low
+
+  * NMU since maintainer is unresponsive to any contact
+    attempts for a log time now.
+  * New upstream release (Closes: #264682)
+  * debian/control:
+    + Shorten short description (Closes: #268340)
+    + Suggest mp3gain (Closes: #230898)
+    + Adjust debhelper build-dependency so that we can use dh_desktop
+  * debian/rules: Tidy up.
+  * debian/docs: Don't install empty NEWS file
+  * debian/menu:
+    + Quote values
+    + Use xpm icon created from the 32x32 icon
+  * debian/gtkpod.sgml: fix some <arg> vs. <option> mistakes
+  * debian/gtkpod.desktop: add .desktop file
+  * Change all occourences of /mnt/ipod to /media/ipod (Closes: #275363)
+    add a NEWS.Debian file to document this.
+  * Fix UTF-8 characters in several files
+  * Don't issue warning about not beeing able to "unsort" a table.
+    It's quite annyoing and the user has no possibility to fix it.
+
+ -- Frank Lichtenheld <djpig at debian.org>  Thu,  9 Dec 2004 18:17:17 +0100
+
+gtkpod (0.72-2-2) unstable; urgency=low
+
+  * Fix build dependencies (libid3tag0-dev).
+  * Change priority to extra.
+
+ -- Quôc Peyrot <chojin at debian.org>  Sat,  7 Feb 2004 05:14:03 +0000
+
+gtkpod (0.72-2-1) unstable; urgency=low
+
+  * New upstream release. Closes: #216155.
+  * Update policy revision to 3.6.1 (use UTF-8).
+  * Change the debian maintainer email to chojin at debian.org.
+
+ -- Quôc Peyrot <chojin at debian.org>  Tue,  3 Feb 2004 07:15:04 +0000
+
+gtkpod (0.51-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Quôc Peyrot <chojin at debian.org>  Sat, 17 May 2003 04:15:02 +0000
+
+gtkpod (0.50-1) unstable; urgency=low
+
+  * Initial Release. Closes: #182289.
+
+ -- Quôc Peyrot <chojin at debian.org>  Tue, 22 Apr 2003 05:16:37 +0000

Deleted: gtkpod/tags/0.99.10-5/debian/control
===================================================================
--- gtkpod/trunk/debian/control	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/debian/control	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,22 +0,0 @@
-Source: gtkpod
-Section: sound
-Priority: extra
-Maintainer: gtkpod Maintainers <pkg-gtkpod-devel at lists.alioth.debian.org>
-Uploaders: Frank Lichtenheld <djpig at debian.org>, Nico Golde <nion at debian.org>
-Build-Depends: debhelper (>= 5), gettext, flex, autotools-dev, perl, libxml-parser-perl, libgtk2.0-dev, libglade2-dev, libgnomecanvas2-dev, libgnomevfs2-dev, libid3tag0-dev, libvorbis-dev, libflac-dev, libgpod-dev (>= 0.5.2), libcurl4-gnutls-dev, libhal-dev
-Standards-Version: 3.7.2
-XS-Vcs-Svn: svn://svn.debian.org/svn/pkg-gtkpod/gtkpod/trunk
-XS-Vcs-Browser: http://svn.debian.org/wsvn/pkg-gtkpod/gtkpod/trunk
-
-Package: gtkpod
-Architecture: any
-Depends: ${shlibs:Depends}
-Suggests: mp3gain, recode, python
-Description: manage songs and playlists on an Apple iPod
- gtkpod is a platform independent GUI for Apple's iPod using GTK2. It
- allows you to upload songs and playlists to your iPod. It supports ID3
- tag editing, multiple charsets for ID3 tags, detects duplicate songs,
- allows offline modification of the database with later synchronisation,
- and more.
- .
-  Homepage: http://www.gtkpod.org

Copied: gtkpod/tags/0.99.10-5/debian/control (from rev 265, gtkpod/trunk/debian/control)
===================================================================
--- gtkpod/tags/0.99.10-5/debian/control	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/debian/control	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,21 @@
+Source: gtkpod
+Section: sound
+Priority: extra
+Maintainer: gtkpod Maintainers <pkg-gtkpod-devel at lists.alioth.debian.org>
+Uploaders: Frank Lichtenheld <djpig at debian.org>, Nico Golde <nion at debian.org>
+Build-Depends: debhelper (>= 5), gettext, flex, autotools-dev, perl, libxml-parser-perl, libgtk2.0-dev, libglade2-dev, libgnomecanvas2-dev, libgnomevfs2-dev, libid3tag0-dev, libvorbis-dev, libflac-dev, libgpod-dev (>= 0.5.2), libcurl4-gnutls-dev, libhal-dev, dpatch
+Standards-Version: 3.7.2
+Homepage: http://www.gtkpod.org
+Vcs-Svn: svn://svn.debian.org/svn/pkg-gtkpod/gtkpod/trunk
+Vcs-Browser: http://svn.debian.org/wsvn/pkg-gtkpod/gtkpod/trunk
+
+Package: gtkpod
+Architecture: any
+Depends: ${shlibs:Depends}
+Suggests: mp3gain, recode, python
+Description: manage songs and playlists on an Apple iPod
+ gtkpod is a platform independent GUI for Apple's iPod using GTK2. It
+ allows you to upload songs and playlists to your iPod. It supports ID3
+ tag editing, multiple charsets for ID3 tags, detects duplicate songs,
+ allows offline modification of the database with later synchronisation,
+ and more.

Copied: gtkpod/tags/0.99.10-5/debian/patches (from rev 274, gtkpod/trunk/debian/patches)

Deleted: gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch
===================================================================
--- gtkpod/trunk/debian/patches/01_mountpoint.dpatch	2007-11-19 17:26:24 UTC (rev 274)
+++ gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,276 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 01_mountpoint.dpatch by Nico Golde <nion at debian.org>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: No description.
-
- at DPATCH@
-diff -urNad trunk~/README trunk/README
---- trunk~/README	2007-11-18 16:47:22.000000000 +0100
-+++ trunk/README	2007-11-18 16:48:21.000000000 +0100
-@@ -52,7 +52,7 @@
- 1) If your iPod is not mounted automatically when connecting it to
-    your computer follow steps 1-7 in the "Connecting your iPod to a
-    Linux box" (basically you need to get the iPod partition mounted to
--   /mnt/ipod).  In most cases this should not be necessary any more
-+   /media/ipod).  In most cases this should not be necessary any more
-    these days.
- 
- 2) If you are using GNOME, starting with V1.0 of gtkpod your iPod will
-@@ -699,13 +699,13 @@
-    (Obviously you need to change the filesystem type from 'vfat' to
-    'hfsplus' when you use an HFS formatted iPod.)
- 
--   Then simply add a link from /mnt/ipod:
-+   Then simply add a link from /media/ipod:
- 
--   ln -s /var/autofs/removable/ipod /mnt/ipod
-+   ln -s /var/autofs/removable/ipod /media/ipod
- 
- 
- Now your system is configured to mount the iPod every time you access
--/mnt/ipod and to unmount it again after two seconds of inactivity. You
-+/media/ipod and to unmount it again after two seconds of inactivity. You
- won't have to worry about doing mounting/unmouting yourself any more.
- 
- 
-@@ -750,19 +750,19 @@
-     *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
- 
- 
--3) Create /mnt/ipod:
-+3) Create /media/ipod:
- 
--   mkdir /mnt/ipod
-+   mkdir /media/ipod
- 
- 4) Add a line to /etc/fstab. You should edit uid to match your user
-    id. Also, /dev/sda2 may not be appropriate, if you have other scsi
-    devices.
- 
--/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
-+/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
- 
-    (For HFS this line should read
- 
--/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
-+/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
- 
-     please note that it's just '/dev/sda')
- 
-@@ -770,7 +770,7 @@
- NOTE: Some users have had problems with newer versions of mount(newer than
- mount-2.11h) The following fstab entry might work better for you.
- 
--/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
-+/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
- 
- 5) Install the hotplug utilities
-    (http://linux-hotplug.sourceforge.net/, debian package: 'hotplug')
-@@ -819,13 +819,13 @@
- 
- 7) Mount the iPod hard drive
- 
--   mount /mnt/ipod
-+   mount /media/ipod
- 
- 8) do whatever you need to do (e.g. start gtkpod, see below)
- 
- 9) Unmount the iPod:
- 
--    umount /mnt/ipod
-+    umount /media/ipod
- 
- 10) Unload the module sbp2 (as most likely as root):
- 
-@@ -874,19 +874,19 @@
-     *                          -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
-     *                          -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
- 
--3) Create /mnt/ipod:
-+3) Create /media/ipod:
- 
--   mkdir /mnt/ipod
-+   mkdir /media/ipod
- 
- 4) Add a line to /etc/fstab. You should edit uid to match your user
-    id. Also, /dev/sda2 may not be appropriate, if you have other scsi
-    devices.
- 
--/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime 0 0
-+/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime 0 0
- 
-    (For HFS this line should read
- 
--/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
-+/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
- 
-     please note that it's just '/dev/sda')
- 
-@@ -894,7 +894,7 @@
- NOTE: Some users have had problems with newer versions of mount(newer than
- mount-2.11h) The following fstab entry might work better for you.
- 
--/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
-+/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
- 
- NOTE: You can add ",umask=0" to the options to make the iPod
- readable/writable for all users.
-@@ -934,13 +934,13 @@
- 
- 7) Mount the iPod hard drive
- 
--   mount /mnt/ipod
-+   mount /media/ipod
- 
- 8) do whatever you need to do (e.g. start gtkpod, see below)
- 
- 9) Unmount the iPod:
- 
--    umount /mnt/ipod
-+    umount /media/ipod
- 
- 10) Unload the module sbp2 (as most likely as root):
- 
-@@ -974,7 +974,7 @@
- - since the iPod's hdd was already spun up, the SCSI subsystem now
-   recognizes it and mounts it as /dev/sda
- 
--- You can then mount /dev/sda2 to /mnt/ipod as normal."
-+- You can then mount /dev/sda2 to /media/ipod as normal."
- 
- On the other hand: with my 4G iPod under 2.6.9 and 2.6.10 I never had
- any problem whatsoever getting the iPod to work. With IEEE it was
-@@ -1030,10 +1030,10 @@
- /**********/
- Add a line similar to the below to your /etc/fstab, this will enable users
- to mount the ipod with read/write capabilities.  Example line assumes your
--ipod mount point is /mnt/ipod and your ipod is detected as /dev/sda
-+ipod mount point is /media/ipod and your ipod is detected as /dev/sda
- 
- ------------------------------- Begin Here ---------------------------------
--/dev/sda2       /mnt/ipod       vfat    rw,user,noauto          0       0
-+/dev/sda2       /media/ipod       vfat    rw,user,noauto          0       0
- ------------------------------- End Here -----------------------------------
- 
- 
-diff -urNad trunk~/scripts/sync-abook.sh trunk/scripts/sync-abook.sh
---- trunk~/scripts/sync-abook.sh	2007-11-18 16:28:19.000000000 +0100
-+++ trunk/scripts/sync-abook.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -9,7 +9,7 @@
- #
- # with the following defaults: 
- 
--IPOD_MOUNT='/mnt/ipod'				# mount point of ipod
-+IPOD_MOUNT='/media/ipod'				# mount point of ipod
- DATAFILE='~/.abook/addressbook'	                # the abook db
- ENCODING_FROM=UTF-8                             # encoding used by abook
- ENCODING=ISO-8859-15                            # encoding used by ipod
-diff -urNad trunk~/scripts/sync-evocalendar.sh trunk/scripts/sync-evocalendar.sh
---- trunk~/scripts/sync-evocalendar.sh	2007-11-18 16:28:23.000000000 +0100
-+++ trunk/scripts/sync-evocalendar.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -10,7 +10,7 @@
- #
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
- 
- #the path to a script that will be passed the ical information from STDIN and filter, if needed
- #FILTER_SCRIPT=
-diff -urNad trunk~/scripts/sync-evolution.sh trunk/scripts/sync-evolution.sh
---- trunk~/scripts/sync-evolution.sh	2007-11-18 16:28:26.000000000 +0100
-+++ trunk/scripts/sync-evolution.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -13,7 +13,7 @@
- #
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod         # mountpoint of ipod
- EVOPATH='/opt/gnome/libexec/evolution/2.0:/usr/lib/evolution/2.0:/opt/gnome/bin'                        # additional path
- ENCODING=ISO-8859-15         # encoding used by ipod
- 
-diff -urNad trunk~/scripts/sync-kaddressbook.sh trunk/scripts/sync-kaddressbook.sh
---- trunk~/scripts/sync-kaddressbook.sh	2007-11-18 16:28:29.000000000 +0100
-+++ trunk/scripts/sync-kaddressbook.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -9,7 +9,7 @@
- #
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
- DATAFILE=~/.kde/share/apps/kabc/std.vcf       # vcard file
- ENCODING=ISO-8859-15                          # encoding used by ipod
- 
-diff -urNad trunk~/scripts/sync-korganizer.sh trunk/scripts/sync-korganizer.sh
---- trunk~/scripts/sync-korganizer.sh	2007-11-18 16:28:35.000000000 +0100
-+++ trunk/scripts/sync-korganizer.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -9,7 +9,7 @@
- #
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
- DATAFILE=~/.kde/share/apps/korganizer/std.ics # calendar data file
- ENCODING=ISO-8859-15                          # encoding used by ipod
- 
-diff -urNad trunk~/scripts/sync-ldif.sh trunk/scripts/sync-ldif.sh
---- trunk~/scripts/sync-ldif.sh	2007-11-18 16:28:40.000000000 +0100
-+++ trunk/scripts/sync-ldif.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -15,7 +15,7 @@
- # differently...This is still Chinese for me!! :)
- 
- export LDIFAMILYNAME=contactIPOD	# Filenames will look like $LDIFAMILYNAMEXX.vcf, X=[0-9]
--export IPOD_MOUNT=/mnt/ipod		# Mount point of the ipod
-+export IPOD_MOUNT=/media/ipod		# Mount point of the ipod
- declare LDIFILE=addressbook.ldif	# default filename 'addressbook.ldif'
- declare ENCODING=ISO-8859-15            # To try others encodings : 'iconv --list'
- declare DELETE="NO"			# To delete old .vcf files by default? 'NO'!!
-@@ -41,9 +41,9 @@
- 		$(basename $0) doesn't delete old .vcf files by default, but overwrites.
- 
- 		Options:
--		Syntax : $(basename $0) -f addbook.ldif -m /mnt/ipod -n contactIPOD -d (-h)
-+		Syntax : $(basename $0) -f addbook.ldif -m /media/ipod -n contactIPOD -d (-h)
- 		[-f] addbook.ldif  : contains the .ldif Filename
--		[-m] /mnt/ipod   : contains the ipod Mounted directory
-+		[-m] /media/ipod   : contains the ipod Mounted directory
- 		[-n] contactIPOD   : contains the .vcf family fileName
- 		[-d]               : contains the option to Delete all old .vcf files
- 		[-h]               : contains this Help
-diff -urNad trunk~/scripts/sync-thunderbird-nano.sh trunk/scripts/sync-thunderbird-nano.sh
---- trunk~/scripts/sync-thunderbird-nano.sh	2007-11-18 16:28:43.000000000 +0100
-+++ trunk/scripts/sync-thunderbird-nano.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -25,7 +25,7 @@
- 
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod         # mountpoint of ipod
- ENCODING=ISO-8859-15         # encoding used by ipod
- NAME=thunderbird             # default file export name
- FILE_FLAG=''		     # flag used to determine end of file
-diff -urNad trunk~/scripts/sync-thunderbird.sh trunk/scripts/sync-thunderbird.sh
---- trunk~/scripts/sync-thunderbird.sh	2007-11-18 16:28:46.000000000 +0100
-+++ trunk/scripts/sync-thunderbird.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -18,7 +18,7 @@
- 
- # with the following defaults: 
- 
--IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
-+IPOD_MOUNT=/media/ipod         # mountpoint of ipod
- ENCODING=ISO-8859-15         # encoding used by ipod
- NAME=thunderbird             # default file export name
- 
-diff -urNad trunk~/scripts/sync-webcalendar.sh trunk/scripts/sync-webcalendar.sh
---- trunk~/scripts/sync-webcalendar.sh	2007-11-18 16:28:52.000000000 +0100
-+++ trunk/scripts/sync-webcalendar.sh	2007-11-18 16:48:16.000000000 +0100
-@@ -9,7 +9,7 @@
- # with the following defaults:
- 
- # mount point of ipod
--IPOD_MOUNT='/mnt/ipod'
-+IPOD_MOUNT='/media/ipod'
- # uri for webcalendar (example)
- DATAFILE='https://somewhere.local/calendar.ics'
- # calendar name

Copied: gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch (from rev 278, gtkpod/trunk/debian/patches/01_mountpoint.dpatch)
===================================================================
--- gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/debian/patches/01_mountpoint.dpatch	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,276 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 01_mountpoint.dpatch by Nico Golde <nion at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+ at DPATCH@
+diff -urNad trunk~/README trunk/README
+--- trunk~/README	2007-11-18 16:47:22.000000000 +0100
++++ trunk/README	2007-11-20 14:20:36.000000000 +0100
+@@ -52,7 +52,7 @@
+ 1) If your iPod is not mounted automatically when connecting it to
+    your computer follow steps 1-7 in the "Connecting your iPod to a
+    Linux box" (basically you need to get the iPod partition mounted to
+-   /mnt/ipod).  In most cases this should not be necessary any more
++   /media/ipod).  In most cases this should not be necessary any more
+    these days.
+ 
+ 2) If you are using GNOME, starting with V1.0 of gtkpod your iPod will
+@@ -699,13 +699,13 @@
+    (Obviously you need to change the filesystem type from 'vfat' to
+    'hfsplus' when you use an HFS formatted iPod.)
+ 
+-   Then simply add a link from /mnt/ipod:
++   Then simply add a link from /media/ipod:
+ 
+-   ln -s /var/autofs/removable/ipod /mnt/ipod
++   ln -s /var/autofs/removable/ipod /media/ipod
+ 
+ 
+ Now your system is configured to mount the iPod every time you access
+-/mnt/ipod and to unmount it again after two seconds of inactivity. You
++/media/ipod and to unmount it again after two seconds of inactivity. You
+ won't have to worry about doing mounting/unmouting yourself any more.
+ 
+ 
+@@ -750,19 +750,19 @@
+     *                            -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
+ 
+ 
+-3) Create /mnt/ipod:
++3) Create /media/ipod:
+ 
+-   mkdir /mnt/ipod
++   mkdir /media/ipod
+ 
+ 4) Add a line to /etc/fstab. You should edit uid to match your user
+    id. Also, /dev/sda2 may not be appropriate, if you have other scsi
+    devices.
+ 
+-/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
++/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,errors=remount 0 0
+ 
+    (For HFS this line should read
+ 
+-/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
++/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
+ 
+     please note that it's just '/dev/sda')
+ 
+@@ -770,7 +770,7 @@
+ NOTE: Some users have had problems with newer versions of mount(newer than
+ mount-2.11h) The following fstab entry might work better for you.
+ 
+-/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
++/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
+ 
+ 5) Install the hotplug utilities
+    (http://linux-hotplug.sourceforge.net/, debian package: 'hotplug')
+@@ -819,13 +819,13 @@
+ 
+ 7) Mount the iPod hard drive
+ 
+-   mount /mnt/ipod
++   mount /media/ipod
+ 
+ 8) do whatever you need to do (e.g. start gtkpod, see below)
+ 
+ 9) Unmount the iPod:
+ 
+-    umount /mnt/ipod
++    umount /media/ipod
+ 
+ 10) Unload the module sbp2 (as most likely as root):
+ 
+@@ -874,19 +874,19 @@
+     *                          -> Codepage 437 (CONFIG_NLS_CODEPAGE_437)
+     *                          -> NLS ISO 8859-1 (CONFIG_NLS_ISO8859_1) 
+ 
+-3) Create /mnt/ipod:
++3) Create /media/ipod:
+ 
+-   mkdir /mnt/ipod
++   mkdir /media/ipod
+ 
+ 4) Add a line to /etc/fstab. You should edit uid to match your user
+    id. Also, /dev/sda2 may not be appropriate, if you have other scsi
+    devices.
+ 
+-/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime 0 0
++/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime 0 0
+ 
+    (For HFS this line should read
+ 
+-/dev/sda  /mnt/ipod  hfsplus  rw,user,noauto,exec  0  0
++/dev/sda  /media/ipod  hfsplus  rw,user,noauto,exec  0  0
+ 
+     please note that it's just '/dev/sda')
+ 
+@@ -894,7 +894,7 @@
+ NOTE: Some users have had problems with newer versions of mount(newer than
+ mount-2.11h) The following fstab entry might work better for you.
+ 
+-/dev/sda2	/mnt/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
++/dev/sda2	/media/ipod	vfat rw,user,noauto,noatime,shortname=winnt 0 0
+ 
+ NOTE: You can add ",umask=0" to the options to make the iPod
+ readable/writable for all users.
+@@ -934,13 +934,13 @@
+ 
+ 7) Mount the iPod hard drive
+ 
+-   mount /mnt/ipod
++   mount /media/ipod
+ 
+ 8) do whatever you need to do (e.g. start gtkpod, see below)
+ 
+ 9) Unmount the iPod:
+ 
+-    umount /mnt/ipod
++    umount /media/ipod
+ 
+ 10) Unload the module sbp2 (as most likely as root):
+ 
+@@ -974,7 +974,7 @@
+ - since the iPod's hdd was already spun up, the SCSI subsystem now
+   recognizes it and mounts it as /dev/sda
+ 
+-- You can then mount /dev/sda2 to /mnt/ipod as normal."
++- You can then mount /dev/sda2 to /media/ipod as normal."
+ 
+ On the other hand: with my 4G iPod under 2.6.9 and 2.6.10 I never had
+ any problem whatsoever getting the iPod to work. With IEEE it was
+@@ -1030,10 +1030,10 @@
+ /**********/
+ Add a line similar to the below to your /etc/fstab, this will enable users
+ to mount the ipod with read/write capabilities.  Example line assumes your
+-ipod mount point is /mnt/ipod and your ipod is detected as /dev/sda
++ipod mount point is /media/ipod and your ipod is detected as /dev/sda
+ 
+ ------------------------------- Begin Here ---------------------------------
+-/dev/sda2       /mnt/ipod       vfat    rw,user,noauto          0       0
++/dev/sda2       /media/ipod       vfat    rw,user,noauto          0       0
+ ------------------------------- End Here -----------------------------------
+ 
+ 
+diff -urNad trunk~/scripts/sync-abook.sh trunk/scripts/sync-abook.sh
+--- trunk~/scripts/sync-abook.sh	2007-11-18 16:28:19.000000000 +0100
++++ trunk/scripts/sync-abook.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -9,7 +9,7 @@
+ #
+ # with the following defaults: 
+ 
+-IPOD_MOUNT='/mnt/ipod'				# mount point of ipod
++IPOD_MOUNT='/media/ipod'				# mount point of ipod
+ DATAFILE='~/.abook/addressbook'	                # the abook db
+ ENCODING_FROM=UTF-8                             # encoding used by abook
+ ENCODING=ISO-8859-15                            # encoding used by ipod
+diff -urNad trunk~/scripts/sync-evocalendar.sh trunk/scripts/sync-evocalendar.sh
+--- trunk~/scripts/sync-evocalendar.sh	2007-11-18 16:28:23.000000000 +0100
++++ trunk/scripts/sync-evocalendar.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -10,7 +10,7 @@
+ #
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
++IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
+ 
+ #the path to a script that will be passed the ical information from STDIN and filter, if needed
+ #FILTER_SCRIPT=
+diff -urNad trunk~/scripts/sync-evolution.sh trunk/scripts/sync-evolution.sh
+--- trunk~/scripts/sync-evolution.sh	2007-11-18 16:28:26.000000000 +0100
++++ trunk/scripts/sync-evolution.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -13,7 +13,7 @@
+ #
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
++IPOD_MOUNT=/media/ipod         # mountpoint of ipod
+ EVOPATH='/opt/gnome/libexec/evolution/2.0:/usr/lib/evolution/2.0:/opt/gnome/bin'                        # additional path
+ ENCODING=ISO-8859-15         # encoding used by ipod
+ 
+diff -urNad trunk~/scripts/sync-kaddressbook.sh trunk/scripts/sync-kaddressbook.sh
+--- trunk~/scripts/sync-kaddressbook.sh	2007-11-18 16:28:29.000000000 +0100
++++ trunk/scripts/sync-kaddressbook.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -9,7 +9,7 @@
+ #
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
++IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
+ DATAFILE=~/.kde/share/apps/kabc/std.vcf       # vcard file
+ ENCODING=ISO-8859-15                          # encoding used by ipod
+ 
+diff -urNad trunk~/scripts/sync-korganizer.sh trunk/scripts/sync-korganizer.sh
+--- trunk~/scripts/sync-korganizer.sh	2007-11-18 16:28:35.000000000 +0100
++++ trunk/scripts/sync-korganizer.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -9,7 +9,7 @@
+ #
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
++IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
+ DATAFILE=~/.kde/share/apps/korganizer/std.ics # calendar data file
+ ENCODING=ISO-8859-15                          # encoding used by ipod
+ 
+diff -urNad trunk~/scripts/sync-ldif.sh trunk/scripts/sync-ldif.sh
+--- trunk~/scripts/sync-ldif.sh	2007-11-19 18:49:28.000000000 +0100
++++ trunk/scripts/sync-ldif.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -15,7 +15,7 @@
+ # differently...This is still Chinese for me!! :)
+ 
+ export LDIFAMILYNAME=contactIPOD	# Filenames will look like $LDIFAMILYNAMEXX.vcf, X=[0-9]
+-export IPOD_MOUNT=/mnt/ipod		# Mount point of the ipod
++export IPOD_MOUNT=/media/ipod		# Mount point of the ipod
+ declare LDIFILE=addressbook.ldif	# default filename 'addressbook.ldif'
+ declare ENCODING=ISO-8859-15            # To try others encodings : 'iconv --list'
+ declare DELETE="NO"			# To delete old .vcf files by default? 'NO'!!
+diff -urNad trunk~/scripts/sync-thunderbird-nano.sh trunk/scripts/sync-thunderbird-nano.sh
+--- trunk~/scripts/sync-thunderbird-nano.sh	2007-11-18 16:28:43.000000000 +0100
++++ trunk/scripts/sync-thunderbird-nano.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -25,7 +25,7 @@
+ 
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
++IPOD_MOUNT=/media/ipod         # mountpoint of ipod
+ ENCODING=ISO-8859-15         # encoding used by ipod
+ NAME=thunderbird             # default file export name
+ FILE_FLAG=''		     # flag used to determine end of file
+diff -urNad trunk~/scripts/sync-thunderbird.sh trunk/scripts/sync-thunderbird.sh
+--- trunk~/scripts/sync-thunderbird.sh	2007-11-18 16:28:46.000000000 +0100
++++ trunk/scripts/sync-thunderbird.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -18,7 +18,7 @@
+ 
+ # with the following defaults: 
+ 
+-IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
++IPOD_MOUNT=/media/ipod         # mountpoint of ipod
+ ENCODING=ISO-8859-15         # encoding used by ipod
+ NAME=thunderbird             # default file export name
+ 
+diff -urNad trunk~/scripts/sync-webcalendar.sh trunk/scripts/sync-webcalendar.sh
+--- trunk~/scripts/sync-webcalendar.sh	2007-11-18 16:28:52.000000000 +0100
++++ trunk/scripts/sync-webcalendar.sh	2007-11-20 14:20:36.000000000 +0100
+@@ -9,7 +9,7 @@
+ # with the following defaults:
+ 
+ # mount point of ipod
+-IPOD_MOUNT='/mnt/ipod'
++IPOD_MOUNT='/media/ipod'
+ # uri for webcalendar (example)
+ DATAFILE='https://somewhere.local/calendar.ics'
+ # calendar name
+diff -urNad trunk~/src/prefs.c trunk/src/prefs.c
+--- trunk~/src/prefs.c	2007-11-18 16:45:09.000000000 +0100
++++ trunk/src/prefs.c	2007-11-20 14:20:44.000000000 +0100
+@@ -178,7 +178,7 @@
+     prefs_set_int("delete_file", TRUE);
+     prefs_set_int("delete_local_file", TRUE);
+     prefs_set_int("delete_database", TRUE);
+-    prefs_set_string("initial_mountpoint", "/mnt/ipod");
++    prefs_set_string("initial_mountpoint", "/media/ipod");
+     prefs_set_string ("path_play_now", "xmms %s");
+     prefs_set_string ("path_play_enqueue", "xmms -e %s");
+     prefs_set_string ("path_mserv_trackinfo_root", "/var/lib/mserv/trackinfo/");

Deleted: gtkpod/tags/0.99.10-5/debian/rules
===================================================================
--- gtkpod/trunk/debian/rules	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/debian/rules	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,64 +0,0 @@
-#!/usr/bin/make -f
-
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-
-CFLAGS = -Wall -g
-
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
-	CFLAGS += -O0
-else
-	CFLAGS += -O2
-endif
-
-config.status: configure
-	dh_testdir
-	CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
-
-build: build-stamp
-
-build-stamp:  config.status
-	dh_testdir
-
-	$(MAKE)
-	pod2man --release "gtkpod 0.99.10" --center "gtkpod Manual" debian/gtkpod.pod >gtkpod.1
-	touch build-stamp
-
-clean:
-	dh_testdir
-	dh_testroot
-	rm -f build-stamp gtkpod.1 pixmaps/gtkpod.glade*
-	[ ! -f Makefile ] || $(MAKE) distclean
-	dh_clean
-
-install: build
-	dh_testdir
-	dh_testroot
-	dh_clean -k
-	dh_installdirs
-	$(MAKE) install DESTDIR=$(CURDIR)/debian/gtkpod
-
-binary-indep: build install
-
-binary-arch: build install
-	dh_testdir
-	dh_testroot
-	dh_installchangelogs ChangeLog
-	dh_installdocs
-	dh_installmenu
-	dh_installman gtkpod.1
-	dh_install
-	dh_desktop
-	dh_link
-	dh_strip
-	dh_compress
-	dh_fixperms
-	dh_makeshlibs
-	dh_installdeb
-	dh_shlibdeps
-	dh_gencontrol
-	dh_md5sums
-	dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 

Copied: gtkpod/tags/0.99.10-5/debian/rules (from rev 265, gtkpod/trunk/debian/rules)
===================================================================
--- gtkpod/tags/0.99.10-5/debian/rules	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/debian/rules	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,66 @@
+#!/usr/bin/make -f
+
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+CFLAGS = -Wall -g
+
+include /usr/share/dpatch/dpatch.make
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+config.status: patch configure
+	dh_testdir
+	CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
+
+build: build-stamp
+
+build-stamp:  config.status
+	dh_testdir
+
+	$(MAKE)
+	pod2man --release "gtkpod 0.99.10" --center "gtkpod Manual" debian/gtkpod.pod >gtkpod.1
+	touch build-stamp
+
+clean: unpatch
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp gtkpod.1 pixmaps/gtkpod.glade*
+	[ ! -f Makefile ] || $(MAKE) distclean
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+	$(MAKE) install DESTDIR=$(CURDIR)/debian/gtkpod
+
+binary-indep: build install
+
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs ChangeLog
+	dh_installdocs
+	dh_installmenu
+	dh_installman gtkpod.1
+	dh_install
+	dh_desktop
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install 

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-abook.sh
===================================================================
--- gtkpod/trunk/scripts/sync-abook.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-abook.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,74 +0,0 @@
-#!/bin/sh
-# (c) 2005 Daniel Kercher 
-# Script to sync the ipod with abook
-
-# Usage:
-# 
-# sync-abook.sh [-i <ipod mountpoint>] [-d <abook database>]
-#           ... [-e <encoding ipod>] [-f <encoding abook>]
-#
-# with the following defaults: 
-
-IPOD_MOUNT='/media/ipod'				# mount point of ipod
-DATAFILE='~/.abook/addressbook'	                # the abook db
-ENCODING_FROM=UTF-8                             # encoding used by abook
-ENCODING=ISO-8859-15                            # encoding used by ipod
-
-# Unless called with "-e=none" this script requires "iconv" available
-# from http://www.gnu.org/software/libiconv/
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calenader files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-# Changelog
-# 2005/06/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Received original script from Daniel Kercher and added character
-# conversion and command line options.
-#
-# 2007/05/31 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Set a more reasonable default datafile.
-#
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e:f: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) DATAFILE=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-	f) ENCODING_FROM=$OPTARG;;
-        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <abook database>] [-e <encoding ipod>] [-f <encoding abook>]"
-	    exit 1;;
-    esac
-done
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f $ENCODING_FROM -t $ENCODING"
-fi
-
-
-# check if DATAFILE exists
-if [ ! -f $DATAFILE ]; then
-    echo "Error: $DATAFILE does not exist"
-    exit 1
-fi
-
-echo -n "Syncing abook to iPod... "
-abook --convert --infile $DATAFILE --outformat gcrd | sed '/^$/d' | $RECODE > ${IPOD_MOUNT}/Contacts/abook.vcf
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-abook.sh (from rev 266, gtkpod/trunk/scripts/sync-abook.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-abook.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-abook.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,74 @@
+#!/bin/sh
+# (c) 2005 Daniel Kercher 
+# Script to sync the ipod with abook
+
+# Usage:
+# 
+# sync-abook.sh [-i <ipod mountpoint>] [-d <abook database>]
+#           ... [-e <encoding ipod>] [-f <encoding abook>]
+#
+# with the following defaults: 
+
+IPOD_MOUNT='/mnt/ipod'				# mount point of ipod
+DATAFILE='~/.abook/addressbook'	                # the abook db
+ENCODING_FROM=UTF-8                             # encoding used by abook
+ENCODING=ISO-8859-15                            # encoding used by ipod
+
+# Unless called with "-e=none" this script requires "iconv" available
+# from http://www.gnu.org/software/libiconv/
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calenader files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+# Changelog
+# 2005/06/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Received original script from Daniel Kercher and added character
+# conversion and command line options.
+#
+# 2007/05/31 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Set a more reasonable default datafile.
+#
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e:f: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) DATAFILE=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+	f) ENCODING_FROM=$OPTARG;;
+        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <abook database>] [-e <encoding ipod>] [-f <encoding abook>]"
+	    exit 1;;
+    esac
+done
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f $ENCODING_FROM -t $ENCODING"
+fi
+
+
+# check if DATAFILE exists
+if [ ! -f $DATAFILE ]; then
+    echo "Error: $DATAFILE does not exist"
+    exit 1
+fi
+
+echo -n "Syncing abook to iPod... "
+abook --convert --infile $DATAFILE --outformat gcrd | sed '/^$/d' | $RECODE > ${IPOD_MOUNT}/Contacts/abook.vcf
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh
===================================================================
--- gtkpod/trunk/scripts/sync-evocalendar.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,127 +0,0 @@
-#!/bin/sh
-# (c) 2004 Markus Gaugusch <markus at gaugusch.at>
-# Script for syncing evolution calendar and task data with iPod
-
-# Usage:
-# 
-# sync-evocalendar.sh [-i <ipod mountpoint>] [-e <encoding>]
-#           ...       [-c <evolution calendar file>] [-t <evolution tasks file>]
-#           ...       [-f <ical filter script>]
-#
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
-
-#the path to a script that will be passed the ical information from STDIN and filter, if needed
-#FILTER_SCRIPT=
-
-#get all the local evolution calendars
-CALFILES=`find ~/.evolution/calendar/local/ -name "calendar.ics"`
-
-#get all the local evolution tasks
-TASKFILES=`find ~/.evolution/tasks/local/ -name "tasks.ics"`
-
-ENCODING=ISO-8859-15                          # encoding used by ipod
-
-# Unless called with "-e none" this script requires "iconv" available
-# from http://www.gnu.org/software/libiconv/
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calenader files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2006/03/08 (Michele C. Soccio <michele at soccio dot it>:
-# Changed to get all the local calendar and task files
-#
-# Changed to correct the calendar file(s) and task file(s) command line option
-# 
-# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Changed to accept ipod-mountpath and encoding as command line
-# option
-#
-# Split into two files -- one for contacts, one for calendar.
-#
-# Placed under GPL in agreement with Markus Gaugusch.
-#
-# Added note about encoding used by the iPod.
-#
-# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Added Usage-line, added check for vcard file, rearranged source
-#
-# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Made "iconv" optional (call with "-e none")
-#
-# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
-# DOS-type vcards as well. Instead changed the "grep" pattern to
-# catch \cr\lf as well.
-#
-# 2004/12/15 (Clinton Gormley <clint at traveljury dot com>):
-# adapted sync-korganiser to work with evolution.
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:c:t:e: option; do
-    case $option in
-	i) IPOD_MOUNT=$OPTARG;;
-        c) CALFILES=$OPTARG;;
-        t) TASKFILES=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-        f) FILTER=$OPTARG;;
-		\?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-c <evolution calendar file>] [-t <evolution tasks file>] [-f <filter script>] [-e <encoding>]"
-	    exit 1;;
-    esac
-done
-
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f UTF-8 -t $ENCODING"
-fi
-
-if [ $FILTER_SCRIPT ]; then
-	FILTER=$FILTER_SCRIPT
-else
-	FILTER="cat"
-fi
-
-# check if CALFILES exist
-for i in $CALFILES; do
-	if [ ! -f $CALFILE ]; then
-	    echo "Error: $i does not exist"
-	    exit 1
-	fi
-done
-
-# check if each TASKFILES exist
-for j in $TASKFILES; do
-	if [ ! -f $j ]; then
-	    echo "Error: $TASKFILE does not exist"
-	    exit 1
-	fi
-done
-
-echo $CALFILES
-echo $TASKFILES
-
-# remove all empty lines and recode if necessary
-echo -n "Syncing iPod ... [Calendar] "
-	cat $CALFILES $TASKFILES | grep -v '^[[:space:]]$\|^$' | $FILTER |  $RECODE > $IPOD_MOUNT/Calendars/evolution
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh (from rev 266, gtkpod/trunk/scripts/sync-evocalendar.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-evocalendar.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,127 @@
+#!/bin/sh
+# (c) 2004 Markus Gaugusch <markus at gaugusch.at>
+# Script for syncing evolution calendar and task data with iPod
+
+# Usage:
+# 
+# sync-evocalendar.sh [-i <ipod mountpoint>] [-e <encoding>]
+#           ...       [-c <evolution calendar file>] [-t <evolution tasks file>]
+#           ...       [-f <ical filter script>]
+#
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
+
+#the path to a script that will be passed the ical information from STDIN and filter, if needed
+#FILTER_SCRIPT=
+
+#get all the local evolution calendars
+CALFILES=`find ~/.evolution/calendar/local/ -name "calendar.ics"`
+
+#get all the local evolution tasks
+TASKFILES=`find ~/.evolution/tasks/local/ -name "tasks.ics"`
+
+ENCODING=ISO-8859-15                          # encoding used by ipod
+
+# Unless called with "-e none" this script requires "iconv" available
+# from http://www.gnu.org/software/libiconv/
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calenader files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2006/03/08 (Michele C. Soccio <michele at soccio dot it>:
+# Changed to get all the local calendar and task files
+#
+# Changed to correct the calendar file(s) and task file(s) command line option
+# 
+# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Changed to accept ipod-mountpath and encoding as command line
+# option
+#
+# Split into two files -- one for contacts, one for calendar.
+#
+# Placed under GPL in agreement with Markus Gaugusch.
+#
+# Added note about encoding used by the iPod.
+#
+# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Added Usage-line, added check for vcard file, rearranged source
+#
+# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Made "iconv" optional (call with "-e none")
+#
+# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
+# DOS-type vcards as well. Instead changed the "grep" pattern to
+# catch \cr\lf as well.
+#
+# 2004/12/15 (Clinton Gormley <clint at traveljury dot com>):
+# adapted sync-korganiser to work with evolution.
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:c:t:e: option; do
+    case $option in
+	i) IPOD_MOUNT=$OPTARG;;
+        c) CALFILES=$OPTARG;;
+        t) TASKFILES=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+        f) FILTER=$OPTARG;;
+		\?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-c <evolution calendar file>] [-t <evolution tasks file>] [-f <filter script>] [-e <encoding>]"
+	    exit 1;;
+    esac
+done
+
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f UTF-8 -t $ENCODING"
+fi
+
+if [ $FILTER_SCRIPT ]; then
+	FILTER=$FILTER_SCRIPT
+else
+	FILTER="cat"
+fi
+
+# check if CALFILES exist
+for i in $CALFILES; do
+	if [ ! -f $CALFILE ]; then
+	    echo "Error: $i does not exist"
+	    exit 1
+	fi
+done
+
+# check if each TASKFILES exist
+for j in $TASKFILES; do
+	if [ ! -f $j ]; then
+	    echo "Error: $TASKFILE does not exist"
+	    exit 1
+	fi
+done
+
+echo $CALFILES
+echo $TASKFILES
+
+# remove all empty lines and recode if necessary
+echo -n "Syncing iPod ... [Calendar] "
+	cat $CALFILES $TASKFILES | grep -v '^[[:space:]]$\|^$' | $FILTER |  $RECODE > $IPOD_MOUNT/Calendars/evolution
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh
===================================================================
--- gtkpod/trunk/scripts/sync-evolution.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,95 +0,0 @@
-#!/bin/sh
-# Script for syncing evolution addressbook data with iPod
-# (c) 2004 Clinton Gormley <clint at traveljury dot com>
-#
-
-# Usage:
-# 
-# sync-addressbooks.sh [-i <ipod mountpoint>] [-e <encoding>]
-#                      [-d <path to evolution-addressbook-export>]
-#
-# (specify '-d' if evolution-addressbook-export is not in your default
-# path)
-#
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod         # mountpoint of ipod
-EVOPATH='/opt/gnome/libexec/evolution/2.0:/usr/lib/evolution/2.0:/opt/gnome/bin'                        # additional path
-ENCODING=ISO-8859-15         # encoding used by ipod
-
-# Unless called with "-e=none" this script requires "iconv" available
-# from http://www.gnu.org/software/libiconv/
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calender files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2004/12/07 (Clinton Gormley <clint at traveljury dot com>):
-# adapted sync-kaddressbook to work with evolution.
-#
-# 2004/12/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Split evolution support into a new file.
-#
-# 2007/04/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Allow syncing of contacts containing pictures. Thanks to Lars Friedrichs.
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) EVOPATH=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-        
-        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to evolution-addressbook-export>]"
-	    exit 1;;
-    esac
-done
-
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f UTF-8 -t $ENCODING"
-fi
-
-
-echo "Trying to export from evolution:"
-
-# adjust path to find evolution-addressbook-export
-PATH=$EVOPATH:$PATH
-
-# check if evolution-addressbook-export is in PATH
-evolution-addressbook-export --help  >/dev/null 2>&1
-
-if [ ! $? == 0 ]; then
-	echo "** Error: Couldn't find evolution-addressbook-export in your PATH:"
-	echo $PATH
-	echo ""
-	echo "Please specify \"-d <path to evolution-addressbook-export>\" when you call this script"
-    exit 1
-fi
-
-
-# remove all empty lines and recode if necessary
-echo -n "Syncing iPod ... [Contacts] "
-# Redirect STDERR to avoid the "FIXME : wait for completion unimplemented" warning
-evolution-addressbook-export 2>&1 | grep -v '^[[:space:]]$\|^$' | $RECODE | sed -e "s/PHOTO;ENCODING=b;TYPE=\"X-EVOLUTION-UNKNOWN\"/PHOTO;BASE64/g" > $IPOD_MOUNT/Contacts/evolution
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh (from rev 266, gtkpod/trunk/scripts/sync-evolution.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-evolution.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,95 @@
+#!/bin/sh
+# Script for syncing evolution addressbook data with iPod
+# (c) 2004 Clinton Gormley <clint at traveljury dot com>
+#
+
+# Usage:
+# 
+# sync-addressbooks.sh [-i <ipod mountpoint>] [-e <encoding>]
+#                      [-d <path to evolution-addressbook-export>]
+#
+# (specify '-d' if evolution-addressbook-export is not in your default
+# path)
+#
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
+EVOPATH='/opt/gnome/libexec/evolution/2.0:/usr/lib/evolution/2.0:/opt/gnome/bin'                        # additional path
+ENCODING=ISO-8859-15         # encoding used by ipod
+
+# Unless called with "-e=none" this script requires "iconv" available
+# from http://www.gnu.org/software/libiconv/
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calender files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2004/12/07 (Clinton Gormley <clint at traveljury dot com>):
+# adapted sync-kaddressbook to work with evolution.
+#
+# 2004/12/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Split evolution support into a new file.
+#
+# 2007/04/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Allow syncing of contacts containing pictures. Thanks to Lars Friedrichs.
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) EVOPATH=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+        
+        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to evolution-addressbook-export>]"
+	    exit 1;;
+    esac
+done
+
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f UTF-8 -t $ENCODING"
+fi
+
+
+echo "Trying to export from evolution:"
+
+# adjust path to find evolution-addressbook-export
+PATH=$EVOPATH:$PATH
+
+# check if evolution-addressbook-export is in PATH
+evolution-addressbook-export --help  >/dev/null 2>&1
+
+if [ ! $? == 0 ]; then
+	echo "** Error: Couldn't find evolution-addressbook-export in your PATH:"
+	echo $PATH
+	echo ""
+	echo "Please specify \"-d <path to evolution-addressbook-export>\" when you call this script"
+    exit 1
+fi
+
+
+# remove all empty lines and recode if necessary
+echo -n "Syncing iPod ... [Contacts] "
+# Redirect STDERR to avoid the "FIXME : wait for completion unimplemented" warning
+evolution-addressbook-export 2>&1 | grep -v '^[[:space:]]$\|^$' | $RECODE | sed -e "s/PHOTO;ENCODING=b;TYPE=\"X-EVOLUTION-UNKNOWN\"/PHOTO;BASE64/g" > $IPOD_MOUNT/Contacts/evolution
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh
===================================================================
--- gtkpod/trunk/scripts/sync-kaddressbook.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,90 +0,0 @@
-#!/bin/sh
-# (c) 2004 Markus Gaugusch <markus at gaugusch dot at>
-# Script for syncing kaddressbook data with iPod
-
-# Usage:
-# 
-# sync-kaddressbook.sh [-i <ipod mountpoint>] [-d <kaddressbook data file>]
-#           ...        [-e <encoding>]
-#
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
-DATAFILE=~/.kde/share/apps/kabc/std.vcf       # vcard file
-ENCODING=ISO-8859-15                          # encoding used by ipod
-
-# Unless called with "-e none" this script requires "iconv" available
-# from http://www.gnu.org/software/libiconv/
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calenader files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Changed to accept ipod-mountpath and encoding as command line
-# option
-#
-# Split into two files -- one for contacts, one for calendar.
-#
-# Placed under GPL in agreement with Markus Gaugusch.
-#
-# Added note about encoding used by the iPod.
-#
-# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Added Usage-line, added check for vcard file, rearranged source
-#
-# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Made "iconv" optional (call with "-e none")
-#
-# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
-# DOS-type vcards as well. Instead changed the "grep" pattern to
-# catch \cr\lf as well.
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) DATAFILE=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <kaddressbook data file>] [-e <encoding>]"
-	    exit 1;;
-    esac
-done
-
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f UTF-8 -t $ENCODING"
-fi
-
-
-# check if DATAFILE exists
-if [ ! -f $DATAFILE ]; then
-    echo "Error: $DATAFILE does not exist"
-    exit 1
-fi
-
-
-# remove all empty lines and recode if necessary
-echo -n "Syncing iPod ... [Contacts] "
-cat $DATAFILE | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Contacts/`basename $DATAFILE`
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh (from rev 266, gtkpod/trunk/scripts/sync-kaddressbook.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-kaddressbook.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,90 @@
+#!/bin/sh
+# (c) 2004 Markus Gaugusch <markus at gaugusch dot at>
+# Script for syncing kaddressbook data with iPod
+
+# Usage:
+# 
+# sync-kaddressbook.sh [-i <ipod mountpoint>] [-d <kaddressbook data file>]
+#           ...        [-e <encoding>]
+#
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
+DATAFILE=~/.kde/share/apps/kabc/std.vcf       # vcard file
+ENCODING=ISO-8859-15                          # encoding used by ipod
+
+# Unless called with "-e none" this script requires "iconv" available
+# from http://www.gnu.org/software/libiconv/
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calenader files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Changed to accept ipod-mountpath and encoding as command line
+# option
+#
+# Split into two files -- one for contacts, one for calendar.
+#
+# Placed under GPL in agreement with Markus Gaugusch.
+#
+# Added note about encoding used by the iPod.
+#
+# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Added Usage-line, added check for vcard file, rearranged source
+#
+# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Made "iconv" optional (call with "-e none")
+#
+# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
+# DOS-type vcards as well. Instead changed the "grep" pattern to
+# catch \cr\lf as well.
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) DATAFILE=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <kaddressbook data file>] [-e <encoding>]"
+	    exit 1;;
+    esac
+done
+
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f UTF-8 -t $ENCODING"
+fi
+
+
+# check if DATAFILE exists
+if [ ! -f $DATAFILE ]; then
+    echo "Error: $DATAFILE does not exist"
+    exit 1
+fi
+
+
+# remove all empty lines and recode if necessary
+echo -n "Syncing iPod ... [Contacts] "
+cat $DATAFILE | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Contacts/`basename $DATAFILE`
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh
===================================================================
--- gtkpod/trunk/scripts/sync-korganizer.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,90 +0,0 @@
-#!/bin/sh
-# (c) 2004 Markus Gaugusch <markus at gaugusch.at>
-# Script for syncing korganizer data with iPod
-
-# Usage:
-# 
-# sync-kaddressbook.sh [-i <ipod mountpoint>] [-d <korganizer data file>]
-#           ...        [-e <encoding>]
-#
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod                          # mountpoint of ipod
-DATAFILE=~/.kde/share/apps/korganizer/std.ics # calendar data file
-ENCODING=ISO-8859-15                          # encoding used by ipod
-
-# Unless called with "-e none" this script requires "iconv" available
-# from http://www.gnu.org/software/libiconv/
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calenader files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Changed to accept ipod-mountpath and encoding as command line
-# option
-#
-# Split into two files -- one for contacts, one for calendar.
-#
-# Placed under GPL in agreement with Markus Gaugusch.
-#
-# Added note about encoding used by the iPod.
-#
-# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Added Usage-line, added check for vcard file, rearranged source
-#
-# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Made "iconv" optional (call with "-e none")
-#
-# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
-# DOS-type vcards as well. Instead changed the "grep" pattern to
-# catch \cr\lf as well.
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) DATAFILE=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <korganizer data file>] [-e <encoding>]"
-	    exit 1;;
-    esac
-done
-
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f UTF-8 -t $ENCODING"
-fi
-
-
-# check if DATAFILE exists
-if [ ! -f $DATAFILE ]; then
-    echo "Error: $DATAFILE does not exist"
-    exit 1
-fi
-
-
-# remove all empty lines and recode if necessary
-echo -n "Syncing iPod ... [Calendar] "
-cat $DATAFILE | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Calendars/`basename $DATAFILE`
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh (from rev 266, gtkpod/trunk/scripts/sync-korganizer.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-korganizer.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,90 @@
+#!/bin/sh
+# (c) 2004 Markus Gaugusch <markus at gaugusch.at>
+# Script for syncing korganizer data with iPod
+
+# Usage:
+# 
+# sync-kaddressbook.sh [-i <ipod mountpoint>] [-d <korganizer data file>]
+#           ...        [-e <encoding>]
+#
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod                          # mountpoint of ipod
+DATAFILE=~/.kde/share/apps/korganizer/std.ics # calendar data file
+ENCODING=ISO-8859-15                          # encoding used by ipod
+
+# Unless called with "-e none" this script requires "iconv" available
+# from http://www.gnu.org/software/libiconv/
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calenader files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2004/06/27 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Changed to accept ipod-mountpath and encoding as command line
+# option
+#
+# Split into two files -- one for contacts, one for calendar.
+#
+# Placed under GPL in agreement with Markus Gaugusch.
+#
+# Added note about encoding used by the iPod.
+#
+# 2004/07/02 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Added Usage-line, added check for vcard file, rearranged source
+#
+# 2004/07/03 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Made "iconv" optional (call with "-e none")
+#
+# Removed "dos2unix" as my iPod (firmware 1.3) happily accepted
+# DOS-type vcards as well. Instead changed the "grep" pattern to
+# catch \cr\lf as well.
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) DATAFILE=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <korganizer data file>] [-e <encoding>]"
+	    exit 1;;
+    esac
+done
+
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f UTF-8 -t $ENCODING"
+fi
+
+
+# check if DATAFILE exists
+if [ ! -f $DATAFILE ]; then
+    echo "Error: $DATAFILE does not exist"
+    exit 1
+fi
+
+
+# remove all empty lines and recode if necessary
+echo -n "Syncing iPod ... [Calendar] "
+cat $DATAFILE | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Calendars/`basename $DATAFILE`
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh
===================================================================
--- gtkpod/trunk/scripts/sync-ldif.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,158 +0,0 @@
-#! /bin/sh
-
-# Placed under GPL; to know more, see:
-# 			http://www.gnu.org/licenses/licenses.html
-#
-# if you make any change, I would be happy to be kept advised by
-# sending an email at <sberidot at libertysurf dot fr>.
-#
-# Write "[sync-ldif.sh]" in the subject, otherwise the message is
-# bound to be considered as spam... :(
-#
-#
-# RESTRICTION : I haven't managed yet to read correctly data from
-# ldif files when accents are used, Thunderbird writes the names
-# differently...This is still Chinese for me!! :)
-
-export LDIFAMILYNAME=contactIPOD	# Filenames will look like $LDIFAMILYNAMEXX.vcf, X=[0-9]
-export IPOD_MOUNT=/media/ipod		# Mount point of the ipod
-declare LDIFILE=addressbook.ldif	# default filename 'addressbook.ldif'
-declare ENCODING=ISO-8859-15            # To try others encodings : 'iconv --list'
-declare DELETE="NO"			# To delete old .vcf files by default? 'NO'!!
-
-# Exiting function
-function EXITING {
-	export -n LDIFAMILYNAME
-	export -n IPOD_MOUNT
-}
-
-# Please HELP!!! :)
-function DISPLAY_HELP {
-	cat <<- EOF
-		Beware not to share the same familyname with old .vcf in the ipod directory;
-		no one precaution is taken, so files will be overwritten. :(
-		For the moment, I did not manage to make accents be displayed properly,
-		but still working on it. Enjoy!
-
-		Default options:
-		Current Ipod directory is      : $IPOD_MOUNT
-		Current Encoding               : $ENCODING
-		Current template for filenames : $LDIFAMILYNAME[1-9*].vcf
-		$(basename $0) doesn't delete old .vcf files by default, but overwrites.
-
-		Options:
-		Syntax : $(basename $0) -f addbook.ldif -m /media/ipod -n contactIPOD -d (-h)
-		[-f] addbook.ldif  : contains the .ldif Filename
-		[-m] /media/ipod   : contains the ipod Mounted directory
-		[-n] contactIPOD   : contains the .vcf family fileName
-		[-d]               : contains the option to Delete all old .vcf files
-		[-h]               : contains this Help
-	EOF
-}
-
-# $1 contains the directory to be tested
-# Is/Are .vcf file(s) present?
-function TST_VCF {
-	local j
-	for j in "${1%%/}/"* ; do
-		if [ "${j##*.}" = "vcf" ] ; then
-			return 0
-			break
-		fi
-	done
-	return 1
-}
-
-# $1 contains the util name
-# Is $1 already installed?
-function TST_UTIL {
-	which "$1" >/dev/null 2>&1
-	if [ "$?" != "0" ]; then
-		echo "[INSTALL] $1 utility not found, please install $1 package first!"
-		EXITING
-		exit 3
-	fi
-}
-
-# $1 contains the .vcf filename
-# extracts names from .vcf filename
-function EXTRACT_CONTACT_FROM_VCF {
-	local NAME="UNKNOWN"
-	if [ -e "$1" ] ; then
-		NAME=$(grep "fn:" "$1")
-		NAME=${NAME:3}
-	fi
-	echo "$NAME"
-}
-
-function DELETE_VCFILE_FROM_IPOD {
-	# if no .vcf file's found, exit!
-	if ! TST_VCF "$IPOD_MOUNT"/Contacts/ ; then
-		echo "[DELETING] no file detected"
-		return
-	fi
-	# begin to delete
-	local i
-	for i in "$IPOD_MOUNT"/Contacts/*.vcf ; do
-		echo "[DELETING] " $(EXTRACT_CONTACT_FROM_VCF "$i") "from ${i##*/}"
-		rm -f "$i"
-	done
-}
-
-# Is Ipod Directory valid?
-function IS_IPOD_DIR_VALID {
-	# Test of the $IPOD_MOUNT directory
-	if [ ! -d "$IPOD_MOUNT/Contacts/" ]; then
-		echo "$IPOD_MOUNT/Contacts invalid... Exiting."
-		EXITING
-		exit 2
-	fi
-}
-
-# Program's starting here!
-
-# Testing awk and iconv utils...
-TST_UTIL "awk"
-TST_UTIL "iconv"
-
-# picking up and processing parameters from prompt...
-while getopts ":f:m:n:dh:" option ; do
-	case $option in
-		f )	LDIFILE="$OPTARG";;
-		m )     IPOD_MOUNT="${OPTARG%%/}";;
-		n )	LDIFAMILYNAME="$OPTARG";;
-		d )	DELETE="OK";;
-		h | * )	DISPLAY_HELP; EXITING; exit 1;;
-	esac
-done
-
-# check, if not valid, exit!
-IS_IPOD_DIR_VALID
-
-# Is LDIFILE really a ldif file? just testing the extension, and if the file exists...
-if [ "${LDIFILE##*.}" == "ldif" ] || [ "${LDIFILE##*.}" == "LDIF" ] && [ -e "$LDIFILE" ] ; then
-	# The $IPOD_MOUNT/Contacts/ directory will be emptied if '-d' option!
-	if [ "$DELETE" == "OK" ]; then
-		echo "Old contacts being deleted from $IPOD_MOUNT. Work in progress..."
-		DELETE_VCFILE_FROM_IPOD
-		sleep 1
-	fi
-
-	echo "New contacts being synchronised from $LDIFILE. Work in progress..."
-	# Translation from LDIF into VCF, in order to cut standard output in vcf files...
-	# Converting into vcf stream | converting to ENCODING | detection of VCF card
-	#							and writing it into the Ipod
-	ldif2vcf.sh < "$LDIFILE" | iconv -f UTF-8 -t $ENCODING | awk 'BEGIN{RS="\n"; NAME=""; CARD=""; VCFILE=""; NCARD=1} /^fn:/ {NAME=substr($0,4)} /^$/{next} /^end:vcard/ {VCFILE = ENVIRON["IPOD_MOUNT"] "/Contacts/" ENVIRON["LDIFAMILYNAME"] (NCARD-1) ".vcf"; print "[WRITING] " NAME " in " ENVIRON["LDIFAMILYNAME"] (NCARD-1) ".vcf"; print CARD "end:vcard" > VCFILE; CARD=""; VCFILE=""; NCARD++; next} {CARD=CARD $0 RS} END{print (NCARD-1) " vcards added."}' # >/dev/null 2>&1
-
-	if [ "$?" != "0" ]; then
-		echo "[ERROR] An error occured, exiting, sorry for that... Please Report!"
-		EXITING
-		exit 1
-	fi
-	echo "complete!"
-else
-	DISPLAY_HELP
-fi
-
-EXITING
-exit 0

Copied: gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh (from rev 275, gtkpod/trunk/scripts/sync-ldif.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-ldif.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,158 @@
+#! /bin/sh
+
+# Placed under GPL; to know more, see:
+# 			http://www.gnu.org/licenses/licenses.html
+#
+# if you make any change, I would be happy to be kept advised by
+# sending an email at <sberidot at libertysurf dot fr>.
+#
+# Write "[sync-ldif.sh]" in the subject, otherwise the message is
+# bound to be considered as spam... :(
+#
+#
+# RESTRICTION : I haven't managed yet to read correctly data from
+# ldif files when accents are used, Thunderbird writes the names
+# differently...This is still Chinese for me!! :)
+
+export LDIFAMILYNAME=contactIPOD	# Filenames will look like $LDIFAMILYNAMEXX.vcf, X=[0-9]
+export IPOD_MOUNT=/mnt/ipod		# Mount point of the ipod
+declare LDIFILE=addressbook.ldif	# default filename 'addressbook.ldif'
+declare ENCODING=ISO-8859-15            # To try others encodings : 'iconv --list'
+declare DELETE="NO"			# To delete old .vcf files by default? 'NO'!!
+
+# Exiting function
+function EXITING {
+	export -n LDIFAMILYNAME
+	export -n IPOD_MOUNT
+}
+
+# Please HELP!!! :)
+function DISPLAY_HELP {
+	cat <<- EOF
+		Beware not to share the same familyname with old .vcf in the ipod directory;
+		no one precaution is taken, so files will be overwritten. :(
+		For the moment, I did not manage to make accents be displayed properly,
+		but still working on it. Enjoy!
+
+		Default options:
+		Current Ipod directory is      : $IPOD_MOUNT
+		Current Encoding               : $ENCODING
+		Current template for filenames : $LDIFAMILYNAME[1-9*].vcf
+		$(basename $0) doesn't delete old .vcf files by default, but overwrites.
+
+		Options:
+		Syntax : $(basename $0) -f addbook.ldif -m /media/ipod -n contactIPOD -d (-h)
+		[-f] addbook.ldif  : contains the .ldif Filename
+		[-m] /media/ipod   : contains the ipod Mounted directory
+		[-n] contactIPOD   : contains the .vcf family fileName
+		[-d]               : contains the option to Delete all old .vcf files
+		[-h]               : contains this Help
+	EOF
+}
+
+# $1 contains the directory to be tested
+# Is/Are .vcf file(s) present?
+function TST_VCF {
+	local j
+	for j in "${1%%/}/"* ; do
+		if [ "${j##*.}" = "vcf" ] ; then
+			return 0
+			break
+		fi
+	done
+	return 1
+}
+
+# $1 contains the util name
+# Is $1 already installed?
+function TST_UTIL {
+	which "$1" >/dev/null 2>&1
+	if [ "$?" != "0" ]; then
+		echo "[INSTALL] $1 utility not found, please install $1 package first!"
+		EXITING
+		exit 3
+	fi
+}
+
+# $1 contains the .vcf filename
+# extracts names from .vcf filename
+function EXTRACT_CONTACT_FROM_VCF {
+	local NAME="UNKNOWN"
+	if [ -e "$1" ] ; then
+		NAME=$(grep "fn:" "$1")
+		NAME=${NAME:3}
+	fi
+	echo "$NAME"
+}
+
+function DELETE_VCFILE_FROM_IPOD {
+	# if no .vcf file's found, exit!
+	if ! TST_VCF "$IPOD_MOUNT"/Contacts/ ; then
+		echo "[DELETING] no file detected"
+		return
+	fi
+	# begin to delete
+	local i
+	for i in "$IPOD_MOUNT"/Contacts/*.vcf ; do
+		echo "[DELETING] " $(EXTRACT_CONTACT_FROM_VCF "$i") "from ${i##*/}"
+		rm -f "$i"
+	done
+}
+
+# Is Ipod Directory valid?
+function IS_IPOD_DIR_VALID {
+	# Test of the $IPOD_MOUNT directory
+	if [ ! -d "$IPOD_MOUNT/Contacts/" ]; then
+		echo "$IPOD_MOUNT/Contacts invalid... Exiting."
+		EXITING
+		exit 2
+	fi
+}
+
+# Program's starting here!
+
+# Testing awk and iconv utils...
+TST_UTIL "awk"
+TST_UTIL "iconv"
+
+# picking up and processing parameters from prompt...
+while getopts ":f:m:n:dh:" option ; do
+	case $option in
+		f )	LDIFILE="$OPTARG";;
+		m )     IPOD_MOUNT="${OPTARG%%/}";;
+		n )	LDIFAMILYNAME="$OPTARG";;
+		d )	DELETE="OK";;
+		h | * )	DISPLAY_HELP; EXITING; exit 1;;
+	esac
+done
+
+# check, if not valid, exit!
+IS_IPOD_DIR_VALID
+
+# Is LDIFILE really a ldif file? just testing the extension, and if the file exists...
+if [ "${LDIFILE##*.}" == "ldif" ] || [ "${LDIFILE##*.}" == "LDIF" ] && [ -e "$LDIFILE" ] ; then
+	# The $IPOD_MOUNT/Contacts/ directory will be emptied if '-d' option!
+	if [ "$DELETE" == "OK" ]; then
+		echo "Old contacts being deleted from $IPOD_MOUNT. Work in progress..."
+		DELETE_VCFILE_FROM_IPOD
+		sleep 1
+	fi
+
+	echo "New contacts being synchronised from $LDIFILE. Work in progress..."
+	# Translation from LDIF into VCF, in order to cut standard output in vcf files...
+	# Converting into vcf stream | converting to ENCODING | detection of VCF card
+	#							and writing it into the Ipod
+	ldif2vcf.sh < "$LDIFILE" | iconv -f UTF-8 -t $ENCODING | awk 'BEGIN{RS="\n"; NAME=""; CARD=""; VCFILE=""; NCARD=1} /^fn:/ {NAME=substr($0,4)} /^$/{next} /^end:vcard/ {VCFILE = ENVIRON["IPOD_MOUNT"] "/Contacts/" ENVIRON["LDIFAMILYNAME"] (NCARD-1) ".vcf"; print "[WRITING] " NAME " in " ENVIRON["LDIFAMILYNAME"] (NCARD-1) ".vcf"; print CARD "end:vcard" > VCFILE; CARD=""; VCFILE=""; NCARD++; next} {CARD=CARD $0 RS} END{print (NCARD-1) " vcards added."}' # >/dev/null 2>&1
+
+	if [ "$?" != "0" ]; then
+		echo "[ERROR] An error occured, exiting, sorry for that... Please Report!"
+		EXITING
+		exit 1
+	fi
+	echo "complete!"
+else
+	DISPLAY_HELP
+fi
+
+EXITING
+exit 0

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh
===================================================================
--- gtkpod/trunk/scripts/sync-thunderbird-nano.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,97 +0,0 @@
-#!/bin/sh
-#
-# Script for syncing thunderbird addressbook data with iPod Nano
-#
-# It appears as if the old iPod Nano firmware only displayed the first
-# entry of a vcf file (the issue doesn't seem to exist with current
-# versions of the firmware). This script writes one vcf file per
-# address in your address book and could therefore also be useful
-# non-Nano users.
-#
-# (c) 2006 Paul Oremland <paul at oremland dot net>
-
-# Usage:
-# 
-# sync-thunderbird-nano.sh [-i <ipod mountpoint>] [-e <encoding>]
-#                      [-d <path to thunderbird address book>]
-#                      [-n <name of exported file>]
-#
-# specify '-d' if your thunderbird address book is not in
-# ~/.thunderbird/
-#
-# specify '-n' if you want to export more than one address book
-# (otherwise the second call to this script will overwrite the output
-# of the first call)
-
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod         # mountpoint of ipod
-ENCODING=ISO-8859-15         # encoding used by ipod
-NAME=thunderbird             # default file export name
-FILE_FLAG=''		     # flag used to determine end of file
-let COUNT=0;		     # file counter
-
-# Unless called with "-e=none" this script requires "recode" available
-# from ftp://ftp.iro.umontreal.ca/pub/recode/recode-3.6.tar.gz
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calender files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2006/04/10 (Paul Oremland <paul at oremland dot net>):
-# break vcf file out into individual vcf files per contact
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e:n: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) THUNPATH=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-	n) NAME=$OPTARG;;
-        
-        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to thunderbird address book>] [-n <name of exported file>]"
-	    exit 1;;
-    esac
-done
-
-
-echo "Exporting Contacts:"
-SYNC="$(dirname $0)/sync-thunderbird.sh -i ${IPOD_MOUNT} -e ${ENCODING} -d ${THUNPATH} -n ${NAME}"
-$SYNC
-
-echo "Breaking apart VCF file into individual contacts"
-for line in $(cat $IPOD_MOUNT/Contacts/${NAME}.vcf | sed "s/\ /[54321]/g")
-do
-	if [ "$FILE_FLAG" = 'END' ]; then
-		let COUNT=$COUNT+1;
-	fi
-
-	echo $line | sed "s/\[54321\]/\ /g" >> $IPOD_MOUNT/Contacts/${NAME}$COUNT.vcf
-
-	if [ "$line" = 'END:VCARD' ]; then
-		echo "Finished Writing ${NAME}$COUNT.vcf"
-		FILE_FLAG="END";
-	else
-		FILE_FLAG='';
-	fi
-done
-
-echo "Removing ${NAME}.vcf"
-rm $IPOD_MOUNT/Contacts/${NAME}.vcf

Copied: gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh (from rev 266, gtkpod/trunk/scripts/sync-thunderbird-nano.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-thunderbird-nano.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,97 @@
+#!/bin/sh
+#
+# Script for syncing thunderbird addressbook data with iPod Nano
+#
+# It appears as if the old iPod Nano firmware only displayed the first
+# entry of a vcf file (the issue doesn't seem to exist with current
+# versions of the firmware). This script writes one vcf file per
+# address in your address book and could therefore also be useful
+# non-Nano users.
+#
+# (c) 2006 Paul Oremland <paul at oremland dot net>
+
+# Usage:
+# 
+# sync-thunderbird-nano.sh [-i <ipod mountpoint>] [-e <encoding>]
+#                      [-d <path to thunderbird address book>]
+#                      [-n <name of exported file>]
+#
+# specify '-d' if your thunderbird address book is not in
+# ~/.thunderbird/
+#
+# specify '-n' if you want to export more than one address book
+# (otherwise the second call to this script will overwrite the output
+# of the first call)
+
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
+ENCODING=ISO-8859-15         # encoding used by ipod
+NAME=thunderbird             # default file export name
+FILE_FLAG=''		     # flag used to determine end of file
+let COUNT=0;		     # file counter
+
+# Unless called with "-e=none" this script requires "recode" available
+# from ftp://ftp.iro.umontreal.ca/pub/recode/recode-3.6.tar.gz
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calender files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2006/04/10 (Paul Oremland <paul at oremland dot net>):
+# break vcf file out into individual vcf files per contact
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e:n: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) THUNPATH=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+	n) NAME=$OPTARG;;
+        
+        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to thunderbird address book>] [-n <name of exported file>]"
+	    exit 1;;
+    esac
+done
+
+
+echo "Exporting Contacts:"
+SYNC="$(dirname $0)/sync-thunderbird.sh -i ${IPOD_MOUNT} -e ${ENCODING} -d ${THUNPATH} -n ${NAME}"
+$SYNC
+
+echo "Breaking apart VCF file into individual contacts"
+for line in $(cat $IPOD_MOUNT/Contacts/${NAME}.vcf | sed "s/\ /[54321]/g")
+do
+	if [ "$FILE_FLAG" = 'END' ]; then
+		let COUNT=$COUNT+1;
+	fi
+
+	echo $line | sed "s/\[54321\]/\ /g" >> $IPOD_MOUNT/Contacts/${NAME}$COUNT.vcf
+
+	if [ "$line" = 'END:VCARD' ]; then
+		echo "Finished Writing ${NAME}$COUNT.vcf"
+		FILE_FLAG="END";
+	else
+		FILE_FLAG='';
+	fi
+done
+
+echo "Removing ${NAME}.vcf"
+rm $IPOD_MOUNT/Contacts/${NAME}.vcf

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh
===================================================================
--- gtkpod/trunk/scripts/sync-thunderbird.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,87 +0,0 @@
-#!/bin/sh
-# Script for syncing thunderbird addressbook data with iPod
-# (c) 2004 Clinton Gormley <clint at traveljury dot com>
-#
-
-# Usage:
-# 
-# sync-thunderbird.sh [-i <ipod mountpoint>] [-e <encoding>]
-#                      [-d <path to thunderbird address book>]
-#                      [-n <name of exported file>]
-#
-# specify '-d' if your thunderbird address book is not in
-# ~/.thunderbird/
-#
-# specify '-n' if you want to export more than one address book
-# (otherwise the second call to this script will overwrite the output
-# of the first call)
-
-# with the following defaults: 
-
-IPOD_MOUNT=/media/ipod         # mountpoint of ipod
-ENCODING=ISO-8859-15         # encoding used by ipod
-NAME=thunderbird             # default file export name
-
-# Unless called with "-e=none" this script requires "recode" available
-# from ftp://ftp.iro.umontreal.ca/pub/recode/recode-3.6.tar.gz
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calender files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-
-# Changelog:
-#
-# 2005/05/18 (Clinton Gormley <clint at traveljury dot com>):
-# adapted sync-kaddressbook to work with thunderbird.
-#
-# 2004/12/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Split evolution support into a new file.
-#
-# 2005/06/23 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# use 'iconv' instead of 'recode'
-
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:e:n: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) THUNPATH=$OPTARG;;
-        e) ENCODING=$OPTARG;;
-	n) NAME=$OPTARG;;
-        
-        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to thunderbird address book>] [-n <name of exported file>]"
-	    exit 1;;
-    esac
-done
-
-
-# set the RECODE command
-if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
-    RECODE="cat"    # no conversion
-else
-    RECODE="iconv -f UTF-8 -t $ENCODING"
-fi
-
-
-echo "Trying to export from thunderbird:"
-
-MAB2VCARD=`dirname $0`/mab2vcard
-
-# remove all empty lines and recode if necessary
-echo -n "Syncing iPod ... [Contacts] "
-$MAB2VCARD $THUNPATH | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Contacts/${NAME}.vcf
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh (from rev 266, gtkpod/trunk/scripts/sync-thunderbird.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-thunderbird.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Script for syncing thunderbird addressbook data with iPod
+# (c) 2004 Clinton Gormley <clint at traveljury dot com>
+#
+
+# Usage:
+# 
+# sync-thunderbird.sh [-i <ipod mountpoint>] [-e <encoding>]
+#                      [-d <path to thunderbird address book>]
+#                      [-n <name of exported file>]
+#
+# specify '-d' if your thunderbird address book is not in
+# ~/.thunderbird/
+#
+# specify '-n' if you want to export more than one address book
+# (otherwise the second call to this script will overwrite the output
+# of the first call)
+
+# with the following defaults: 
+
+IPOD_MOUNT=/mnt/ipod         # mountpoint of ipod
+ENCODING=ISO-8859-15         # encoding used by ipod
+NAME=thunderbird             # default file export name
+
+# Unless called with "-e=none" this script requires "recode" available
+# from ftp://ftp.iro.umontreal.ca/pub/recode/recode-3.6.tar.gz
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calender files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+
+# Changelog:
+#
+# 2005/05/18 (Clinton Gormley <clint at traveljury dot com>):
+# adapted sync-kaddressbook to work with thunderbird.
+#
+# 2004/12/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Split evolution support into a new file.
+#
+# 2005/06/23 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# use 'iconv' instead of 'recode'
+
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:e:n: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) THUNPATH=$OPTARG;;
+        e) ENCODING=$OPTARG;;
+	n) NAME=$OPTARG;;
+        
+        \?) echo "Usage: `basename $0 ` [-i <ipod mountpoint>] [-e <encoding>] [-d <path to thunderbird address book>] [-n <name of exported file>]"
+	    exit 1;;
+    esac
+done
+
+
+# set the RECODE command
+if [ $ENCODING = "none" ] || [ $ENCODING = "NONE" ]; then
+    RECODE="cat"    # no conversion
+else
+    RECODE="iconv -f UTF-8 -t $ENCODING"
+fi
+
+
+echo "Trying to export from thunderbird:"
+
+MAB2VCARD=`dirname $0`/mab2vcard
+
+# remove all empty lines and recode if necessary
+echo -n "Syncing iPod ... [Contacts] "
+$MAB2VCARD $THUNPATH | grep -v '^[[:space:]]$\|^$' | $RECODE > $IPOD_MOUNT/Contacts/${NAME}.vcf
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh
===================================================================
--- gtkpod/trunk/scripts/sync-webcalendar.sh	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,63 +0,0 @@
-#!/bin/sh
-# (c) 2005 Daniel Kercher
-# sync ipod with webcalendar
-
-# Usage:
-#
-# sync-webcalendar.sh [-i <ipod mountpoint>] [-d <webcalendar uri>] [-c <calendar name>]
-#
-# with the following defaults:
-
-# mount point of ipod
-IPOD_MOUNT='/media/ipod'
-# uri for webcalendar (example)
-DATAFILE='https://somewhere.local/calendar.ics'
-# calendar name
-CALENDAR='webcalendar'
-# special options for wget
-WGET_OPTIONS='--no-check-certificate'
-
-# About the encoding used by the iPod (by Jorg Schuler):
-#
-# For some reason the encoding used for the contact files and
-# calenader files depends on the language you have set your iPod
-# to. If you set your iPod to German, iso-8859-15 (or -1?) is
-# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
-# to reboot the iPod to have the change take effect, however. (I'm
-# using firmware version 1.3.)
-#
-# If you know of more encodings, please let me know, so they can be
-# added here:
-#
-# iPod language      encoding expected
-# ----------------------------------------
-# German             ISO-8859-15
-# Japanese           SHIFT-JIS
-
-# Changelog
-#
-# 2007/02/01 (Giray Devlet <giray at devlet.cc>): Multi Calendar Support
-#
-# 2005/06/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Received original script from Daniel Kercher and added command line
-# options
-#
-# 2007/05/31 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
-# Set a more reasonable default datafile.
-#
-# FIXME: some way to convert the character set
-
-# overwrite default settings with optional command line arguments
-while getopts i:d:c: option; do
-    case $option in
-        i) IPOD_MOUNT=$OPTARG;;
-        d) DATAFILE=$OPTARG;;
-        c) CALENDAR=$OPTARG;;
-        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <webcalendar uri>] [-c <calendar_name>]"
-            exit 1;;
-    esac
-done
-
-echo -n "Syncing Web Calendar \"${CALENDAR}\" to iPod... "
-wget -q $WGET_OPTIONS -O ${IPOD_MOUNT}/Calendars/${CALENDAR}.ics $DATAFILE
-echo "done!"

Copied: gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh (from rev 266, gtkpod/trunk/scripts/sync-webcalendar.sh)
===================================================================
--- gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/scripts/sync-webcalendar.sh	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,63 @@
+#!/bin/sh
+# (c) 2005 Daniel Kercher
+# sync ipod with webcalendar
+
+# Usage:
+#
+# sync-webcalendar.sh [-i <ipod mountpoint>] [-d <webcalendar uri>] [-c <calendar name>]
+#
+# with the following defaults:
+
+# mount point of ipod
+IPOD_MOUNT='/mnt/ipod'
+# uri for webcalendar (example)
+DATAFILE='https://somewhere.local/calendar.ics'
+# calendar name
+CALENDAR='webcalendar'
+# special options for wget
+WGET_OPTIONS='--no-check-certificate'
+
+# About the encoding used by the iPod (by Jorg Schuler):
+#
+# For some reason the encoding used for the contact files and
+# calenader files depends on the language you have set your iPod
+# to. If you set your iPod to German, iso-8859-15 (or -1?) is
+# expected. If you set it to Japanese, SHIFT-JIS is expected. You need
+# to reboot the iPod to have the change take effect, however. (I'm
+# using firmware version 1.3.)
+#
+# If you know of more encodings, please let me know, so they can be
+# added here:
+#
+# iPod language      encoding expected
+# ----------------------------------------
+# German             ISO-8859-15
+# Japanese           SHIFT-JIS
+
+# Changelog
+#
+# 2007/02/01 (Giray Devlet <giray at devlet.cc>): Multi Calendar Support
+#
+# 2005/06/15 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Received original script from Daniel Kercher and added command line
+# options
+#
+# 2007/05/31 (Jorg Schuler <jcsjcs at users dot sourceforge dot net>):
+# Set a more reasonable default datafile.
+#
+# FIXME: some way to convert the character set
+
+# overwrite default settings with optional command line arguments
+while getopts i:d:c: option; do
+    case $option in
+        i) IPOD_MOUNT=$OPTARG;;
+        d) DATAFILE=$OPTARG;;
+        c) CALENDAR=$OPTARG;;
+        \?) echo "Usage: `basename $0` [-i <ipod mountpoint>] [-d <webcalendar uri>] [-c <calendar_name>]"
+            exit 1;;
+    esac
+done
+
+echo -n "Syncing Web Calendar \"${CALENDAR}\" to iPod... "
+wget -q $WGET_OPTIONS -O ${IPOD_MOUNT}/Calendars/${CALENDAR}.ics $DATAFILE
+echo "done!"

Deleted: gtkpod/tags/0.99.10-5/src/mp3file.c
===================================================================
--- gtkpod/trunk/src/mp3file.c	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/src/mp3file.c	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,2678 +0,0 @@
-/* Time-stamp: <2007-06-26 00:39:11 jcs>
-|
-|  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
-|  Part of the gtkpod project.
-| 
-|  URL: http://www.gtkpod.org/
-|  URL: http://gtkpod.sourceforge.net/
-|
-|  This program is free software; you can redistribute it and/or modify
-|  it under the terms of the GNU General Public License as published by
-|  the Free Software Foundation; either version 2 of the License, or
-|  (at your option) any later version.
-|
-|  This program is distributed in the hope that it will be useful,
-|  but WITHOUT ANY WARRANTY; without even the implied warranty of
-|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-|  GNU General Public License for more details.
-|
-|  You should have received a copy of the GNU General Public License
-|  along with this program; if not, write to the Free Software
-|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-|
-|  iTunes and iPod are trademarks of Apple
-|
-|  This product is not supported/written/published by Apple!
-|
-|  $Id: mp3file.c 1591 2007-06-26 03:33:25Z tmzullinger $
-*/
-
-
-#define LOCALDEBUG 0
-
-
-/* The code in the first section of this file is taken from the
- * mp3info (http://www.ibiblio.org/mp3info/) project. Only the code
- * needed for the playlength calculation has been extracted. */
-
-/* The code in the second section of this file is taken from the
- * mpg123 code used in xmms-1.2.7 (Input/mpg123). Only the code needed
- * for the playlength calculation has been extracted. */
-
-/* The code in the last section of this file is original gtkpod
- * code. */
-
-/****************
- * Declarations *
- ****************/
-
-#include <glib.h>
-#include <math.h>
-/*
- * Description of each item of the TagList list
- */
-typedef struct _File_Tag File_Tag;
-typedef struct _GainData GainData;
-typedef struct _GaplessData GaplessData;
-
-struct _File_Tag
-{
-    gchar *title;          /* Title of track */
-    gchar *artist;         /* Artist name */
-    gchar *album;          /* Album name */
-    gchar *year;           /* Year of track */
-    gchar *trackstring;    /* Position of track in the album */
-    gchar *track_total;    /* The number of tracks for the album (ex: 12/20) */
-    gchar *genre;          /* Genre of song */
-    gchar *comment;        /* Comment */
-    gchar *composer;	   /* Composer */
-    guint32 songlen;       /* Length of file in ms */
-    gchar *cdnostring;    /* Position of disc in the album */
-    gchar *cdno_total;    /* The number of discs in the album (ex: 1/2) */
-    gchar *compilation;   /* The track is a member of a compilation */
-    gchar *podcasturl;    /* The following are mainly used for podcasts */
-    gchar *sort_artist;
-    gchar *sort_title;
-    gchar *sort_album;
-    gchar *sort_albumartist;
-    gchar *sort_composer;
-    gchar *description;
-    gchar *podcastrss;
-    gchar *time_released;
-    gchar *subtitle;
-    gchar *BPM;           /* beats per minute */
-    gchar *lyrics;        /* does not appear to be the full lyrics --
-			     only used to set the flag 'lyrics_flag'
-			     of the Track structure */
-};
-
-
-struct _GainData
-{
-  guint32 peak_signal;	  /* LAME Peak Signal * 0x800000             */
-  gdouble radio_gain;	  /* RadioGain in dB
-			     (as defined by www.replaygain.org)      */
-  gdouble audiophile_gain;/* AudiophileGain in dB 
-			     (as defined by www.replaygain.org)      */
-  gboolean peak_signal_set;    /* has the peak signal been set?      */
-  gboolean radio_gain_set;     /* has the radio gain been set?       */
-  gboolean audiophile_gain_set;/* has the audiophile gain been set?  */
-};
-
-struct _GaplessData
-{
-    guint32 pregap;       /* number of pregap samples */
-    guint64 samplecount;  /* number of actual music samples */
-    guint32 postgap;      /* number of postgap samples */
-    guint32 gapless_data; /* number of bytes from the first sync frame to the 8th to last frame */
-};
-
-/* This code is taken from the mp3info code. Only the code needed for
- * the playlength calculation has been extracted */
-
-/*
-    mp3tech.c - Functions for handling MP3 files and most MP3 data
-		structure manipulation.
-
-    Copyright (C) 2000-2001  Cedric Tefft <cedric at earthling.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  ***************************************************************************
-
-  This file is based in part on:
-
-	* MP3Info 0.5 by Ricardo Cerqueira <rmc at rccn.net>
-	* MP3Stat 0.9 by Ed Sweetman <safemode at voicenet.com> and
-			 Johannes Overmann <overmann at iname.com>
-
-*/
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mp3file.h"
-#include "charset.h"
-#include "itdb.h"
-#include "file.h"
-#include "misc.h"
-
-
-/* MIN_CONSEC_GOOD_FRAMES defines how many consecutive valid MP3 frames
-   we need to see before we decide we are looking at a real MP3 file */
-#define MIN_CONSEC_GOOD_FRAMES 4
-#define FRAME_HEADER_SIZE 4
-#define MIN_FRAME_SIZE 21
-
-enum VBR_REPORT { VBR_VARIABLE, VBR_AVERAGE, VBR_MEDIAN };
-
-typedef struct {
-    gulong sync;
-    guint  version;
-    guint  layer;
-    guint  crc;
-    guint  bitrate;
-    guint  freq;
-    guint  padding;
-    guint  extension;
-    guint  mode;
-    guint  mode_extension;
-    guint  copyright;
-    guint  original;
-    guint  emphasis;
-} MP3Header;
-
-typedef struct {
-    gchar *filename;
-    FILE *file;
-    off_t datasize;
-    gint header_isvalid;
-    MP3Header header;
-    gint id3_isvalid;
-    gint vbr;
-    float vbr_average;
-    gint milliseconds;
-    gint frames;
-    gint badframes;
-} MP3Info;
-
-/* This is for xmms code */
-static guint get_track_time(gchar *path);
-
-
-
-/* ------------------------------------------------------------
-
-   start of first section
-
-   ------------------------------------------------------------ */
-void get_mp3_info(MP3Info *mp3);
-
-gint frequencies[3][4] = {
-   {22050,24000,16000,50000},  /* MPEG 2.0 */
-   {44100,48000,32000,50000},  /* MPEG 1.0 */
-   {11025,12000,8000,50000}    /* MPEG 2.5 */
-};
-
-/* "0" added by JCS */
-gint bitrate[2][3][16] = {
-  { /* MPEG 2.0 */
-    {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},/* layer 1 */
-    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},     /* layer 2 */
-    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}      /* layer 3 */
-  },
-
-  { /* MPEG 1.0 */
-    {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},/* layer 1 */
-    {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},   /* layer 2 */
-    {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}     /* layer 3 */
-  }
-};
-
-gint frame_size_index[] = {24000, 72000, 72000};
-
-
-gchar *mode_text[] = {
-   "stereo", "joint stereo", "dual channel", "mono"
-};
-
-gchar *emphasis_text[] = {
-  "none", "50/15 microsecs", "reserved", "CCITT J 17"
-};
-
-
-static gint mp3file_header_bitrate(MP3Header *h) {
-    return bitrate[h->version & 1][3-h->layer][h->bitrate];
-}
-
-
-static gint mp3file_header_frequency(MP3Header *h) {
-    return frequencies[h->version][h->freq];
-}
-
-
-gint frame_length(MP3Header *header) {
-	return header->sync == 0xFFE ?
-		    (frame_size_index[3-header->layer]*((header->version&1)+1)*
-		    mp3file_header_bitrate(header)/(float)mp3file_header_frequency(header))+
-		    header->padding : 1;
-}
-
-/* Get next MP3 frame header.
-   Return codes:
-   positive value = Frame Length of this header
-   0 = No, we did not retrieve a valid frame header
-*/
-gint get_header(FILE *file,MP3Header *header)
-{
-    guchar buffer[FRAME_HEADER_SIZE];
-    gint fl;
-
-    if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
-	header->sync=0;
-	return 0;
-    }
-    header->sync=(((gint)buffer[0]<<4) | ((gint)(buffer[1]&0xE0)>>4));
-    if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
-		    else header->version=2;
-    header->layer=(buffer[1] >> 1) & 3;
-    if (header->layer == 0)
-    {
-	header->layer = 1; /* sanity added by JCS */
-    }
-    if((header->sync != 0xFFE) || (header->layer != 1)) {
-	header->sync=0;
-	return 0;
-    }
-    header->crc=buffer[1] & 1;
-    header->bitrate=(buffer[2] >> 4) & 0x0F;
-    header->freq=(buffer[2] >> 2) & 0x3;
-    header->padding=(buffer[2] >>1) & 0x1;
-    header->extension=(buffer[2]) & 0x1;
-    header->mode=(buffer[3] >> 6) & 0x3;
-    header->mode_extension=(buffer[3] >> 4) & 0x3;
-    header->copyright=(buffer[3] >> 3) & 0x1;
-    header->original=(buffer[3] >> 2) & 0x1;
-    header->emphasis=(buffer[3]) & 0x3;
-
-    return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0);
-}
-
-gint sameConstant(MP3Header *h1, MP3Header *h2) {
-    if((*(guint*)h1) == (*(guint*)h2)) return 1;
-
-    if((h1->version       == h2->version         ) &&
-       (h1->layer         == h2->layer           ) &&
-       (h1->crc           == h2->crc             ) &&
-       (h1->freq          == h2->freq            ) &&
-       (h1->mode          == h2->mode            ) &&
-       (h1->copyright     == h2->copyright       ) &&
-       (h1->original      == h2->original        ) &&
-       (h1->emphasis      == h2->emphasis        ))
-		return 1;
-    else return 0;
-}
-
-
-gint get_first_header(MP3Info *mp3, long startpos)
-{
-  gint k, l=0,c;
-  MP3Header h, h2;
-  long valid_start=0;
-
-  fseek(mp3->file,startpos,SEEK_SET);
-  while (1) {
-     while((c=fgetc(mp3->file)) != 255 && (c != EOF));
-     if(c == 255) {
-	ungetc(c,mp3->file);
-	valid_start=ftell(mp3->file);
-	if((l=get_header(mp3->file,&h))) {
-	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
-	    if(!(l=get_header(mp3->file,&h2))) break;
-	    if(!sameConstant(&h,&h2)) break;
-	    fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  }
-	  if(k == MIN_CONSEC_GOOD_FRAMES) {
-		fseek(mp3->file,valid_start,SEEK_SET);
-		memcpy(&(mp3->header),&h2,sizeof(MP3Header));
-		mp3->header_isvalid=1;
-		return 1;
-	  }
-	}
-     } else {
-	return 0;
-     }
-   }
-
-  return 0;
-}
-
-
-/* get_next_header() - read header at current position or look for
-   the next valid header if there isn't one at the current position
-*/
-gint get_next_header(MP3Info *mp3)
-{
-  gint l=0,c,skip_bytes=0;
-  MP3Header h;
-
-   while(1) {
-     while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
-     if(c == 255) {
-	ungetc(c,mp3->file);
-	if((l=get_header(mp3->file,&h))) {
-	  if(skip_bytes) mp3->badframes++;
-	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
-	  return 15-h.bitrate;
-	} else {
-		skip_bytes += FRAME_HEADER_SIZE;
-	}
-     } else {
-	  if(skip_bytes) mp3->badframes++;
-	  return 0;
-     }
-  }
-}
-
-
-void get_mp3_info(MP3Info *mp3)
-{
-  gint frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-  float milliseconds=0,total_rate=0;
-  gint frames=0,frame_types=0,frames_so_far=0;
-  gint vbr_median=-1;
-  guint bitrate;
-  gint counter=0;
-  MP3Header header;
-  struct stat filestat;
-  off_t data_start=0;
-
-
-  stat(mp3->filename,&filestat);
-  mp3->datasize=filestat.st_size;
-
-  if(get_first_header(mp3,0L)) {
-      data_start=ftell(mp3->file);
-      while((bitrate=get_next_header(mp3))) {
-	  if (bitrate < 15)  /* sanity added by JCS */
-	      frame_type[15-bitrate]++;
-	  frames++;
-      }
-      memcpy(&header,&(mp3->header),sizeof(MP3Header));
-      for(counter=0;counter<15;counter++) {
-	  if(frame_type[counter]) {
-	      float header_bitrate; /* introduced by JCS to speed up */
-	      frame_types++;
-	      header.bitrate=counter;
-	      frames_so_far += frame_type[counter];
-	      header_bitrate = mp3file_header_bitrate(&header);
-	      if (header_bitrate != 0)
-		  milliseconds += (float)(8*frame_length(&header)*frame_type[counter])/header_bitrate;
-	      total_rate += header_bitrate*frame_type[counter];
-	      if((vbr_median == -1) && (frames_so_far >= frames/2))
-		  vbr_median=counter;
-	  }
-      }
-      mp3->milliseconds=(gint)(milliseconds+0.5);
-      mp3->header.bitrate=vbr_median;
-      mp3->vbr_average=total_rate/(float)frames;
-      mp3->frames=frames;
-      if(frame_types > 1) {
-	  mp3->vbr=1;
-      }
-  }
-}
-
-
-
-
-/* ------------------------------------------------------------
-
-	 xmms code
-
-
-   ------------------------------------------------------------ */
-
-/*
-|  Changed by Jorg Schuler <jcsjcs at users.sourceforge.net> to
-|  compile with the gtkpod project. 2003/04/01
-*/
-
-/* This code is taken from the mpg123 code used in xmms-1.2.7
- * (Input/mpg123). Only the code needed for the playlength calculation
- * has been extracted */
-
-#include "mp3file.h"
-#include <stdio.h>
-#include <string.h>
-
-#define FRAMES_FLAG     0x0001
-#define BYTES_FLAG      0x0002
-#define TOC_FLAG        0x0004
-#define VBR_SCALE_FLAG  0x0008
-
-#define         SBLIMIT                 32
-#define         SCALE_BLOCK             12
-#define         SSLIMIT                 18
-
-#define         MPG_MD_STEREO           0
-#define         MPG_MD_JOINT_STEREO     1
-#define         MPG_MD_DUAL_CHANNEL     2
-#define         MPG_MD_MONO             3
-#define MAXFRAMESIZE 1792
-#define real float
-
-struct bitstream_info
-{
-	int bitindex;
-	unsigned char *wordpointer;
-};
-
-struct bitstream_info bsi;
-
-real mpg123_muls[27][64];	/* also used by layer 1 */
-
-int tabsel_123[2][3][16] =
-{
-	{
-    {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
-       {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
-       {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
-
-	{
-       {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
-	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
-	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}}
-};
-
-long mpg123_freqs[9] =
-{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
-
-/*
- * structure to receive extracted header
- */
-typedef struct
-{
-	int frames;		/* total bit stream frames from Xing header data */
-	int bytes;		/* total bit stream bytes from Xing header data */
-	unsigned char toc[100];	/* "table of contents" */
-} xing_header_t;
-
-struct al_table
-{
-	short bits;
-	short d;
-};
-
-struct frame
-{
-	struct al_table *alloc;
-	int (*synth) (real *, int, unsigned char *, int *);
-	int (*synth_mono) (real *, unsigned char *, int *);
-#ifdef USE_3DNOW
-	void (*dct36)(real *,real *,real *,real *,real *);
-#endif
-	int stereo;
-	int jsbound;
-	int single;
-	int II_sblimit;
-	int down_sample_sblimit;
-	int lsf;
-	int mpeg25;
-	int down_sample;
-	int header_change;
-	int lay;
-	int (*do_layer) (struct frame * fr);
-	int error_protection;
-	int bitrate_index;
-	int sampling_frequency;
-	int padding;
-	int extension;
-	int mode;
-	int mode_ext;
-	int copyright;
-	int original;
-	int emphasis;
-	int framesize;		/* computed framesize */
-};
-
-static guint32 convert_to_header(guint8 * buf)
-{
-
-	return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
-}
-
-static int mpg123_head_check(unsigned long head)
-{
-	if ((head & 0xffe00000) != 0xffe00000)
-		return FALSE;
-	if (!((head >> 17) & 3))
-		return FALSE;
-	if (((head >> 12) & 0xf) == 0xf)
-		return FALSE;
-	if (!((head >> 12) & 0xf))
-		return FALSE;
-	if (((head >> 10) & 0x3) == 0x3)
-		return FALSE;
-	if (((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
-		return FALSE;
-	if ((head & 0xffff0000) == 0xfffe0000)
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/*
- * the code a header and write the information
- * into the frame structure
- */
-static int mpg123_decode_header(struct frame *fr, unsigned long newhead)
-{
-    int ssize;
-
-	if (newhead & (1 << 20))
-	{
-		fr->lsf = (newhead & (1 << 19)) ? 0x0 : 0x1;
-		fr->mpeg25 = 0;
-	}
-	else
-	{
-		fr->lsf = 1;
-		fr->mpeg25 = 1;
-	}
-	fr->lay = 4 - ((newhead >> 17) & 3);
-	if (fr->mpeg25)
-	{
-		fr->sampling_frequency = 6 + ((newhead >> 10) & 0x3);
-	}
-	else
-		fr->sampling_frequency = ((newhead >> 10) & 0x3) + (fr->lsf * 3);
-	fr->error_protection = ((newhead >> 16) & 0x1) ^ 0x1;
-
-	fr->bitrate_index = ((newhead >> 12) & 0xf);
-	fr->padding = ((newhead >> 9) & 0x1);
-	fr->extension = ((newhead >> 8) & 0x1);
-	fr->mode = ((newhead >> 6) & 0x3);
-	fr->mode_ext = ((newhead >> 4) & 0x3);
-	fr->copyright = ((newhead >> 3) & 0x1);
-	fr->original = ((newhead >> 2) & 0x1);
-	fr->emphasis = newhead & 0x3;
-
-	fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
-
-	ssize = 0;
-
-	if (!fr->bitrate_index)
-		return (0);
-
-	switch (fr->lay)
-	{
-		case 1:
-/*			fr->do_layer = mpg123_do_layer1; */
-/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
-			fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
-			fr->framesize = ((fr->framesize + fr->padding) << 2) - 4;
-			break;
-		case 2:
-/*			fr->do_layer = mpg123_do_layer2; */
-/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
-			fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
-			fr->framesize += fr->padding - 4;
-			break;
-		case 3:
-/*			fr->do_layer = mpg123_do_layer3; */
-			if (fr->lsf)
-				ssize = (fr->stereo == 1) ? 9 : 17;
-			else
-				ssize = (fr->stereo == 1) ? 17 : 32;
-			if (fr->error_protection)
-				ssize += 2;
-			fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
-			fr->framesize /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			fr->framesize = fr->framesize + fr->padding - 4;
-			break;
-		default:
-			return (0);
-	}
-	if(fr->framesize > MAXFRAMESIZE)
-		return 0;
-	return 1;
-}
-
-#define GET_INT32BE(b) \
-(i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i)
-
-static int mpg123_get_xing_header(xing_header_t * xing, unsigned char *buf)
-{
-	int i, head_flags;
-	int id, mode;
-
-	memset(xing, 0, sizeof(xing_header_t));
-
-	/* get selected MPEG header data */
-	id = (buf[1] >> 3) & 1;
-	mode = (buf[3] >> 6) & 3;
-	buf += 4;
-
-	/* Skip the sub band data */
-	if (id)
-	{
-		/* mpeg1 */
-		if (mode != 3)
-			buf += 32;
-		else
-			buf += 17;
-	}
-	else
-	{
-		/* mpeg2 */
-		if (mode != 3)
-			buf += 17;
-		else
-			buf += 9;
-	}
-
-	if (strncmp(buf, "Xing", 4))
-		return 0;
-	buf += 4;
-
-	head_flags = GET_INT32BE(buf);
-
-	if (head_flags & FRAMES_FLAG)
-		xing->frames = GET_INT32BE(buf);
-	if (xing->frames < 1)
-		xing->frames = 1;
-	if (head_flags & BYTES_FLAG)
-		xing->bytes = GET_INT32BE(buf);
-
-	if (head_flags & TOC_FLAG)
-	{
-		for (i = 0; i < 100; i++)
-			xing->toc[i] = buf[i];
-		buf += 100;
-	}
-
-#ifdef XING_DEBUG
-	for (i = 0; i < 100; i++)
-	{
-		if ((i % 10) == 0)
-			fprintf(stderr, "\n");
-		fprintf(stderr, " %3d", xing->toc[i]);
-	}
-#endif
-
-	return 1;
-}
-
-static double mpg123_compute_tpf(struct frame *fr)
-{
-	const int bs[4] = {0, 384, 1152, 1152};
-	double tpf;
-
-	tpf = bs[fr->lay];
-	tpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-	return tpf;
-}
-
-static double mpg123_compute_bpf(struct frame *fr)
-{
-	double bpf;
-
-	switch (fr->lay)
-	{
-		case 1:
-			bpf = tabsel_123[fr->lsf][0][fr->bitrate_index];
-			bpf *= 12000.0 * 4.0;
-			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			break;
-		case 2:
-		case 3:
-			bpf = tabsel_123[fr->lsf][fr->lay - 1][fr->bitrate_index];
-			bpf *= 144000;
-			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
-			break;
-		default:
-			bpf = 1.0;
-	}
-
-	return bpf;
-}
-
-
-unsigned int mpg123_getbits(int number_of_bits)
-{
-	unsigned long rval;
-
-#ifdef DEBUG_GETBITS
-	fprintf(stderr, "g%d", number_of_bits);
-#endif
-
-	if(!number_of_bits)
-		return 0;
-
-#if 0
-	check_buffer_range(number_of_bits + bsi.bitindex);
-#endif
-
-	{
-		rval = bsi.wordpointer[0];
-		rval <<= 8;
-		rval |= bsi.wordpointer[1];
-		rval <<= 8;
-		rval |= bsi.wordpointer[2];
-
-		rval <<= bsi.bitindex;
-		rval &= 0xffffff;
-
-		bsi.bitindex += number_of_bits;
-
-		rval >>= (24-number_of_bits);
-
-		bsi.wordpointer += (bsi.bitindex >> 3);
-		bsi.bitindex &= 7;
-	}
-
-#ifdef DEBUG_GETBITS
-	fprintf(stderr,":%x ",rval);
-#endif
-
-	return rval;
-}
-
-
-void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT], struct frame *fr)
-{
-	unsigned int *ba = balloc;
-	unsigned int *sca = (unsigned int *) scale_index;
-
-	if (fr->stereo)
-	{
-		int i;
-		int jsbound = fr->jsbound;
-
-		for (i = 0; i < jsbound; i++)
-		{
-			*ba++ = mpg123_getbits(4);
-			*ba++ = mpg123_getbits(4);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			*ba++ = mpg123_getbits(4);
-
-		ba = balloc;
-
-		for (i = 0; i < jsbound; i++)
-		{
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			if ((*ba++))
-			{
-				*sca++ = mpg123_getbits(6);
-				*sca++ = mpg123_getbits(6);
-			}
-	}
-	else
-	{
-		int i;
-
-		for (i = 0; i < SBLIMIT; i++)
-			*ba++ = mpg123_getbits(4);
-		ba = balloc;
-		for (i = 0; i < SBLIMIT; i++)
-			if ((*ba++))
-				*sca++ = mpg123_getbits(6);
-	}
-}
-
-void I_step_two(real fraction[2][SBLIMIT], unsigned int balloc[2 * SBLIMIT],
-		unsigned int scale_index[2][SBLIMIT], struct frame *fr)
-{
-	int i, n;
-	int smpb[2 * SBLIMIT];	/* values: 0-65535 */
-	int *sample;
-	register unsigned int *ba;
-	register unsigned int *sca = (unsigned int *) scale_index;
-
-	if (fr->stereo)
-	{
-		int jsbound = fr->jsbound;
-		register real *f0 = fraction[0];
-		register real *f1 = fraction[1];
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < jsbound; i++)
-		{
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < jsbound; i++)
-		{
-			if ((n = *ba++))
-				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f0++ = 0.0;
-			if ((n = *ba++))
-				*f1++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f1++ = 0.0;
-		}
-		for (i = jsbound; i < SBLIMIT; i++)
-		{
-			if ((n = *ba++))
-			{
-				real samp = (((-1) << n) + (*sample++) + 1);
-
-				*f0++ = samp * mpg123_muls[n + 1][*sca++];
-				*f1++ = samp * mpg123_muls[n + 1][*sca++];
-			}
-			else
-				*f0++ = *f1++ = 0.0;
-		}
-		for (i = fr->down_sample_sblimit; i < 32; i++)
-			fraction[0][i] = fraction[1][i] = 0.0;
-	}
-	else
-	{
-		register real *f0 = fraction[0];
-
-		ba = balloc;
-		for (sample = smpb, i = 0; i < SBLIMIT; i++)
-			if ((n = *ba++))
-				*sample++ = mpg123_getbits(n + 1);
-		ba = balloc;
-		for (sample = smpb, i = 0; i < SBLIMIT; i++)
-		{
-			if ((n = *ba++))
-				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
-			else
-				*f0++ = 0.0;
-		}
-		for (i = fr->down_sample_sblimit; i < 32; i++)
-			fraction[0][i] = 0.0;
-	}
-}
-
-static guint get_track_time_file(FILE * file)
-{
-	guint32 head;
-	guchar tmp[4], *buf;
-	struct frame frm;
-	xing_header_t xing_header;
-	double tpf, bpf;
-	guint32 len;
-
-	if (!file)
-		return -1;
-
-	fseek(file, 0, SEEK_SET);
-	if (fread(tmp, 1, 4, file) != 4)
-		return 0;
-	head = convert_to_header(tmp);
-	while (!mpg123_head_check(head))
-	{
-		head <<= 8;
-		if (fread(tmp, 1, 1, file) != 1)
-			return 0;
-		head |= tmp[0];
-	}
-	if (mpg123_decode_header(&frm, head))
-	{
-		buf = g_malloc(frm.framesize + 4);
-		fseek(file, -4, SEEK_CUR);
-		fread(buf, 1, frm.framesize + 4, file);
-		tpf = mpg123_compute_tpf(&frm);
-		if (mpg123_get_xing_header(&xing_header, buf))
-		{
-			g_free(buf);
-			return ((guint) (tpf * xing_header.frames * 1000));
-		}
-		g_free(buf);
-		bpf = mpg123_compute_bpf(&frm);
-		fseek(file, 0, SEEK_END);
-		len = ftell(file);
-		fseek(file, -128, SEEK_END);
-		fread(tmp, 1, 3, file);
-		if (!strncmp(tmp, "TAG", 3))
-			len -= 128;
-		return ((guint) ((guint)(len / bpf) * tpf * 1000));
-	}
-	return 0;
-}
-
-static guint get_track_time (gchar *path)
-{
-    guint result = 0;
-
-    if (path)
-    {
-	FILE *file = fopen (path, "r");
-	result = get_track_time_file (file);
-	if (file) fclose (file);
-    }
-    return result;
-}
-
-
-/* libid3tag stuff */
-
-#include <id3tag.h>
-#include "prefs.h"
-
-#ifndef ID3_FRAME_GROUP
-#define ID3_FRAME_GROUP "TPE2"
-#endif
-
-
-
-static const gchar* id3_get_binary (struct id3_tag *tag,
-				    char *frame_name,
-				    id3_length_t *len,
-				    int index)
-{
-    const id3_byte_t *binary = NULL;
-    struct id3_frame *frame;
-    union id3_field *field;
-
-    g_return_val_if_fail (len, NULL);
-
-    *len = 0;
-
-    frame = id3_tag_findframe (tag, frame_name, index);
-#if LOCALDEBUG
-    printf ("frame: %p\n", frame); 
-#endif
-
-    if (!frame) return NULL;
-
-#if LOCALDEBUG
-    printf (" nfields: %d\n", frame->nfields);
-    if (strncmp (frame_name, "APIC",  4) == 0)
-    {
-	field = id3_frame_field (frame, 2);
-	printf (" picture type: %ld\n", field->number.value);
-    }
-#endif
-
-
-#if 0
-/*-----------------*/
-/* just to show that this field (before last) contains the d8 ff e0 ff
-   part of the start of a jpeg file when the coverart war embedded by iTunes */
-
-    const id3_ucs4_t *string = NULL;
-    gchar *raw = NULL;
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-2);
-
-#if LOCALDEBUG
-     printf (" field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf (" type: %d\n", field->type);
-#endif
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_STRING:
-	string = id3_field_getstring (field);
-	break;
-    default:
-	break;
-    }
-  
-    /* ISO_8859_1 is just a "marker" -- most people just drop
-       whatever coding system they are using into it, so we use
-       charset_to_utf8() to convert to utf8 */
-
-    if (string)
-    {
-	raw = id3_ucs4_latin1duplicate (string);
-    }
-
-
-#if LOCALDEBUG
-    {
-	FILE *file;
-	printf (" string len: %d\n", raw?strlen(raw):0);
-	file = fopen ("/tmp/folder1.jpg", "w");
-	fwrite (raw, 1, raw?strlen(raw):0, file);
-	fclose (file);
-    }
-#endif
-    g_free (raw);
-
-/*-----------------*/
-#endif
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-1);
-
-#if LOCALDEBUG
-     printf (" field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf (" type: %d\n", field->type);
-#endif
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_BINARYDATA:
-	binary = id3_field_getbinarydata(field, len);
-	break;
-    default:
-	break;
-    }
-
-#if LOCALDEBUG
-    {
-	FILE *file;
-	printf (" binary len: %ld\n", *len);
-	file = fopen ("/tmp/folder2.jpg", "w");
-	fwrite (binary, 1, *len, file);
-	fclose (file);
-    }
-#endif
-
-
-
-    return binary;
-}
-
-
-
-static gchar* id3_get_string (struct id3_tag *tag, char *frame_name)
-{
-    const id3_ucs4_t *string = NULL;
-    const id3_byte_t *binary = NULL;
-    id3_length_t len = 0;
-    struct id3_frame *frame;
-    union id3_field *field;
-    gchar *utf8 = NULL;
-    enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
-
-    frame = id3_tag_findframe (tag, frame_name, 0);
-#if LOCALDEGUB
-    printf ("frame: %p\n", frame); 
-#endif
-
-    if (!frame) return NULL;
-
-    /* Find the encoding used for the field */
-    field = id3_frame_field (frame, 0);
-#if LOCALDEBUG
-    printf ("field: %p\n", field); 
-    printf ("type: %d\n", id3_field_type (field));
-#endif
-
-    if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
-    {
-	encoding = field->number.value;
-#if LOCALDEBUG
-	printf ("encoding: %d\n", encoding);
-#endif
-    }
-
-    /* The last field contains the data */
-    field = id3_frame_field (frame, frame->nfields-1);
-
-#if LOCALDEBUG
-     printf ("field: %p\n", field);
-#endif
-
-    if (!field) return NULL;
-
-#if LOCALDEBUG
-     printf ("type: %d\n", field->type);
-#endif
-
-
-    switch (field->type)
-    {
-    case ID3_FIELD_TYPE_STRINGLIST:
-	string = id3_field_getstrings (field, 0);
-	break;
-    case ID3_FIELD_TYPE_STRINGFULL:
-	string = id3_field_getfullstring (field);
-	break;
-    case ID3_FIELD_TYPE_BINARYDATA:
-	binary = id3_field_getbinarydata(field, &len);
-#if LOCALDEBUG
-	printf ("len: %ld\nbinary: %s\n", len, binary+1);
-#endif
-	if (len > 0)
-	    return charset_to_utf8 (binary+1);
-	break;
-    default:
-	break;
-    }
-
-/*     printf ("string: %p\n", string); */
-
-    if (!string) return NULL;
-
-    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
-       string = id3_genre_name (string);
-
-    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-    {
-	/* ISO_8859_1 is just a "marker" -- most people just drop
-	   whatever coding system they are using into it, so we use
-	   charset_to_utf8() to convert to utf8 */
-	id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
-	utf8 = charset_to_utf8 (raw);
-	g_free (raw);
-    }
-    else
-    {
-	/* Standard unicode is being used -- we won't have to worry
-	   about charsets then. */
-	utf8 = id3_ucs4_utf8duplicate (string);
-    }
-    return utf8;
-}
-
-static void id3_set_string (struct id3_tag *tag,
-			    const char *frame_name,
-			    const char *data,
-			    enum id3_field_textencoding encoding)
-{
-    int res;
-    struct id3_frame *frame;
-    union id3_field *field;
-    id3_ucs4_t *ucs4;
-
-    /* clear the frame, because of bug in libid3tag see
-       http://www.mars.org/mailman/public/mad-dev/2004-October/001113.html
-    */
-    while ((frame = id3_tag_findframe (tag, frame_name, 0)))
-    {
-	id3_tag_detachframe (tag, frame);
-        id3_frame_delete (frame);
-    }
-
-    if ((data == NULL) || (strlen(data) == 0))
-	return;
-
-    frame = id3_frame_new (frame_name);
-    id3_tag_attachframe (tag, frame);
-
-    /* Use the specified text encoding */
-    field = id3_frame_field (frame, 0);
-    id3_field_settextencoding(field, encoding);
-   
-    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
-    {
-	field = id3_frame_field (frame, 3);
-	field->type = ID3_FIELD_TYPE_STRINGFULL;
-    }
-    else
-    {
-	field = id3_frame_field (frame, 1);
-	field->type = ID3_FIELD_TYPE_STRINGLIST;
-    }
-
-
-    /* maybe could be optimized see
-       http://www.mars.org/mailman/public/mad-dev/2002-October/000739.html
-    */
-    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
-    {
-	id3_ucs4_t *tmp_ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
-	int index = id3_genre_number (tmp_ucs4);
-	if (index != -1)
-	{
-	    /* valid genre -- simply store the genre number */
-	    gchar *tmp = g_strdup_printf("%d", index);
-	    ucs4 = id3_latin1_ucs4duplicate (tmp);
-	    g_free (tmp);
-	}
-	else
-	{
-	    /* oups -- not a valid genre -- save the entire genre string */
-	    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-	    {
-		/* we read 'ISO_8859_1' to stand for 'any locale
-		   charset' -- most programs seem to work that way */
-		id3_latin1_t *raw = charset_from_utf8 (data);
-		ucs4 = id3_latin1_ucs4duplicate (raw);
-		g_free (raw);
-	    }
-	    else
-	    {
-		/* Yeah! We use unicode encoding and won't have to
-		   worry about charsets */
-		ucs4 = tmp_ucs4;
-		tmp_ucs4 = NULL;
-	    }
-	}
-	g_free (tmp_ucs4);
-    }
-    else
-    {
-	if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
-	{
-	    /* we read 'ISO_8859_1' to stand for 'any locale charset'
-	       -- most programs seem to work that way */
-	    id3_latin1_t *raw = charset_from_utf8 (data);
-	    ucs4 = id3_latin1_ucs4duplicate (raw);
-	    g_free (raw);
-	}
-	else
-	{
-	    /* Yeah! We use unicode encoding and won't have to
-	       worry about charsets */
-	    ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
-	}
-    }
-
-    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
-	res = id3_field_setfullstring (field, ucs4);
-    else
-	res = id3_field_setstrings (field, 1, &ucs4);
-
-    g_free (ucs4);
-
-    if (res != 0)
-	g_print(_("Error setting ID3 field: %s\n"), frame_name);
-}
-
-
-/***
- * Reads id3v1.x / id3v2 apic data
- * @returns: TRUE on success, else FALSE.
- */
-static gboolean id3_apic_read (gchar *filename,
-			       guchar **image_data, gsize *image_data_len)
-{
-    struct id3_file *id3file;
-    struct id3_tag *id3tag;
-
-    g_return_val_if_fail (filename, FALSE);
-    g_return_val_if_fail (image_data, FALSE);
-    g_return_val_if_fail (image_data_len, FALSE);
-
-    *image_data = NULL;
-    *image_data_len = 0;
-
-    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	id3_length_t len;
-	const guchar *coverart = NULL;
-	int i;
-	struct id3_frame *frame;
-
-	/* Loop through APIC tags and set coverart.  The picture type should be
-	 * 3 -- Cover (front), but iTunes has been known to use 0 -- Other. */
-	for (i = 0; (frame = id3_tag_findframe(id3tag, "APIC", i)) != NULL; i++)
-	{
-	    union id3_field *field = id3_frame_field (frame, 2);
-	    int pictype = field->number.value;
-/*	    printf ("%s: found apic type %d\n", filename, pictype);*/
-
-	    /* We'll prefer type 3 (cover) over type 0 (other) */
-	    if (pictype == 3)
-	    {
-		coverart = id3_get_binary (id3tag, "APIC", &len, i);
-		break;
-	    }
-	    if ((pictype == 0) && !coverart)
-	    {
-		coverart = id3_get_binary (id3tag, "APIC", &len, i);
-	    }
-	}
-
-	if (coverart)
-	{   /* I guess iTunes is doing something wrong -- the
-	     * beginning of the coverart data ends up in a different
-	       field... We'll just add the missing data manually. */
-	    const guchar itunes_broken_jfif_marker[] =
-		{ 0x10, 'J', 'F', 'I', 'F'};
-	    if (len >= 5)
-	    {
-		if (strncmp (itunes_broken_jfif_marker, coverart,  5) == 0)
-		{
-		    const guchar itunes_missing_header[] =
-			{ 0xff, 0xd8, 0xff, 0xe0, 0x00 };
-		    *image_data = g_malloc (len+5);
-		    memcpy (*image_data, itunes_missing_header, 5);
-		    memcpy ((*image_data)+5, coverart, len);
-		    *image_data_len = len+5;
-		}
-	    }
-	    if (!*image_data)
-	    {
-		*image_data = g_malloc (len);
-		memcpy (*image_data, coverart, len);
-		*image_data_len = len;
-	    }
-#if LOCALDEBUG
-	    if (*image_data)
-	    {
-		FILE *file;
-		file = fopen ("/tmp/folder.jpg", "w");
-		fwrite (*image_data, 1, *image_data_len, file);
-		fclose (file);
-	    }
-#endif
-	}    
-    }
-    id3_file_close (id3file);
-    return TRUE;
-}
-
-/***
- * Reads id3v1.x / id3v2 tag and load data into the Id3tag structure.
- * If a tag entry exists (ex: title), we allocate memory, else value
- * stays to NULL
- * @returns: TRUE on success, else FALSE.
- */
-gboolean id3_tag_read (gchar *filename, File_Tag *tag)
-{
-    struct id3_file *id3file;
-    struct id3_tag *id3tag;
-    gchar* string;
-    gchar* string2;
-
-    g_return_val_if_fail (filename, FALSE);
-    g_return_val_if_fail (tag, FALSE);
-
-    memset (tag, 0, sizeof (File_Tag));
-
-    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	tag->title = id3_get_string (id3tag, ID3_FRAME_TITLE);
-	tag->artist = id3_get_string (id3tag, ID3_FRAME_GROUP);
-	if (!tag->artist || !*tag->artist)
-	{
-	    g_free (tag->artist);
-	    tag->artist = id3_get_string (id3tag, ID3_FRAME_ARTIST);
-	}
-	tag->album = id3_get_string (id3tag, ID3_FRAME_ALBUM);
-	tag->year = id3_get_string (id3tag, ID3_FRAME_YEAR);
-	tag->composer = id3_get_string (id3tag, "TCOM");
-	tag->comment = id3_get_string (id3tag, ID3_FRAME_COMMENT);
-	tag->genre = id3_get_string (id3tag, ID3_FRAME_GENRE);
-	tag->compilation = id3_get_string (id3tag, "TCMP");
-	tag->subtitle = id3_get_string (id3tag, "TIT3");
-	tag->lyrics = id3_get_string (id3tag, "USLT");
-	tag->podcasturl = id3_get_string (id3tag, "YTID");
-	tag->podcastrss = id3_get_string (id3tag, "YWFD");
-	tag->description = id3_get_string (id3tag, "YTDS");
-	tag->time_released = id3_get_string (id3tag, "YTDR");
-	tag->BPM = id3_get_string (id3tag, "TBPM");
-	tag->sort_artist = id3_get_string (id3tag, "TSOP");
-	tag->sort_album = id3_get_string (id3tag, "TSOA");
-	tag->sort_title = id3_get_string (id3tag, "TSOT");
-	tag->sort_albumartist = id3_get_string (id3tag, "TSO2");
-	tag->sort_composer = id3_get_string (id3tag, "TSOC");
-
-	string = id3_get_string (id3tag, "TLEN");
-	if (string)
-	{
-	    tag->songlen = (guint32) strtoul (string, 0, 10);
-	    g_free (string);
-	}
-
-	string = id3_get_string (id3tag, ID3_FRAME_TRACK);
-	if (string)
-	{
-	    string2 = strchr(string,'/');
-	    if (string2)
-	    {
-		tag->track_total = g_strdup_printf ("%.2d", atoi (string2+1));
-		*string2 = '\0';
-	    }
-	    tag->trackstring = g_strdup_printf ("%.2d", atoi (string));
-	    g_free(string);
-	}
-	
-	/* CD/disc number tag handling */
-	string = id3_get_string (id3tag, "TPOS");
-	if (string)
-	{
-	    string2 = strchr(string,'/');
-	    if (string2)
-	    {
-		tag->cdno_total = g_strdup_printf ("%.2d", atoi (string2+1));
-		*string2 = '\0';
-	    }
-	    tag->cdnostring = g_strdup_printf ("%.2d", atoi (string));
-	    g_free(string);
-	}
-    }
-
-    id3_file_close (id3file);
-    return TRUE;
-}
-
-
-
-static enum id3_field_textencoding get_encoding_of (struct id3_tag *tag, const char *frame_name)
-{
-    struct id3_frame *frame;
-    enum id3_field_textencoding encoding = -1;
-
-    frame = id3_tag_findframe (tag, frame_name, 0);
-    if (frame)
-    {
-	union id3_field *field = id3_frame_field (frame, 0);
-	if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
-	    encoding = field->number.value;
-    }
-    return encoding;
-}
-
-/* Find out which encoding is being used. If in doubt, return
- * latin1. This code assumes that the same encoding is used in all
- * fields.  */
-static enum id3_field_textencoding get_encoding (struct id3_tag *tag)
-{
-    enum id3_field_textencoding enc;
-
-    enc = get_encoding_of (tag, ID3_FRAME_TITLE);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_ARTIST);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_ALBUM);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, "TCOM");
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_COMMENT);
-    if (enc != -1) return enc;
-    enc = get_encoding_of (tag, ID3_FRAME_YEAR);
-    if (enc != -1) return enc;
-    return ID3_FIELD_TEXTENCODING_ISO_8859_1;
-}
-
-
-/* I'm not really sure about this: The original TAG identifier was
-   "TID", but no matter what I do I end up writing "YTID" */
-void set_uncommon_tag (struct id3_tag *id3tag,
-		       const gchar *id,
-		       const gchar *text,
-		       enum id3_field_textencoding encoding)
-{
-#if 0
-    struct id3_frame *frame;
-
-    frame = id3_tag_findframe (id3tag, id, 0);
-	union id3_field *field;
-	frame->flags = 0;
-	field = id3_frame_field (frame, 0);
-	    if (field)
-	    {
-		string1 = g_strdup_printf ("%c%s", '\0',
-					   track->podcasturl);
-		id3_field_setbinarydata (field, string1,
-					 strlen(track->podcasturl)+1);
-		g_free (string1);
-	    }
-
-#endif
-}
-
-
-
-/**
- * Write the ID3 tags to the file.
- * @returns: TRUE on success, else FALSE.
- */
-gboolean mp3_write_file_info (gchar *filename, Track *track)
-{
-    struct id3_tag* id3tag;
-    struct id3_file* id3file;
-    gint error = 0;
-
-    id3file = id3_file_open (filename, ID3_FILE_MODE_READWRITE);
-    if (!id3file)
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while opening file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    if ((id3tag = id3_file_tag(id3file)))
-    {
-	char *string1;
-
-	enum id3_field_textencoding encoding;
-
-	/* use the same coding as before... */
-	encoding = get_encoding (id3tag);
-	/* ...unless it's ISO_8859_1 and prefs say we should use
-	   unicode (i.e. ID3v2.4) */
-	if (prefs_get_int("id3_write_id3v24") &&
-	    (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1))
-	    encoding = ID3_FIELD_TEXTENCODING_UTF_8;
-
-	/* always render id3v1 to prevent dj studio from crashing */
-	id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);
-
-        /* turn off frame compression and crc information to let
-	   itunes read tags see
-	   http://www.mars.org/mailman/public/mad-dev/2002-October/000742.html
-	*/
-	id3_tag_options(id3tag, ID3_TAG_OPTION_COMPRESSION, 0);
-	id3_tag_options(id3tag, ID3_TAG_OPTION_CRC, 0);
-
-	id3_set_string (id3tag, ID3_FRAME_TITLE, track->title, encoding);
-	id3_set_string (id3tag, ID3_FRAME_ARTIST, track->artist, encoding);
-	id3_set_string (id3tag, ID3_FRAME_ALBUM, track->album, encoding);
-	id3_set_string (id3tag, ID3_FRAME_GENRE, track->genre, encoding);
-	id3_set_string (id3tag, ID3_FRAME_COMMENT, track->comment, encoding);
-	id3_set_string (id3tag, "TIT3", track->subtitle, encoding);
-	id3_set_string (id3tag, "TSOP", track->sort_artist, encoding);
-	id3_set_string (id3tag, "TSOA", track->sort_album, encoding);
-	id3_set_string (id3tag, "TSOT", track->sort_title, encoding);
-	id3_set_string (id3tag, "TSO2", track->sort_albumartist, encoding);
-	id3_set_string (id3tag, "TSOC", track->sort_composer, encoding);
-
-	set_uncommon_tag (id3tag, "YTID", track->podcasturl, encoding);
-	set_uncommon_tag (id3tag, "YTDS", track->description, encoding);
-	set_uncommon_tag (id3tag, "YWFD", track->podcastrss, encoding);
-
-	id3_set_string (id3tag, "TCOM", track->composer, encoding);
-
-	string1 = g_strdup_printf("%d", track->year);
-	id3_set_string(id3tag, ID3_FRAME_YEAR, string1, encoding);
-	g_free(string1);
-
-	string1 = g_strdup_printf("%d", track->BPM);
-	id3_set_string(id3tag, "TBPM", string1, encoding);
-	g_free(string1);
-
-	if (track->tracks)
-	    string1 = g_strdup_printf ("%d/%d",
-				       track->track_nr, track->tracks);
-	else
-	    string1 = g_strdup_printf ("%d", track->track_nr);
-	id3_set_string (id3tag, ID3_FRAME_TRACK, string1, encoding);
-	g_free(string1);
-
-	if (track->cds)
-	    string1 = g_strdup_printf ("%d/%d",
-				       track->cd_nr, track->cds);
-	else
-	    string1 = g_strdup_printf ("%d", track->cd_nr);
-	id3_set_string (id3tag, "TPOS", string1, encoding);
-	g_free(string1);
-        
-       string1 = g_strdup_printf ("%d", track->compilation);
-       id3_set_string (id3tag, "TCMP", string1, encoding);
-       g_free(string1);
-    } 
-
-    if (id3_file_update(id3file) != 0)
-    {
-	gchar *fbuf = charset_to_utf8 (filename);
-	g_print(_("ERROR while writing tag to file: '%s' (%s).\n"),
-		fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return FALSE;
-    }
-
-    id3_file_close (id3file);
-
-    if (error) return FALSE;
-    else       return TRUE;
-}
-
-
-/*
- * Code to read the ReplayGain Values stored by LAME in its own tag.
- *
- * Most of the relevant information has been extracted from them LAME sources
- * (http://lame.sourceforge.net/).
- * The "Mp3 info Tag rev 1 specifications - draft 0"
- * (http://gabriel.mp3-tech.org/mp3infotag.html) by Gabriel Bouvigne describes
- * the actual Tag (except for small changes).
- * Details on the actual ReplayGain fields have been obtained from
- * http://www.replaygain.org .
- *
- * Apart from that, some information has been derived from phwip's LameTag
- * (http://www.silisoftware.com/applets/?scriptname=LameTag)
- *
- * 
- * Code to read the ReplayGain Values stored in an Ape tag.
- *
- * Info on Lyrics3 V2.00 can be found at:
- * http://www.id3.org/lyrics3200.html
- * On the actual Ape Tag V2.0:
- * http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
- *
- * Copyright (C) 2004 Jens Taprogge <jens.taprogge at post.rwth-aachen.de>
- *
- * Provided under GPL according to Jens Taprogge. (JCS -- 12 March 2004)
- */
-
-#define TAG_FOOTER		0x10
-#define LAME_OFFSET		0x74
-#define SIDEINFO_MPEG1_MONO	17
-#define SIDEINFO_MPEG1_MULTI	32
-#define SIDEINFO_MPEG2_MONO	9
-#define SIDEINFO_MPEG2_MULTI	17
-#define ID3V1_SIZE		0x80
-#define APE_FOOTER_SIZE 	0x20
-#define LYRICS_FOOTER_SIZE 	0x0f
-
-
-static gint lame_vcmp(gchar a[5], gchar b[5]) {
-	int r;
-
-	r = strncmp(a, b, 4);
-	if (r) return r;
-
-	if (a[4] == b[4]) return 0;
-
-	/* check for '.': indicates subminor version */
-	if (a[4] == '.') return 1;
-	if (b[4] == '.') return -1;
-	
-	/* check for alpha or beta versions */
-	if (a[4] == ' ') return 1;
-	if (b[4] == ' ') return -1;
-
-	/* check for alpha, beta etc. indicated by a, b... */
-	return strncmp(&a[4], &b[4], 1);
-}
-
-
-/* buf[] must be declared unsigned -- otherwise the casts, shifts and
-   additions below produce funny results */             
-static void read_lame_replaygain(unsigned char buf[],
-				 GainData *gd, int gain_adjust) {
-	char oc, nc;
-	gint gain;
-
-	g_return_if_fail (gd);
-
-	/* buf[0] and buf[1] are a bit field:
-	   3 bits: name  (mask: 0xe0 = 11100000)
-	   3 bits: originator (mask: 0x1c = 00011100)
-	   1 bit: negative if set (mask: 0x02 = 00000010)
-	   9 bits: value
-	*/
-
-	/* check originator */
-	oc = (buf[0] & 0x1c) >> 2;
-	if ((oc <= 0) || (oc > 3)) return;
-
-	/* check name code */
-	nc = buf[0] & 0xe0;
-	if (!((nc == 0x20) || (nc == 0x40))) return;
-	
-	gain = ((((guint)buf[0]) & 0x1) << 8) + buf[1];
-	
-	/* This would be a value of -0.
-	 * That value however is illegal by current standards and reserved for
-	 * future use. */
-	if ((!gain) && (buf[0] & 0x02)) return;
-	
-	if (buf[0] & 2) gain = -gain;
-	
-	gain += gain_adjust;
-
-	switch (nc) {
-		case 0x20:
-			if (gd->radio_gain_set) return;
-			gd->radio_gain = (gdouble)gain / 10;
-			gd->radio_gain_set = TRUE;
-/*			printf("radio_gain (lame): %i\n", gd->radio_gain); */
-			break;
-		case 0x40:
-			if (gd->audiophile_gain_set) return;
-			gd->audiophile_gain = (gdouble)gain / 10;
-			gd->audiophile_gain_set = TRUE;
-/*			printf("audiophile_gain (lame): %i\n", 
-					gd->audiophile_gain);*/
-			break;
-	}
-}
-
-
-static inline guint32 parse_ape_uint32(char *buf) {
-	return (buf[0] & 0xff) | (buf[1] & 0xff) << 8 
-		| (buf[2] & 0xff) << 16 | (buf[3] & 0xff) << 24;
-}
-
-static inline guint32 parse_lame_uint32(char *buf) {
-	return (buf[0] & 0xff) << 24 | (buf[1] & 0xff) << 16 
-		| (buf[2] & 0xff) << 8 | (buf[3] & 0xff);
-}
-
-
-/* 
- * mp3_get_track_lame_replaygain - read the specified file and scan for LAME Tag
- * ReplayGain information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * FIXME: Are there other encoders writing a LAME Tag using a different magic
- * string?
- * TODO: Check CRC.
- */
-
-gboolean mp3_get_track_lame_replaygain (gchar *path, GainData *gd)
-{
-	struct {
-		/* All members are defined in terms of chars so padding does not
-		 * occur. Is there a cleaner way to keep the compiler from
-		 * padding? */
-		
-		char     id[3];
-		char     version[2];
-		char     flags;
-		char     size[4];
-	} id3head;
-
-	FILE *file = NULL;
-	char buf[4], version[5];
-	int gain_adjust = 0;
-	int sideinfo;
-	guint32 ps;
-
-	g_return_val_if_fail (gd, FALSE);
-
-	gd->radio_gain = 0;
-	gd->audiophile_gain = 0;
-	gd->peak_signal = 0;
-	gd->radio_gain_set = FALSE;
-	gd->audiophile_gain_set = FALSE;
-	gd->peak_signal_set = FALSE;
-	
-	if (!path)
-		goto rg_fail;
-	
-	file = fopen (path, "r");
-
-	if (!file)
-	    goto rg_fail;
-
-	/* Skip ID3 header if appropriate */
-	if (fread(&id3head, 1, sizeof(id3head), file) != 
-			sizeof(id3head))
-		goto rg_fail;
-	
-	if (!strncmp(id3head.id, "ID3", 3)) {
-		int realsize = 0;
-		
-		realsize = (id3head.size[0] & 0x7f) << 21 
-			| (id3head.size[1] & 0x7f) << 14 
-			| (id3head.size[2] & 0x7f) << 7 
-			| (id3head.size[3] & 0x7f);
-
-		if (id3head.flags & TAG_FOOTER) {
-			/* footer is copy of header */
-			realsize += sizeof(id3head);
-		}
-
-		if (fseek(file, realsize-1, SEEK_CUR) ||
-				(!fread(&buf[0], 1, 1, file)))
-			goto rg_fail;
-	} else {
-		/* no ID3 Tag - go back */
-		fseek(file, -sizeof(id3head), SEEK_CUR);
-	}
-
-	/* Search Xing header. The location is dependant on the MPEG Layer and
-	 * whether the stream is mono or not. */
-	if (fread(buf, 1, 4, file) != 4) goto rg_fail;
-	
-	/* should start with 0xff 0xf? (synch) */
-	if (((buf[0] & 0xff) != 0xff) 
-			|| ((buf[1] & 0xf0) != 0xf0)) goto rg_fail;
-	
-	/* determine the length of the sideinfo */
-	if (buf[1] & 0x08) {
-		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
-			SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
-	} else {
-		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
-			SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
-	}
-	
-	if (fseek(file, sideinfo, SEEK_CUR) ||
-			(fread(&buf[0], 1, 4, file) != 4))
-		goto rg_fail;
-	
-	/* Is this really a Xing or Info Header? 
-	 * FIXME: Apparently (according to madplay sources) there is a different
-	 * possible location for the Xing header ("due to an unfortunate
-	 * historical event"). I do not thing we need to care though since
-	 * RaplayGain information is only conatined in recent files.  */
-	if (strncmp(buf, "Xing", 4) && strncmp(buf, "Info", 4))
-		goto rg_fail;
-
-	/* Check for LAME Tag */
-	if (fseek(file, LAME_OFFSET, SEEK_CUR) ||
-				(fread(&buf[0], 1, 4, file) != 4))
-		goto rg_fail;
-	if (strncmp(buf, "LAME", 4))
-		goto rg_fail;
-	
-	/* Check LAME Version */
-	if (fread(version, 1, 5, file) != 5)
-		goto rg_fail;
-	
-	/* Skip really old versions altogether. I am not sure when radio_gain
-	 * information was introduced. 3.89 does not seem to supprt it though.
-	 * */
-	if (lame_vcmp(version, "3.90") < 0) {
-/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Not used.\n",
-				version[0], version[1], version[2], version[3], version[4]); */
-		goto rg_fail;
-	}
-		
-	if (fseek(file, 0x2, SEEK_CUR) || (fread(buf, 1, 4, file) != 4))
-		goto rg_fail;
-
-	/* get the peak signal. */
-	ps = parse_lame_uint32(buf);
-	
-	/* Don't know when fixed-point PeakSingleAmplitude
-	 * was introduced exactly. 3.94b will be used for now.) */
-	if ((lame_vcmp(version, "3.94b") >= 0)) {
-		if ((!gd->peak_signal_set) && ps) {
-			gd->peak_signal = ps;
-			gd->peak_signal_set = TRUE;
-/*			printf("peak_signal (lame): %f\n", (double)
-					gd->peak_signal / 0x800000);*/
-		}
-	} else {
-		float f = *((float *) (void *) (&ps)) * 0x800000;
-		gd->peak_signal = (guint32) f;
-		/* I would like to see an example of that. */
-/*		printf("peak_signal (lame floating point): %f. PLEASE report.\n", 
-				(double) gd->peak_signal / 0x800000);*/
-	}
-
-	/*
-	 * Versions prior to 3.95.1 used a reference volume of 83dB.
-	 * (As compared to the currently used 89dB.)
-	 */
-	if ((lame_vcmp(version, "3.95.") < 0)) {
-		gain_adjust = 60;
-/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Adjusting gain.\n",
-				version[0], version[1], version[2], version[3], version[4]); */
-	}
-
-	if (fread(&buf[0], 1, 2, file) != 2)
-		goto rg_fail;
-
-	/* radio gain */
-	read_lame_replaygain (buf, gd, gain_adjust);
-
-	if (fread(&buf[0], 1, 2, file) != 2)
-		goto rg_fail;
-
-	/* audiophile gain */
-	read_lame_replaygain (buf, gd, gain_adjust);
-
-	fclose(file);
-	return TRUE;
-
-rg_fail:
-	if (file)
-		fclose(file);
-	return FALSE;
-}
-
-
-/* 
- * mp3_get_track_ape_replaygain - read the specified file and scan for Ape Tag
- * ReplayGain information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * The function only modifies the gains if they have not previously been set.
- */
-
-gboolean mp3_get_track_ape_replaygain(gchar *path, GainData *gd)
-{
-	/* The Ape Tag is located a t the end of the file. Or at least that
-	 * seems where it can most likely be found. Either it is at the very end
-	 * or before a trailing ID3v1 Tag. Sometimes a Lyrics3 Tag is placed
-	 * between the ID3v1 and the Ape Tag.
-	 * If you find files that have the Tags located in different
-	 * positions please let me know. */
-
-	FILE *file = NULL;
-	char buf[16];
-	char *dbuf = NULL, *ep;
-
-	int offset = 0;
-	int i;
-	int pos = 0, pos2 = 0;
-	guint32 version;
-	guint32 data_length;
-	guint32 entry_length = 0;
-	guint32 entries;
-	double d;
-
-	g_return_val_if_fail (gd, FALSE);
-	g_return_val_if_fail (path, FALSE);
-
-	file = fopen (path, "r");
-
-	if (!file)
-	    goto rg_fail;
-
-	/* check for ID3v1 Tag */
-	if (fseek(file, -ID3V1_SIZE, SEEK_END) ||
-			fread(&buf, 1, 3, file) != 3)
-		goto rg_fail;
-	if (!strncmp(buf, "TAG", 3)) offset -= ID3V1_SIZE;
-
-	/* check for Lyrics3 Tag */
-	if (fseek(file, -9 + offset, SEEK_END) ||
-			fread(&buf, 1, 9, file) != 9)
-		goto rg_fail;
-	if (!strncmp(buf, "LYRICS200", 9)) {
-		if (fseek(file, -LYRICS_FOOTER_SIZE + offset, SEEK_END) ||
-				fread(&buf, 1, 9, file) != 9)
-			goto rg_fail;
-		data_length = buf[0] - '0';
-		for (i = 1; i < 6; i++) {
-			data_length *= 10;
-			data_length += buf[i] - '0';
-		}
-		if (fseek(file, -LYRICS_FOOTER_SIZE - data_length + offset,
-					SEEK_END) ||
-				fread(&buf, 1, 11, file) != 11)
-			goto rg_fail;
-		if (!strncmp(buf, "LYRICSBEGIN", 11)) 
-			offset -= LYRICS_FOOTER_SIZE + data_length;
-	}
-
-	/* check for APE Tag */
-	if (fseek(file, -APE_FOOTER_SIZE + offset, SEEK_END) ||
-			fread(&buf, 1, 8, file) != 8)
-		goto rg_fail;
-	if (strncmp(buf, "APETAGEX", 8)) goto rg_fail;
-
-	/* Check the version of the tag. 1000 and 2000 (v1.0 and 2.0) are the
-	 * only ones I know about. Make suer things do not break in the future.
-	 * */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	version = parse_ape_uint32(buf);
-	if (version != 1000 && version != 2000)
-		goto rg_fail;
-
-	/* determine data length */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	data_length = parse_ape_uint32(buf) - APE_FOOTER_SIZE;
-
-	/* determine number of entries */
-	if (fread(&buf, 1, 4, file) != 4)
-		goto rg_fail;
-	entries = parse_ape_uint32(buf);
-
-	/* seek to first entry and read the whole buffer*/
-	if (fseek(file, -APE_FOOTER_SIZE + offset - data_length, SEEK_END))
-		goto rg_fail;
-	if (!(dbuf = malloc(data_length)))
-		goto rg_fail;
-	if (fread(dbuf, 1, data_length, file) != data_length)
-		goto rg_fail;
-	
-	for (i = 0; i < entries; i++) {
-		if (gd->radio_gain_set && gd->peak_signal_set) break;
-		pos = pos2 + entry_length;
-		if (pos > data_length - 10) break;
-		
-		entry_length = parse_ape_uint32(&dbuf[pos]); pos += 4;
-		pos += 4;
-		
-		pos2 = pos;
-		while (dbuf[pos2] && pos2 < data_length) pos2++;
-		if (pos2 == data_length) break;
-		pos2++;
-		
-		if (entry_length + 1 > sizeof(buf))
-			continue;
-/* 		printf ("%s:%d:%d\n",&dbuf[pos], pos2, pos); */
-		if (!gd->radio_gain_set && !strcasecmp(&dbuf[pos],
-					"REPLAYGAIN_TRACK_GAIN")) {
-			memcpy(buf, &dbuf[pos2], entry_length);
-			buf[entry_length] = '\0';
-			
-			d = g_ascii_strtod(buf, &ep);
-/* 			printf("%f\n", d); */
-			if ((ep == buf + entry_length - 3) 
-					&& (!strncasecmp(ep, " dB", 3))) {
-			    gd->radio_gain = d;
-				gd->radio_gain_set = TRUE;
-/*				printf("radio_gain (ape): %i\n", gd->radio_gain);*/
-			}
-			
-			continue;
-		}
-		if (!gd->peak_signal_set && !strcasecmp(&dbuf[pos],
-					"REPLAYGAIN_TRACK_PEAK")) {
-			memcpy(buf, &dbuf[pos2], entry_length);
-			buf[entry_length] = '\0';
-			
-			d = g_ascii_strtod(buf, &ep);
-			if (ep == buf + entry_length) {
-				d *= 0x800000;
-				gd->peak_signal = (guint32) floor(d + 0.5);
-				gd->peak_signal_set = TRUE;
-/*				printf("peak_signal (ape): %f\n", (double) gd->peak_signal / 0x800000);*/
-			}
-
-			continue;
-		}
-	}
-
-	free(dbuf);
-	fclose(file);
-	return TRUE;
-
-rg_fail:
-	if (dbuf)
-		free(dbuf);
-	if (file)
-		fclose(file);
-	return FALSE;
-}
-
-
-/* ----------------------------------------------------------------------
-
-	      mp3gain code
-
----------------------------------------------------------------------- */
-
-#include <sys/wait.h>
-#include <fcntl.h>
-
-
-
-
-
-
-/** 
- * mp3_read_soundcheck:
- *
- * try to read the ReplayGain values from the LAME or Ape Tags and set
- * the track's soundcheck field accordingly.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * The function always rereads the gain from the file.
- *
- * Returns TRUE if the soundcheck field could be set.
- */
-gboolean mp3_read_soundcheck (gchar *path, Track *track)
-{
-    GainData gd;
-
-    g_return_val_if_fail (track, FALSE);
-
-    memset (&gd, 0, sizeof (GainData));
-
-    gd.radio_gain_set = FALSE;
-    gd.audiophile_gain_set = FALSE;
-    gd.peak_signal_set = FALSE;
-
-    mp3_get_track_lame_replaygain (path, &gd);
-    if (gd.radio_gain_set)
-    {
-	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
-	return TRUE;
-    }
-
-    mp3_get_track_ape_replaygain (path, &gd);
-    if (gd.radio_gain_set)
-    {
-	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
-	return TRUE;
-    }
-
-    return FALSE;
-}
-
-
-
-
-
-
-/* mp3 slot size in bytes */
-int slotsize[3] = {4,1,1}; /* layer 1, layer 2, layer 3 */
-
-int samplesperframe[2][3] = {
-  { /* MPEG 2.0 */
-    384,1152,576 /* layer 1, layer 2, layer 3 */
-  },
-
-  { /* MPEG 1.0 */
-    384,1152,1152 /* layer 1, layer 2, layer 3 */
-  }
-};
-
-
-/* 
- * mp3_get_track_lame_gapless - read the specified file and scan for LAME Tag
- * gapless information.
- *
- * @path: localtion of the file
- * @track: structure holding track information
- *
- * TODO: Split off non-LAME stuff (samplecount, gapless_data) to a separate function since it's generic
- */
-gboolean mp3_get_track_lame_gapless (gchar *path, GaplessData *gd)
-{
-    FILE *file = NULL;
-    char buf[4], version[5];
-    unsigned char ubuf[4];
-    int sideinfo;
-    int i;
-
-    g_return_val_if_fail (gd, FALSE);
-
-    if (!path)
-	goto gp_fail;
-
-    file = fopen (path, "rb");
-
-    if (!file)
-	goto gp_fail;
-
-    /* use get_first_header() to seek to the first mp3 header */
-    MP3Info *mp3i = NULL;
-    mp3i = g_malloc0 (sizeof (MP3Info));
-    mp3i->filename = path;
-    mp3i->file = file;
-    get_mp3_info (mp3i);
-    get_first_header (mp3i, 0);
-
-    int xing_header_offset = ftell (file);
-
-    MP3Header h;
-    if (!get_header (file, &h))
-	goto gp_fail;
-
-    int mysamplesperframe = samplesperframe[h.version & 1][3 - h.layer];
-
-    /* Determine offset of Xing header based on sideinfo size */
-    if (h.version & 0x1)
-    {
-	sideinfo = (h.mode & 0x2) ?
-	    SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
-    }
-    else
-    {
-	sideinfo = (h.mode & 0x2) ?
-	    SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
-    }
-
-    if (fseek (file, sideinfo, SEEK_CUR) ||
-	(fread (&buf[0], 1, 4, file) != 4))
-	goto gp_fail;
-
-    /* Is this really a Xing or Info Header? 
-     * FIXME: Apparently (according to madplay sources) there is a different
-     * possible location for the Xing header ("due to an unfortunate
-     * historical event"). I do not thing we need to care though since
-     * ReplayGain information is only contained in recent files.  */
-    if (strncmp (buf, "Xing", 4) && strncmp (buf, "Info", 4))
-	goto gp_fail;
-
-    /* Determine the offset of the LAME tag based on contents of the Xing header */
-    int flags;
-    fread (&flags, 4, 1, file);
-    int toskip = 0;
-    if (flags | 0x1)
-    {				/* frames field is set */
-	toskip += 4;
-    }
-    if (flags | 0x2)
-    {				/* bytes field is set */
-	toskip += 4;
-    }
-    if (flags | 0x4)
-    {				/* TOC field is set */
-	toskip += 100;
-    }
-    if (flags | 0x8)
-    {				/* quality field is set */
-	toskip += 4;
-    }
-
-    /* Check for LAME Tag */
-    if (fseek (file, toskip, SEEK_CUR) || (fread (&buf[0], 1, 4, file) != 4))
-	goto gp_fail;
-    if (strncmp (buf, "LAME", 4))
-	goto gp_fail;
-
-    /* Check LAME Version */
-    if (fread (version, 1, 5, file) != 5)
-	goto gp_fail;
-
-    /* XXX skip old LAME versions, or just assume that pre/postgap
-     * turn out zeros anyway, or check the CRC to vaidate the tag? */
-
-    gboolean cbr = FALSE;
-    if (fread (ubuf, 1, 1, file) != 1)
-	goto gp_fail;
-
-    if ((ubuf[0] & 0xf) == 0x1)
-	cbr = TRUE;
-
-    if (fseek (file, 0xB, SEEK_CUR) || (fread (ubuf, 1, 4, file) != 4))
-	goto gp_fail;
-
-    /* set pregap and postgap directly from LAME header */
-    gd->pregap = (ubuf[0] << 4) + (ubuf[1] >> 4);
-    gd->postgap = ((ubuf[1] & 0xf) << 8) + ubuf[2];
-
-    /* jump the end of the frame with the xing header */
-    if (fseek (file, xing_header_offset + frame_length (&h), SEEK_SET))
-	goto gp_fail;
-
-    /* counts bytes from the start of the 1st sync frame */
-    int totaldatasize = frame_length (&h);
-
-    /* keeps track of the last 8 frame sizes */
-    int lastframes[8];
-
-    /* counts number of music frames */
-    int totalframes = 0;
-
-    /* quickly parse the file, reading only frame headers */
-    int l = 0;
-    while ((l = get_header (file, &h)) != 0)
-    {
-	for (i = 7; i > 0; i--)
-	{
-	    lastframes[i] = lastframes[i - 1];
-	}
-	lastframes[0] = l;
-	totaldatasize += l;
-	totalframes++;
-
-	if (fseek (file, l - FRAME_HEADER_SIZE, SEEK_CUR))
-	    goto gp_fail;
-
-    }
-
-    int finaleight = 0;
-    for (i = 0; i < 8; i++)
-    {
-	finaleight += lastframes[i];
-    }
-
-    if (cbr)
-	totalframes++;
-
-    /* all but last eight frames */
-    gd->gapless_data = totaldatasize - finaleight;
-    /* total samples minus pre/postgap */
-    gd->samplecount = totalframes * mysamplesperframe - gd->pregap - gd->postgap;
-	fclose(file);
-
-    return TRUE;
-
-
-  gp_fail:
-    if (file)
-	fclose (file);
-    return FALSE;
-
-}
-
-
-
-/** 
- * mp3_read_gapless:
- *
- * try to read the gapless values from the LAME Tag and set
- * the track's pregap, postgap, samplecount, and gapless_data fields
- * accordingly.
- *
- * @path: location of the file
- * @track: structure holding track information
- *
- * The function always rereads the data from the file.
- *
- * Returns TRUE if all four gapless fields could be
- * set. etrack->tchanged is set to TRUE if data has been changed,
- * FALSE otherwise.
- */
-gboolean mp3_read_gapless (char *path, Track *track)
-{
-    GaplessData gd;
-    ExtraTrackData *etr;
-
-    g_return_val_if_fail (track, FALSE);
-
-    etr = track->userdata;
-
-    memset (&gd, 0, sizeof (GaplessData));
-
-    gd.pregap = 0;
-    gd.samplecount = 0;
-    gd.postgap = 0;
-    gd.gapless_data = 0;
-
-    mp3_get_track_lame_gapless (path, &gd);
-
-    etr->tchanged = FALSE;
-
-    if ((gd.pregap) && (gd.samplecount) && (gd.postgap) && (gd.gapless_data))
-    {
-	if ((track->pregap != gd.pregap) ||
-	    (track->samplecount != gd.samplecount) ||
-	    (track->postgap != gd.postgap) ||
-	    (track->gapless_data != gd.gapless_data) ||
-	    (track->gapless_track_flag == FALSE))
-	{
-	    etr->tchanged = TRUE;
-	    track->pregap = gd.pregap;
-	    track->samplecount = gd.samplecount;
-	    track->postgap = gd.postgap;
-	    track->gapless_data = gd.gapless_data;
-	    track->gapless_track_flag = TRUE;
-	}
-    }
-    return FALSE;
-}
-
-
-
-/* ----------------------------------------------------------------------
-
-	      From here starts original gtkpod code
-
----------------------------------------------------------------------- */
-
-/* Return a Track structure with all information read from the mp3
-   file filled in */
-Track *mp3_get_file_info (gchar *name)
-{
-    Track *track = NULL;
-    File_Tag filetag;
-    MP3Info *mp3i=NULL;
-    FILE *file;
-    guchar *image_data = NULL;
-    gsize image_data_len = 0;
-
-    g_return_val_if_fail (name, NULL);
-
-    /* Attempt to open the file */
-    file = fopen (name, "r");
-    if (file)
-    {
-	mp3i = g_malloc0 (sizeof (MP3Info));
-	mp3i->filename = name;
-	mp3i->file = file;
-	get_mp3_info (mp3i);
-	mp3i->file = NULL;
-	fclose (file);
-    }
-    else
-    {
-	gchar *fbuf = charset_to_utf8 (name);
-    	gtkpod_warning(_("ERROR while opening file: '%s' (%s).\n"),
-		       fbuf, g_strerror(errno));
-	g_free (fbuf);
-	return NULL;
-    }
-
-    track = gp_track_new ();
-    track->filetype = g_strdup ("MPEG audio file");
-
-    if (prefs_get_int("readtags") && (id3_tag_read (name, &filetag) == TRUE))
-    {
-
-	if (filetag.album)
-	{
-	    track->album = filetag.album;
-	}
-
-	if (filetag.artist)
-	{
-	    track->artist = filetag.artist;
-	}
-
-	if (filetag.title)
-	{
-	    track->title = filetag.title;
-	}
-
-	if (filetag.genre)
-	{
-	    track->genre = filetag.genre;
-	}
-
-	if (filetag.composer)
-	{
-	    track->composer = filetag.composer;
-	}
-
-	if (filetag.comment)
-	{
-	    track->comment = filetag.comment;
-	}
-
-	if (filetag.podcasturl)
-	{
-	    track->podcasturl = filetag.podcasturl;
-	}
-
-	if (filetag.podcastrss)
-	{
-	    track->podcastrss = filetag.podcastrss;
-	}
-
-	if (filetag.subtitle)
-	{
-	    track->subtitle = filetag.subtitle;
-	}
-
-	if (filetag.description)
-	{
-	    track->description = filetag.description;
-	}
-
-	if (filetag.sort_artist)
-	{
-	    track->sort_artist = filetag.sort_artist;
-	}
-
-	if (filetag.sort_title)
-	{
-	    track->sort_title = filetag.sort_title;
-	}
-
-	if (filetag.sort_album)
-	{
-	    track->sort_album = filetag.sort_album;
-	}
-
-	if (filetag.sort_albumartist)
-	{
-	    track->sort_albumartist = filetag.sort_albumartist;
-	}
-
-	if (filetag.sort_composer)
-	{
-	    track->sort_composer = filetag.sort_composer;
-	}
-
-	if (filetag.year == NULL)
-	{
-	    track->year = 0;
-	}
-	else
-	{
-	    track->year = atoi(filetag.year);
-	    g_free (filetag.year);
-	}
-
-	if (filetag.trackstring == NULL)
-	{
-	    track->track_nr = 0;
-	}
-	else
-	{
-	    track->track_nr = atoi(filetag.trackstring);
-	    g_free (filetag.trackstring);
-	}
-
-	if (filetag.track_total == NULL)
-	{
-	    track->tracks = 0;
-	}
-	else
-	{
-	    track->tracks = atoi(filetag.track_total);
-	    g_free (filetag.track_total);
-	}
-	/* CD/disc number handling */
-	if (filetag.cdnostring == NULL)
-	{
-	    track->cd_nr = 0;
-	}
-	else
-	{
-	    track->cd_nr = atoi(filetag.cdnostring);
-	    g_free (filetag.cdnostring);
-	}
-	
-	if (filetag.cdno_total == NULL)
-	{
-	    track->cds = 0;
-	}
-	else
-	{
-	    track->cds = atoi(filetag.cdno_total);
-	    g_free (filetag.cdno_total);
-	}
-
-	if (filetag.compilation == NULL)
-	{
-	    track->compilation = 0;
-	}
-	else
-	{
-	    track->compilation = atoi(filetag.compilation);
-	    g_free (filetag.compilation);
-	}
-
-	if (filetag.BPM == NULL)
-	{
-	    track->BPM = 0;
-	}
-	else
-	{
-	    track->BPM = atoi(filetag.BPM);
-	    g_free (filetag.BPM);
-	}
-
-	if (filetag.lyrics)
-	{
-	    track->lyrics_flag = 0x01;
-	    g_free (filetag.lyrics);
-	}
-	else
-	{
-	    track->lyrics_flag = 0x00;
-	}
-    }
-
-    if (prefs_get_int("coverart_apic") &&
-	(id3_apic_read (name, &image_data, &image_data_len) == TRUE))
-    {
-	if (image_data)
-	{
-	    gp_track_set_thumbnails_from_data (track,
-					       image_data,
-					       image_data_len);
-	    g_free (image_data);
-	}
-    }
-
-    mp3_read_soundcheck (name, track);
-
-    mp3_read_gapless (name, track);
-
-#if LOCALDEBUG
-	printf("%s\n", name);
-    printf("\tpregap: %i\n", track->pregap);
-    printf("\tpostgap: %i\n", track->postgap);
-    printf("\tsamplecount: %li\n", track->samplecount);
-    printf("\tgaplessdata: %i\n", track->gapless_data);
-#endif
-
-
-    /* Get additional info (play time and bitrate */
-    if (mp3i)
-    {
-	track->tracklen = mp3i->milliseconds;
-	track->bitrate = (gint)(mp3i->vbr_average);
- 	track->samplerate = mp3file_header_frequency (&mp3i->header);
-	g_free (mp3i);
-    }
-    /* Fall back to xmms code if tracklen is 0 */
-    if (track->tracklen == 0)
-    {
-	track->tracklen = get_track_time (name);
-	if (track->tracklen)
-	    track->bitrate = (float)track->size*8/track->tracklen;
-    }
-
-    if (track->tracklen == 0)
-    {
-	/* Tracks with zero play length are ignored by iPod... */
-	gtkpod_warning (_("File \"%s\" has zero play length. Ignoring.\n"),
-			name);
-	gp_track_free (track);
-	track = NULL;
-    }
-    return track;
-}

Copied: gtkpod/tags/0.99.10-5/src/mp3file.c (from rev 267, gtkpod/trunk/src/mp3file.c)
===================================================================
--- gtkpod/tags/0.99.10-5/src/mp3file.c	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/src/mp3file.c	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,2677 @@
+/* Time-stamp: <2007-06-26 00:39:11 jcs>
+|
+|  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  This program is free software; you can redistribute it and/or modify
+|  it under the terms of the GNU General Public License as published by
+|  the Free Software Foundation; either version 2 of the License, or
+|  (at your option) any later version.
+|
+|  This program is distributed in the hope that it will be useful,
+|  but WITHOUT ANY WARRANTY; without even the implied warranty of
+|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+|  GNU General Public License for more details.
+|
+|  You should have received a copy of the GNU General Public License
+|  along with this program; if not, write to the Free Software
+|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+|
+|  iTunes and iPod are trademarks of Apple
+|
+|  This product is not supported/written/published by Apple!
+|
+|  $Id: mp3file.c 1591 2007-06-26 03:33:25Z tmzullinger $
+*/
+
+
+#define LOCALDEBUG 0
+
+
+/* The code in the first section of this file is taken from the
+ * mp3info (http://www.ibiblio.org/mp3info/) project. Only the code
+ * needed for the playlength calculation has been extracted. */
+
+/* The code in the second section of this file is taken from the
+ * mpg123 code used in xmms-1.2.7 (Input/mpg123). Only the code needed
+ * for the playlength calculation has been extracted. */
+
+/* The code in the last section of this file is original gtkpod
+ * code. */
+
+/****************
+ * Declarations *
+ ****************/
+
+#include <glib.h>
+#include <math.h>
+/*
+ * Description of each item of the TagList list
+ */
+typedef struct _File_Tag File_Tag;
+typedef struct _GainData GainData;
+typedef struct _GaplessData GaplessData;
+
+struct _File_Tag
+{
+    gchar *title;          /* Title of track */
+    gchar *artist;         /* Artist name */
+    gchar *album;          /* Album name */
+    gchar *year;           /* Year of track */
+    gchar *trackstring;    /* Position of track in the album */
+    gchar *track_total;    /* The number of tracks for the album (ex: 12/20) */
+    gchar *genre;          /* Genre of song */
+    gchar *comment;        /* Comment */
+    gchar *composer;	   /* Composer */
+    guint32 songlen;       /* Length of file in ms */
+    gchar *cdnostring;    /* Position of disc in the album */
+    gchar *cdno_total;    /* The number of discs in the album (ex: 1/2) */
+    gchar *compilation;   /* The track is a member of a compilation */
+    gchar *podcasturl;    /* The following are mainly used for podcasts */
+    gchar *sort_artist;
+    gchar *sort_title;
+    gchar *sort_album;
+    gchar *sort_albumartist;
+    gchar *sort_composer;
+    gchar *description;
+    gchar *podcastrss;
+    gchar *time_released;
+    gchar *subtitle;
+    gchar *BPM;           /* beats per minute */
+    gchar *lyrics;        /* does not appear to be the full lyrics --
+			     only used to set the flag 'lyrics_flag'
+			     of the Track structure */
+};
+
+
+struct _GainData
+{
+  guint32 peak_signal;	  /* LAME Peak Signal * 0x800000             */
+  gdouble radio_gain;	  /* RadioGain in dB
+			     (as defined by www.replaygain.org)      */
+  gdouble audiophile_gain;/* AudiophileGain in dB 
+			     (as defined by www.replaygain.org)      */
+  gboolean peak_signal_set;    /* has the peak signal been set?      */
+  gboolean radio_gain_set;     /* has the radio gain been set?       */
+  gboolean audiophile_gain_set;/* has the audiophile gain been set?  */
+};
+
+struct _GaplessData
+{
+    guint32 pregap;       /* number of pregap samples */
+    guint64 samplecount;  /* number of actual music samples */
+    guint32 postgap;      /* number of postgap samples */
+    guint32 gapless_data; /* number of bytes from the first sync frame to the 8th to last frame */
+};
+
+/* This code is taken from the mp3info code. Only the code needed for
+ * the playlength calculation has been extracted */
+
+/*
+    mp3tech.c - Functions for handling MP3 files and most MP3 data
+		structure manipulation.
+
+    Copyright (C) 2000-2001  Cedric Tefft <cedric at earthling.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  ***************************************************************************
+
+  This file is based in part on:
+
+	* MP3Info 0.5 by Ricardo Cerqueira <rmc at rccn.net>
+	* MP3Stat 0.9 by Ed Sweetman <safemode at voicenet.com> and
+			 Johannes Overmann <overmann at iname.com>
+
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "mp3file.h"
+#include "charset.h"
+#include "itdb.h"
+#include "file.h"
+#include "misc.h"
+
+
+/* MIN_CONSEC_GOOD_FRAMES defines how many consecutive valid MP3 frames
+   we need to see before we decide we are looking at a real MP3 file */
+#define MIN_CONSEC_GOOD_FRAMES 4
+#define FRAME_HEADER_SIZE 4
+#define MIN_FRAME_SIZE 21
+
+enum VBR_REPORT { VBR_VARIABLE, VBR_AVERAGE, VBR_MEDIAN };
+
+typedef struct {
+    gulong sync;
+    guint  version;
+    guint  layer;
+    guint  crc;
+    guint  bitrate;
+    guint  freq;
+    guint  padding;
+    guint  extension;
+    guint  mode;
+    guint  mode_extension;
+    guint  copyright;
+    guint  original;
+    guint  emphasis;
+} MP3Header;
+
+typedef struct {
+    gchar *filename;
+    FILE *file;
+    off_t datasize;
+    gint header_isvalid;
+    MP3Header header;
+    gint id3_isvalid;
+    gint vbr;
+    float vbr_average;
+    gint milliseconds;
+    gint frames;
+    gint badframes;
+} MP3Info;
+
+/* This is for xmms code */
+static guint get_track_time(gchar *path);
+
+
+
+/* ------------------------------------------------------------
+
+   start of first section
+
+   ------------------------------------------------------------ */
+void get_mp3_info(MP3Info *mp3);
+
+gint frequencies[3][4] = {
+   {22050,24000,16000,50000},  /* MPEG 2.0 */
+   {44100,48000,32000,50000},  /* MPEG 1.0 */
+   {11025,12000,8000,50000}    /* MPEG 2.5 */
+};
+
+/* "0" added by JCS */
+gint bitrate[2][3][16] = {
+  { /* MPEG 2.0 */
+    {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},/* layer 1 */
+    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},     /* layer 2 */
+    {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}      /* layer 3 */
+  },
+
+  { /* MPEG 1.0 */
+    {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},/* layer 1 */
+    {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},   /* layer 2 */
+    {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}     /* layer 3 */
+  }
+};
+
+gint frame_size_index[] = {24000, 72000, 72000};
+
+
+gchar *mode_text[] = {
+   "stereo", "joint stereo", "dual channel", "mono"
+};
+
+gchar *emphasis_text[] = {
+  "none", "50/15 microsecs", "reserved", "CCITT J 17"
+};
+
+
+static gint mp3file_header_bitrate(MP3Header *h) {
+    return bitrate[h->version & 1][3-h->layer][h->bitrate];
+}
+
+
+static gint mp3file_header_frequency(MP3Header *h) {
+    return frequencies[h->version][h->freq];
+}
+
+
+gint frame_length(MP3Header *header) {
+	return header->sync == 0xFFE ?
+		    (frame_size_index[3-header->layer]*((header->version&1)+1)*
+		    mp3file_header_bitrate(header)/(float)mp3file_header_frequency(header))+
+		    header->padding : 1;
+}
+
+/* Get next MP3 frame header.
+   Return codes:
+   positive value = Frame Length of this header
+   0 = No, we did not retrieve a valid frame header
+*/
+gint get_header(FILE *file,MP3Header *header)
+{
+    guchar buffer[FRAME_HEADER_SIZE];
+    gint fl;
+
+    if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
+	header->sync=0;
+	return 0;
+    }
+    header->sync=(((gint)buffer[0]<<4) | ((gint)(buffer[1]&0xE0)>>4));
+    if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
+		    else header->version=2;
+    header->layer=(buffer[1] >> 1) & 3;
+    if (header->layer == 0)
+    {
+	header->layer = 1; /* sanity added by JCS */
+    }
+    if((header->sync != 0xFFE) || (header->layer != 1)) {
+	header->sync=0;
+	return 0;
+    }
+    header->crc=buffer[1] & 1;
+    header->bitrate=(buffer[2] >> 4) & 0x0F;
+    header->freq=(buffer[2] >> 2) & 0x3;
+    header->padding=(buffer[2] >>1) & 0x1;
+    header->extension=(buffer[2]) & 0x1;
+    header->mode=(buffer[3] >> 6) & 0x3;
+    header->mode_extension=(buffer[3] >> 4) & 0x3;
+    header->copyright=(buffer[3] >> 3) & 0x1;
+    header->original=(buffer[3] >> 2) & 0x1;
+    header->emphasis=(buffer[3]) & 0x3;
+
+    return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0);
+}
+
+gint sameConstant(MP3Header *h1, MP3Header *h2) {
+    if((*(guint*)h1) == (*(guint*)h2)) return 1;
+
+    if((h1->version       == h2->version         ) &&
+       (h1->layer         == h2->layer           ) &&
+       (h1->crc           == h2->crc             ) &&
+       (h1->freq          == h2->freq            ) &&
+       (h1->mode          == h2->mode            ) &&
+       (h1->copyright     == h2->copyright       ) &&
+       (h1->original      == h2->original        ) &&
+       (h1->emphasis      == h2->emphasis        ))
+		return 1;
+    else return 0;
+}
+
+
+gint get_first_header(MP3Info *mp3, long startpos)
+{
+  gint k, l=0,c;
+  MP3Header h, h2;
+  long valid_start=0;
+
+  fseek(mp3->file,startpos,SEEK_SET);
+  while (1) {
+     while((c=fgetc(mp3->file)) != 255 && (c != EOF));
+     if(c == 255) {
+	ungetc(c,mp3->file);
+	valid_start=ftell(mp3->file);
+	if((l=get_header(mp3->file,&h))) {
+	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
+	    if(!(l=get_header(mp3->file,&h2))) break;
+	    if(!sameConstant(&h,&h2)) break;
+	    fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  }
+	  if(k == MIN_CONSEC_GOOD_FRAMES) {
+		fseek(mp3->file,valid_start,SEEK_SET);
+		memcpy(&(mp3->header),&h2,sizeof(MP3Header));
+		mp3->header_isvalid=1;
+		return 1;
+	  }
+	}
+     } else {
+	return 0;
+     }
+   }
+
+  return 0;
+}
+
+
+/* get_next_header() - read header at current position or look for
+   the next valid header if there isn't one at the current position
+*/
+gint get_next_header(MP3Info *mp3)
+{
+  gint l=0,c,skip_bytes=0;
+  MP3Header h;
+
+   while(1) {
+     while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
+     if(c == 255) {
+	ungetc(c,mp3->file);
+	if((l=get_header(mp3->file,&h))) {
+	  if(skip_bytes) mp3->badframes++;
+	  fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
+	  return 15-h.bitrate;
+	} else {
+		skip_bytes += FRAME_HEADER_SIZE;
+	}
+     } else {
+	  if(skip_bytes) mp3->badframes++;
+	  return 0;
+     }
+  }
+}
+
+
+void get_mp3_info(MP3Info *mp3)
+{
+  gint frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  float milliseconds=0,total_rate=0;
+  gint frames=0,frame_types=0,frames_so_far=0;
+  gint vbr_median=-1;
+  guint bitrate;
+  gint counter=0;
+  MP3Header header;
+  struct stat filestat;
+  off_t data_start=0;
+
+
+  stat(mp3->filename,&filestat);
+  mp3->datasize=filestat.st_size;
+
+  if(get_first_header(mp3,0L)) {
+      data_start=ftell(mp3->file);
+      while((bitrate=get_next_header(mp3))) {
+	  if (bitrate < 15)  /* sanity added by JCS */
+	      frame_type[15-bitrate]++;
+	  frames++;
+      }
+      memcpy(&header,&(mp3->header),sizeof(MP3Header));
+      for(counter=0;counter<15;counter++) {
+	  if(frame_type[counter]) {
+	      float header_bitrate; /* introduced by JCS to speed up */
+	      frame_types++;
+	      header.bitrate=counter;
+	      frames_so_far += frame_type[counter];
+	      header_bitrate = mp3file_header_bitrate(&header);
+	      if (header_bitrate != 0)
+		  milliseconds += (float)(8*frame_length(&header)*frame_type[counter])/header_bitrate;
+	      total_rate += header_bitrate*frame_type[counter];
+	      if((vbr_median == -1) && (frames_so_far >= frames/2))
+		  vbr_median=counter;
+	  }
+      }
+      mp3->milliseconds=(gint)(milliseconds+0.5);
+      mp3->header.bitrate=vbr_median;
+      mp3->vbr_average=total_rate/(float)frames;
+      mp3->frames=frames;
+      if(frame_types > 1) {
+	  mp3->vbr=1;
+      }
+  }
+}
+
+
+
+
+/* ------------------------------------------------------------
+
+	 xmms code
+
+
+   ------------------------------------------------------------ */
+
+/*
+|  Changed by Jorg Schuler <jcsjcs at users.sourceforge.net> to
+|  compile with the gtkpod project. 2003/04/01
+*/
+
+/* This code is taken from the mpg123 code used in xmms-1.2.7
+ * (Input/mpg123). Only the code needed for the playlength calculation
+ * has been extracted */
+
+#include "mp3file.h"
+#include <stdio.h>
+#include <string.h>
+
+#define FRAMES_FLAG     0x0001
+#define BYTES_FLAG      0x0002
+#define TOC_FLAG        0x0004
+#define VBR_SCALE_FLAG  0x0008
+
+#define         SBLIMIT                 32
+#define         SCALE_BLOCK             12
+#define         SSLIMIT                 18
+
+#define         MPG_MD_STEREO           0
+#define         MPG_MD_JOINT_STEREO     1
+#define         MPG_MD_DUAL_CHANNEL     2
+#define         MPG_MD_MONO             3
+#define MAXFRAMESIZE 1792
+#define real float
+
+struct bitstream_info
+{
+	int bitindex;
+	unsigned char *wordpointer;
+};
+
+struct bitstream_info bsi;
+
+real mpg123_muls[27][64];	/* also used by layer 1 */
+
+int tabsel_123[2][3][16] =
+{
+	{
+    {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+       {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+       {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
+
+	{
+       {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+	    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}}
+};
+
+long mpg123_freqs[9] =
+{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
+
+/*
+ * structure to receive extracted header
+ */
+typedef struct
+{
+	int frames;		/* total bit stream frames from Xing header data */
+	int bytes;		/* total bit stream bytes from Xing header data */
+	unsigned char toc[100];	/* "table of contents" */
+} xing_header_t;
+
+struct al_table
+{
+	short bits;
+	short d;
+};
+
+struct frame
+{
+	struct al_table *alloc;
+	int (*synth) (real *, int, unsigned char *, int *);
+	int (*synth_mono) (real *, unsigned char *, int *);
+#ifdef USE_3DNOW
+	void (*dct36)(real *,real *,real *,real *,real *);
+#endif
+	int stereo;
+	int jsbound;
+	int single;
+	int II_sblimit;
+	int down_sample_sblimit;
+	int lsf;
+	int mpeg25;
+	int down_sample;
+	int header_change;
+	int lay;
+	int (*do_layer) (struct frame * fr);
+	int error_protection;
+	int bitrate_index;
+	int sampling_frequency;
+	int padding;
+	int extension;
+	int mode;
+	int mode_ext;
+	int copyright;
+	int original;
+	int emphasis;
+	int framesize;		/* computed framesize */
+};
+
+static guint32 convert_to_header(guint8 * buf)
+{
+
+	return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+}
+
+static int mpg123_head_check(unsigned long head)
+{
+	if ((head & 0xffe00000) != 0xffe00000)
+		return FALSE;
+	if (!((head >> 17) & 3))
+		return FALSE;
+	if (((head >> 12) & 0xf) == 0xf)
+		return FALSE;
+	if (!((head >> 12) & 0xf))
+		return FALSE;
+	if (((head >> 10) & 0x3) == 0x3)
+		return FALSE;
+	if (((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
+		return FALSE;
+	if ((head & 0xffff0000) == 0xfffe0000)
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/*
+ * the code a header and write the information
+ * into the frame structure
+ */
+static int mpg123_decode_header(struct frame *fr, unsigned long newhead)
+{
+    int ssize;
+
+	if (newhead & (1 << 20))
+	{
+		fr->lsf = (newhead & (1 << 19)) ? 0x0 : 0x1;
+		fr->mpeg25 = 0;
+	}
+	else
+	{
+		fr->lsf = 1;
+		fr->mpeg25 = 1;
+	}
+	fr->lay = 4 - ((newhead >> 17) & 3);
+	if (fr->mpeg25)
+	{
+		fr->sampling_frequency = 6 + ((newhead >> 10) & 0x3);
+	}
+	else
+		fr->sampling_frequency = ((newhead >> 10) & 0x3) + (fr->lsf * 3);
+	fr->error_protection = ((newhead >> 16) & 0x1) ^ 0x1;
+
+	fr->bitrate_index = ((newhead >> 12) & 0xf);
+	fr->padding = ((newhead >> 9) & 0x1);
+	fr->extension = ((newhead >> 8) & 0x1);
+	fr->mode = ((newhead >> 6) & 0x3);
+	fr->mode_ext = ((newhead >> 4) & 0x3);
+	fr->copyright = ((newhead >> 3) & 0x1);
+	fr->original = ((newhead >> 2) & 0x1);
+	fr->emphasis = newhead & 0x3;
+
+	fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
+
+	ssize = 0;
+
+	if (!fr->bitrate_index)
+		return (0);
+
+	switch (fr->lay)
+	{
+		case 1:
+/*			fr->do_layer = mpg123_do_layer1; */
+/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
+			fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+			fr->framesize = ((fr->framesize + fr->padding) << 2) - 4;
+			break;
+		case 2:
+/*			fr->do_layer = mpg123_do_layer2; */
+/*			mpg123_init_layer2();	/\* inits also shared tables with layer1 *\/ */
+			fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+			fr->framesize += fr->padding - 4;
+			break;
+		case 3:
+/*			fr->do_layer = mpg123_do_layer3; */
+			if (fr->lsf)
+				ssize = (fr->stereo == 1) ? 9 : 17;
+			else
+				ssize = (fr->stereo == 1) ? 17 : 32;
+			if (fr->error_protection)
+				ssize += 2;
+			fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
+			fr->framesize /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			fr->framesize = fr->framesize + fr->padding - 4;
+			break;
+		default:
+			return (0);
+	}
+	if(fr->framesize > MAXFRAMESIZE)
+		return 0;
+	return 1;
+}
+
+#define GET_INT32BE(b) \
+(i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i)
+
+static int mpg123_get_xing_header(xing_header_t * xing, unsigned char *buf)
+{
+	int i, head_flags;
+	int id, mode;
+
+	memset(xing, 0, sizeof(xing_header_t));
+
+	/* get selected MPEG header data */
+	id = (buf[1] >> 3) & 1;
+	mode = (buf[3] >> 6) & 3;
+	buf += 4;
+
+	/* Skip the sub band data */
+	if (id)
+	{
+		/* mpeg1 */
+		if (mode != 3)
+			buf += 32;
+		else
+			buf += 17;
+	}
+	else
+	{
+		/* mpeg2 */
+		if (mode != 3)
+			buf += 17;
+		else
+			buf += 9;
+	}
+
+	if (strncmp(buf, "Xing", 4))
+		return 0;
+	buf += 4;
+
+	head_flags = GET_INT32BE(buf);
+
+	if (head_flags & FRAMES_FLAG)
+		xing->frames = GET_INT32BE(buf);
+	if (xing->frames < 1)
+		xing->frames = 1;
+	if (head_flags & BYTES_FLAG)
+		xing->bytes = GET_INT32BE(buf);
+
+	if (head_flags & TOC_FLAG)
+	{
+		for (i = 0; i < 100; i++)
+			xing->toc[i] = buf[i];
+		buf += 100;
+	}
+
+#ifdef XING_DEBUG
+	for (i = 0; i < 100; i++)
+	{
+		if ((i % 10) == 0)
+			fprintf(stderr, "\n");
+		fprintf(stderr, " %3d", xing->toc[i]);
+	}
+#endif
+
+	return 1;
+}
+
+static double mpg123_compute_tpf(struct frame *fr)
+{
+	const int bs[4] = {0, 384, 1152, 1152};
+	double tpf;
+
+	tpf = bs[fr->lay];
+	tpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+	return tpf;
+}
+
+static double mpg123_compute_bpf(struct frame *fr)
+{
+	double bpf;
+
+	switch (fr->lay)
+	{
+		case 1:
+			bpf = tabsel_123[fr->lsf][0][fr->bitrate_index];
+			bpf *= 12000.0 * 4.0;
+			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			break;
+		case 2:
+		case 3:
+			bpf = tabsel_123[fr->lsf][fr->lay - 1][fr->bitrate_index];
+			bpf *= 144000;
+			bpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+			break;
+		default:
+			bpf = 1.0;
+	}
+
+	return bpf;
+}
+
+
+unsigned int mpg123_getbits(int number_of_bits)
+{
+	unsigned long rval;
+
+#ifdef DEBUG_GETBITS
+	fprintf(stderr, "g%d", number_of_bits);
+#endif
+
+	if(!number_of_bits)
+		return 0;
+
+#if 0
+	check_buffer_range(number_of_bits + bsi.bitindex);
+#endif
+
+	{
+		rval = bsi.wordpointer[0];
+		rval <<= 8;
+		rval |= bsi.wordpointer[1];
+		rval <<= 8;
+		rval |= bsi.wordpointer[2];
+
+		rval <<= bsi.bitindex;
+		rval &= 0xffffff;
+
+		bsi.bitindex += number_of_bits;
+
+		rval >>= (24-number_of_bits);
+
+		bsi.wordpointer += (bsi.bitindex >> 3);
+		bsi.bitindex &= 7;
+	}
+
+#ifdef DEBUG_GETBITS
+	fprintf(stderr,":%x ",rval);
+#endif
+
+	return rval;
+}
+
+
+void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT], struct frame *fr)
+{
+	unsigned int *ba = balloc;
+	unsigned int *sca = (unsigned int *) scale_index;
+
+	if (fr->stereo)
+	{
+		int i;
+		int jsbound = fr->jsbound;
+
+		for (i = 0; i < jsbound; i++)
+		{
+			*ba++ = mpg123_getbits(4);
+			*ba++ = mpg123_getbits(4);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			*ba++ = mpg123_getbits(4);
+
+		ba = balloc;
+
+		for (i = 0; i < jsbound; i++)
+		{
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			if ((*ba++))
+			{
+				*sca++ = mpg123_getbits(6);
+				*sca++ = mpg123_getbits(6);
+			}
+	}
+	else
+	{
+		int i;
+
+		for (i = 0; i < SBLIMIT; i++)
+			*ba++ = mpg123_getbits(4);
+		ba = balloc;
+		for (i = 0; i < SBLIMIT; i++)
+			if ((*ba++))
+				*sca++ = mpg123_getbits(6);
+	}
+}
+
+void I_step_two(real fraction[2][SBLIMIT], unsigned int balloc[2 * SBLIMIT],
+		unsigned int scale_index[2][SBLIMIT], struct frame *fr)
+{
+	int i, n;
+	int smpb[2 * SBLIMIT];	/* values: 0-65535 */
+	int *sample;
+	register unsigned int *ba;
+	register unsigned int *sca = (unsigned int *) scale_index;
+
+	if (fr->stereo)
+	{
+		int jsbound = fr->jsbound;
+		register real *f0 = fraction[0];
+		register real *f1 = fraction[1];
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < jsbound; i++)
+		{
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < jsbound; i++)
+		{
+			if ((n = *ba++))
+				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f0++ = 0.0;
+			if ((n = *ba++))
+				*f1++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f1++ = 0.0;
+		}
+		for (i = jsbound; i < SBLIMIT; i++)
+		{
+			if ((n = *ba++))
+			{
+				real samp = (((-1) << n) + (*sample++) + 1);
+
+				*f0++ = samp * mpg123_muls[n + 1][*sca++];
+				*f1++ = samp * mpg123_muls[n + 1][*sca++];
+			}
+			else
+				*f0++ = *f1++ = 0.0;
+		}
+		for (i = fr->down_sample_sblimit; i < 32; i++)
+			fraction[0][i] = fraction[1][i] = 0.0;
+	}
+	else
+	{
+		register real *f0 = fraction[0];
+
+		ba = balloc;
+		for (sample = smpb, i = 0; i < SBLIMIT; i++)
+			if ((n = *ba++))
+				*sample++ = mpg123_getbits(n + 1);
+		ba = balloc;
+		for (sample = smpb, i = 0; i < SBLIMIT; i++)
+		{
+			if ((n = *ba++))
+				*f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++];
+			else
+				*f0++ = 0.0;
+		}
+		for (i = fr->down_sample_sblimit; i < 32; i++)
+			fraction[0][i] = 0.0;
+	}
+}
+
+static guint get_track_time_file(FILE * file)
+{
+	guint32 head;
+	guchar tmp[4], *buf;
+	struct frame frm;
+	xing_header_t xing_header;
+	double tpf, bpf;
+	guint32 len;
+
+	if (!file)
+		return -1;
+
+	fseek(file, 0, SEEK_SET);
+	if (fread(tmp, 1, 4, file) != 4)
+		return 0;
+	head = convert_to_header(tmp);
+	while (!mpg123_head_check(head))
+	{
+		head <<= 8;
+		if (fread(tmp, 1, 1, file) != 1)
+			return 0;
+		head |= tmp[0];
+	}
+	if (mpg123_decode_header(&frm, head))
+	{
+		buf = g_malloc(frm.framesize + 4);
+		fseek(file, -4, SEEK_CUR);
+		fread(buf, 1, frm.framesize + 4, file);
+		tpf = mpg123_compute_tpf(&frm);
+		if (mpg123_get_xing_header(&xing_header, buf))
+		{
+			g_free(buf);
+			return ((guint) (tpf * xing_header.frames * 1000));
+		}
+		g_free(buf);
+		bpf = mpg123_compute_bpf(&frm);
+		fseek(file, 0, SEEK_END);
+		len = ftell(file);
+		fseek(file, -128, SEEK_END);
+		fread(tmp, 1, 3, file);
+		if (!strncmp(tmp, "TAG", 3))
+			len -= 128;
+		return ((guint) ((guint)(len / bpf) * tpf * 1000));
+	}
+	return 0;
+}
+
+static guint get_track_time (gchar *path)
+{
+    guint result = 0;
+
+    if (path)
+    {
+	FILE *file = fopen (path, "r");
+	result = get_track_time_file (file);
+	if (file) fclose (file);
+    }
+    return result;
+}
+
+
+/* libid3tag stuff */
+
+#include <id3tag.h>
+#include "prefs.h"
+
+#ifndef ID3_FRAME_GROUP
+#define ID3_FRAME_GROUP "TPE2"
+#endif
+
+
+
+static const gchar* id3_get_binary (struct id3_tag *tag,
+				    char *frame_name,
+				    id3_length_t *len,
+				    int index)
+{
+    const id3_byte_t *binary = NULL;
+    struct id3_frame *frame;
+    union id3_field *field;
+
+    g_return_val_if_fail (len, NULL);
+
+    *len = 0;
+
+    frame = id3_tag_findframe (tag, frame_name, index);
+#if LOCALDEBUG
+    printf ("frame: %p\n", frame); 
+#endif
+
+    if (!frame) return NULL;
+
+#if LOCALDEBUG
+    printf (" nfields: %d\n", frame->nfields);
+    if (strncmp (frame_name, "APIC",  4) == 0)
+    {
+	field = id3_frame_field (frame, 2);
+	printf (" picture type: %ld\n", field->number.value);
+    }
+#endif
+
+
+#if 0
+/*-----------------*/
+/* just to show that this field (before last) contains the d8 ff e0 ff
+   part of the start of a jpeg file when the coverart war embedded by iTunes */
+
+    const id3_ucs4_t *string = NULL;
+    gchar *raw = NULL;
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-2);
+
+#if LOCALDEBUG
+     printf (" field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf (" type: %d\n", field->type);
+#endif
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_STRING:
+	string = id3_field_getstring (field);
+	break;
+    default:
+	break;
+    }
+  
+    /* ISO_8859_1 is just a "marker" -- most people just drop
+       whatever coding system they are using into it, so we use
+       charset_to_utf8() to convert to utf8 */
+
+    if (string)
+    {
+	raw = id3_ucs4_latin1duplicate (string);
+    }
+
+
+#if LOCALDEBUG
+    {
+	FILE *file;
+	printf (" string len: %d\n", raw?strlen(raw):0);
+	file = fopen ("/tmp/folder1.jpg", "w");
+	fwrite (raw, 1, raw?strlen(raw):0, file);
+	fclose (file);
+    }
+#endif
+    g_free (raw);
+
+/*-----------------*/
+#endif
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-1);
+
+#if LOCALDEBUG
+     printf (" field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf (" type: %d\n", field->type);
+#endif
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_BINARYDATA:
+	binary = id3_field_getbinarydata(field, len);
+	break;
+    default:
+	break;
+    }
+
+#if LOCALDEBUG
+    {
+	FILE *file;
+	printf (" binary len: %ld\n", *len);
+	file = fopen ("/tmp/folder2.jpg", "w");
+	fwrite (binary, 1, *len, file);
+	fclose (file);
+    }
+#endif
+
+
+
+    return binary;
+}
+
+
+
+static gchar* id3_get_string (struct id3_tag *tag, char *frame_name)
+{
+    const id3_ucs4_t *string = NULL;
+    const id3_byte_t *binary = NULL;
+    id3_length_t len = 0;
+    struct id3_frame *frame;
+    union id3_field *field;
+    gchar *utf8 = NULL;
+    enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
+
+    frame = id3_tag_findframe (tag, frame_name, 0);
+#if LOCALDEGUB
+    printf ("frame: %p\n", frame); 
+#endif
+
+    if (!frame) return NULL;
+
+    /* Find the encoding used for the field */
+    field = id3_frame_field (frame, 0);
+#if LOCALDEBUG
+    printf ("field: %p\n", field); 
+    printf ("type: %d\n", id3_field_type (field));
+#endif
+
+    if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
+    {
+	encoding = field->number.value;
+#if LOCALDEBUG
+	printf ("encoding: %d\n", encoding);
+#endif
+    }
+
+    /* The last field contains the data */
+    field = id3_frame_field (frame, frame->nfields-1);
+
+#if LOCALDEBUG
+     printf ("field: %p\n", field);
+#endif
+
+    if (!field) return NULL;
+
+#if LOCALDEBUG
+     printf ("type: %d\n", field->type);
+#endif
+
+
+    switch (field->type)
+    {
+    case ID3_FIELD_TYPE_STRINGLIST:
+	string = id3_field_getstrings (field, 0);
+	break;
+    case ID3_FIELD_TYPE_STRINGFULL:
+	string = id3_field_getfullstring (field);
+	break;
+    case ID3_FIELD_TYPE_BINARYDATA:
+	binary = id3_field_getbinarydata(field, &len);
+#if LOCALDEBUG
+	printf ("len: %ld\nbinary: %s\n", len, binary+1);
+#endif
+	if (len > 0)
+	    return charset_to_utf8 (binary+1);
+	break;
+    default:
+	break;
+    }
+
+/*     printf ("string: %p\n", string); */
+
+    if (!string) return NULL;
+
+    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
+       string = id3_genre_name (string);
+
+    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+    {
+	/* ISO_8859_1 is just a "marker" -- most people just drop
+	   whatever coding system they are using into it, so we use
+	   charset_to_utf8() to convert to utf8 */
+	id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
+	utf8 = charset_to_utf8 (raw);
+	g_free (raw);
+    }
+    else
+    {
+	/* Standard unicode is being used -- we won't have to worry
+	   about charsets then. */
+	utf8 = id3_ucs4_utf8duplicate (string);
+    }
+    return utf8;
+}
+
+static void id3_set_string (struct id3_tag *tag,
+			    const char *frame_name,
+			    const char *data,
+			    enum id3_field_textencoding encoding)
+{
+    int res;
+    struct id3_frame *frame;
+    union id3_field *field;
+    id3_ucs4_t *ucs4;
+
+    /* clear the frame, because of bug in libid3tag see
+       http://www.mars.org/mailman/public/mad-dev/2004-October/001113.html
+    */
+    while ((frame = id3_tag_findframe (tag, frame_name, 0)))
+    {
+	id3_tag_detachframe (tag, frame);
+        id3_frame_delete (frame);
+    }
+
+    if ((data == NULL) || (strlen(data) == 0))
+	return;
+
+    frame = id3_frame_new (frame_name);
+    id3_tag_attachframe (tag, frame);
+
+    /* Use the specified text encoding */
+    field = id3_frame_field (frame, 0);
+    id3_field_settextencoding(field, encoding);
+   
+    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
+    {
+	field = id3_frame_field (frame, 3);
+	field->type = ID3_FIELD_TYPE_STRINGFULL;
+    }
+    else
+    {
+	field = id3_frame_field (frame, 1);
+	field->type = ID3_FIELD_TYPE_STRINGLIST;
+    }
+
+
+    /* maybe could be optimized see
+       http://www.mars.org/mailman/public/mad-dev/2002-October/000739.html
+    */
+    if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
+    {
+	id3_ucs4_t *tmp_ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
+	int index = id3_genre_number (tmp_ucs4);
+	if (index != -1)
+	{
+	    /* valid genre -- simply store the genre number */
+	    gchar *tmp = g_strdup_printf("%d", index);
+	    ucs4 = id3_latin1_ucs4duplicate (tmp);
+	    g_free (tmp);
+	}
+	else
+	{
+	    /* oups -- not a valid genre -- save the entire genre string */
+	    if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+	    {
+		/* we read 'ISO_8859_1' to stand for 'any locale
+		   charset' -- most programs seem to work that way */
+		id3_latin1_t *raw = charset_from_utf8 (data);
+		ucs4 = id3_latin1_ucs4duplicate (raw);
+		g_free (raw);
+	    }
+	    else
+	    {
+		/* Yeah! We use unicode encoding and won't have to
+		   worry about charsets */
+		ucs4 = tmp_ucs4;
+		tmp_ucs4 = NULL;
+	    }
+	}
+	g_free (tmp_ucs4);
+    }
+    else
+    {
+	if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
+	{
+	    /* we read 'ISO_8859_1' to stand for 'any locale charset'
+	       -- most programs seem to work that way */
+	    id3_latin1_t *raw = charset_from_utf8 (data);
+	    ucs4 = id3_latin1_ucs4duplicate (raw);
+	    g_free (raw);
+	}
+	else
+	{
+	    /* Yeah! We use unicode encoding and won't have to
+	       worry about charsets */
+	    ucs4 = id3_utf8_ucs4duplicate ((id3_utf8_t *)data);
+	}
+    }
+
+    if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
+	res = id3_field_setfullstring (field, ucs4);
+    else
+	res = id3_field_setstrings (field, 1, &ucs4);
+
+    g_free (ucs4);
+
+    if (res != 0)
+	g_print(_("Error setting ID3 field: %s\n"), frame_name);
+}
+
+
+/***
+ * Reads id3v1.x / id3v2 apic data
+ * @returns: TRUE on success, else FALSE.
+ */
+static gboolean id3_apic_read (gchar *filename,
+			       guchar **image_data, gsize *image_data_len)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+
+    g_return_val_if_fail (filename, FALSE);
+    g_return_val_if_fail (image_data, FALSE);
+    g_return_val_if_fail (image_data_len, FALSE);
+
+    *image_data = NULL;
+    *image_data_len = 0;
+
+    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	id3_length_t len;
+	const guchar *coverart = NULL;
+	int i;
+	struct id3_frame *frame;
+
+	/* Loop through APIC tags and set coverart.  The picture type should be
+	 * 3 -- Cover (front), but iTunes has been known to use 0 -- Other. */
+	for (i = 0; (frame = id3_tag_findframe(id3tag, "APIC", i)) != NULL; i++)
+	{
+	    union id3_field *field = id3_frame_field (frame, 2);
+	    int pictype = field->number.value;
+/*	    printf ("%s: found apic type %d\n", filename, pictype);*/
+
+	    /* We'll prefer type 3 (cover) over type 0 (other) */
+	    if (pictype == 3)
+	    {
+		coverart = id3_get_binary (id3tag, "APIC", &len, i);
+		break;
+	    }
+	    if ((pictype == 0) && !coverart)
+	    {
+		coverart = id3_get_binary (id3tag, "APIC", &len, i);
+	    }
+	}
+
+	if (coverart)
+	{   /* I guess iTunes is doing something wrong -- the
+	     * beginning of the coverart data ends up in a different
+	       field... We'll just add the missing data manually. */
+	    const guchar itunes_broken_jfif_marker[] =
+		{ 0x10, 'J', 'F', 'I', 'F'};
+	    if (len >= 5)
+	    {
+		if (strncmp (itunes_broken_jfif_marker, coverart,  5) == 0)
+		{
+		    const guchar itunes_missing_header[] =
+			{ 0xff, 0xd8, 0xff, 0xe0, 0x00 };
+		    *image_data = g_malloc (len+5);
+		    memcpy (*image_data, itunes_missing_header, 5);
+		    memcpy ((*image_data)+5, coverart, len);
+		    *image_data_len = len+5;
+		}
+	    }
+	    if (!*image_data)
+	    {
+		*image_data = g_malloc (len);
+		memcpy (*image_data, coverart, len);
+		*image_data_len = len;
+	    }
+#if LOCALDEBUG
+	    if (*image_data)
+	    {
+		FILE *file;
+		file = fopen ("/tmp/folder.jpg", "w");
+		fwrite (*image_data, 1, *image_data_len, file);
+		fclose (file);
+	    }
+#endif
+	}    
+    }
+    id3_file_close (id3file);
+    return TRUE;
+}
+
+/***
+ * Reads id3v1.x / id3v2 tag and load data into the Id3tag structure.
+ * If a tag entry exists (ex: title), we allocate memory, else value
+ * stays to NULL
+ * @returns: TRUE on success, else FALSE.
+ */
+gboolean id3_tag_read (gchar *filename, File_Tag *tag)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+    gchar* string;
+    gchar* string2;
+
+    g_return_val_if_fail (filename, FALSE);
+    g_return_val_if_fail (tag, FALSE);
+
+    memset (tag, 0, sizeof (File_Tag));
+
+    if (!(id3file = id3_file_open (filename, ID3_FILE_MODE_READONLY)))
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	tag->title = id3_get_string (id3tag, ID3_FRAME_TITLE);
+	tag->artist = id3_get_string (id3tag, ID3_FRAME_GROUP);
+	if (!tag->artist || !*tag->artist)
+	{
+	    g_free (tag->artist);
+	    tag->artist = id3_get_string (id3tag, ID3_FRAME_ARTIST);
+	}
+	tag->album = id3_get_string (id3tag, ID3_FRAME_ALBUM);
+	tag->year = id3_get_string (id3tag, ID3_FRAME_YEAR);
+	tag->composer = id3_get_string (id3tag, "TCOM");
+	tag->comment = id3_get_string (id3tag, ID3_FRAME_COMMENT);
+	tag->genre = id3_get_string (id3tag, ID3_FRAME_GENRE);
+	tag->compilation = id3_get_string (id3tag, "TCMP");
+	tag->subtitle = id3_get_string (id3tag, "TIT3");
+	tag->lyrics = id3_get_string (id3tag, "USLT");
+	tag->podcasturl = id3_get_string (id3tag, "YTID");
+	tag->podcastrss = id3_get_string (id3tag, "YWFD");
+	tag->description = id3_get_string (id3tag, "YTDS");
+	tag->time_released = id3_get_string (id3tag, "YTDR");
+	tag->BPM = id3_get_string (id3tag, "TBPM");
+	tag->sort_artist = id3_get_string (id3tag, "TSOP");
+	tag->sort_album = id3_get_string (id3tag, "TSOA");
+	tag->sort_title = id3_get_string (id3tag, "TSOT");
+	tag->sort_albumartist = id3_get_string (id3tag, "TSO2");
+	tag->sort_composer = id3_get_string (id3tag, "TSOC");
+
+	string = id3_get_string (id3tag, "TLEN");
+	if (string)
+	{
+	    tag->songlen = (guint32) strtoul (string, 0, 10);
+	    g_free (string);
+	}
+
+	string = id3_get_string (id3tag, ID3_FRAME_TRACK);
+	if (string)
+	{
+	    string2 = strchr(string,'/');
+	    if (string2)
+	    {
+		tag->track_total = g_strdup_printf ("%.2d", atoi (string2+1));
+		*string2 = '\0';
+	    }
+	    tag->trackstring = g_strdup_printf ("%.2d", atoi (string));
+	    g_free(string);
+	}
+	
+	/* CD/disc number tag handling */
+	string = id3_get_string (id3tag, "TPOS");
+	if (string)
+	{
+	    string2 = strchr(string,'/');
+	    if (string2)
+	    {
+		tag->cdno_total = g_strdup_printf ("%.2d", atoi (string2+1));
+		*string2 = '\0';
+	    }
+	    tag->cdnostring = g_strdup_printf ("%.2d", atoi (string));
+	    g_free(string);
+	}
+    }
+
+    id3_file_close (id3file);
+    return TRUE;
+}
+
+
+
+static enum id3_field_textencoding get_encoding_of (struct id3_tag *tag, const char *frame_name)
+{
+    struct id3_frame *frame;
+    enum id3_field_textencoding encoding = -1;
+
+    frame = id3_tag_findframe (tag, frame_name, 0);
+    if (frame)
+    {
+	union id3_field *field = id3_frame_field (frame, 0);
+	if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
+	    encoding = field->number.value;
+    }
+    return encoding;
+}
+
+/* Find out which encoding is being used. If in doubt, return
+ * latin1. This code assumes that the same encoding is used in all
+ * fields.  */
+static enum id3_field_textencoding get_encoding (struct id3_tag *tag)
+{
+    enum id3_field_textencoding enc;
+
+    enc = get_encoding_of (tag, ID3_FRAME_TITLE);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_ARTIST);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_ALBUM);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, "TCOM");
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_COMMENT);
+    if (enc != -1) return enc;
+    enc = get_encoding_of (tag, ID3_FRAME_YEAR);
+    if (enc != -1) return enc;
+    return ID3_FIELD_TEXTENCODING_ISO_8859_1;
+}
+
+
+/* I'm not really sure about this: The original TAG identifier was
+   "TID", but no matter what I do I end up writing "YTID" */
+void set_uncommon_tag (struct id3_tag *id3tag,
+		       const gchar *id,
+		       const gchar *text,
+		       enum id3_field_textencoding encoding)
+{
+#if 0
+    struct id3_frame *frame;
+
+    frame = id3_tag_findframe (id3tag, id, 0);
+	union id3_field *field;
+	frame->flags = 0;
+	field = id3_frame_field (frame, 0);
+	    if (field)
+	    {
+		string1 = g_strdup_printf ("%c%s", '\0',
+					   track->podcasturl);
+		id3_field_setbinarydata (field, string1,
+					 strlen(track->podcasturl)+1);
+		g_free (string1);
+	    }
+
+#endif
+}
+
+
+
+/**
+ * Write the ID3 tags to the file.
+ * @returns: TRUE on success, else FALSE.
+ */
+gboolean mp3_write_file_info (gchar *filename, Track *track)
+{
+    struct id3_tag* id3tag;
+    struct id3_file* id3file;
+    gint error = 0;
+
+    id3file = id3_file_open (filename, ID3_FILE_MODE_READWRITE);
+    if (!id3file)
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while opening file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    if ((id3tag = id3_file_tag(id3file)))
+    {
+	char *string1;
+
+	enum id3_field_textencoding encoding;
+
+	/* use the same coding as before... */
+	encoding = get_encoding (id3tag);
+	/* ...unless it's ISO_8859_1 and prefs say we should use
+	   unicode (i.e. ID3v2.4) */
+	if (prefs_get_int("id3_write_id3v24") &&
+	    (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1))
+	    encoding = ID3_FIELD_TEXTENCODING_UTF_8;
+
+	/* always render id3v1 to prevent dj studio from crashing */
+	id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);
+
+        /* turn off frame compression and crc information to let
+	   itunes read tags see
+	   http://www.mars.org/mailman/public/mad-dev/2002-October/000742.html
+	*/
+	id3_tag_options(id3tag, ID3_TAG_OPTION_COMPRESSION, 0);
+	id3_tag_options(id3tag, ID3_TAG_OPTION_CRC, 0);
+
+	id3_set_string (id3tag, ID3_FRAME_TITLE, track->title, encoding);
+	id3_set_string (id3tag, ID3_FRAME_ARTIST, track->artist, encoding);
+	id3_set_string (id3tag, ID3_FRAME_ALBUM, track->album, encoding);
+	id3_set_string (id3tag, ID3_FRAME_GENRE, track->genre, encoding);
+	id3_set_string (id3tag, ID3_FRAME_COMMENT, track->comment, encoding);
+	id3_set_string (id3tag, "TIT3", track->subtitle, encoding);
+	id3_set_string (id3tag, "TSOP", track->sort_artist, encoding);
+	id3_set_string (id3tag, "TSOA", track->sort_album, encoding);
+	id3_set_string (id3tag, "TSOT", track->sort_title, encoding);
+	id3_set_string (id3tag, "TSO2", track->sort_albumartist, encoding);
+	id3_set_string (id3tag, "TSOC", track->sort_composer, encoding);
+
+	set_uncommon_tag (id3tag, "YTID", track->podcasturl, encoding);
+	set_uncommon_tag (id3tag, "YTDS", track->description, encoding);
+	set_uncommon_tag (id3tag, "YWFD", track->podcastrss, encoding);
+
+	id3_set_string (id3tag, "TCOM", track->composer, encoding);
+
+	string1 = g_strdup_printf("%d", track->year);
+	id3_set_string(id3tag, ID3_FRAME_YEAR, string1, encoding);
+	g_free(string1);
+
+	string1 = g_strdup_printf("%d", track->BPM);
+	id3_set_string(id3tag, "TBPM", string1, encoding);
+	g_free(string1);
+
+	if (track->tracks)
+	    string1 = g_strdup_printf ("%d/%d",
+				       track->track_nr, track->tracks);
+	else
+	    string1 = g_strdup_printf ("%d", track->track_nr);
+	id3_set_string (id3tag, ID3_FRAME_TRACK, string1, encoding);
+	g_free(string1);
+
+	if (track->cds)
+	    string1 = g_strdup_printf ("%d/%d",
+				       track->cd_nr, track->cds);
+	else
+	    string1 = g_strdup_printf ("%d", track->cd_nr);
+	id3_set_string (id3tag, "TPOS", string1, encoding);
+	g_free(string1);
+        
+       string1 = g_strdup_printf ("%d", track->compilation);
+       id3_set_string (id3tag, "TCMP", string1, encoding);
+       g_free(string1);
+    } 
+
+    if (id3_file_update(id3file) != 0)
+    {
+	gchar *fbuf = charset_to_utf8 (filename);
+	g_print(_("ERROR while writing tag to file: '%s' (%s).\n"),
+		fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return FALSE;
+    }
+
+    id3_file_close (id3file);
+
+    if (error) return FALSE;
+    else       return TRUE;
+}
+
+
+/*
+ * Code to read the ReplayGain Values stored by LAME in its own tag.
+ *
+ * Most of the relevant information has been extracted from them LAME sources
+ * (http://lame.sourceforge.net/).
+ * The "Mp3 info Tag rev 1 specifications - draft 0"
+ * (http://gabriel.mp3-tech.org/mp3infotag.html) by Gabriel Bouvigne describes
+ * the actual Tag (except for small changes).
+ * Details on the actual ReplayGain fields have been obtained from
+ * http://www.replaygain.org .
+ *
+ * Apart from that, some information has been derived from phwip's LameTag
+ * (http://www.silisoftware.com/applets/?scriptname=LameTag)
+ *
+ * 
+ * Code to read the ReplayGain Values stored in an Ape tag.
+ *
+ * Info on Lyrics3 V2.00 can be found at:
+ * http://www.id3.org/lyrics3200.html
+ * On the actual Ape Tag V2.0:
+ * http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
+ *
+ * Copyright (C) 2004 Jens Taprogge <jens.taprogge at post.rwth-aachen.de>
+ *
+ * Provided under GPL according to Jens Taprogge. (JCS -- 12 March 2004)
+ */
+
+#define TAG_FOOTER		0x10
+#define LAME_OFFSET		0x74
+#define SIDEINFO_MPEG1_MONO	17
+#define SIDEINFO_MPEG1_MULTI	32
+#define SIDEINFO_MPEG2_MONO	9
+#define SIDEINFO_MPEG2_MULTI	17
+#define ID3V1_SIZE		0x80
+#define APE_FOOTER_SIZE 	0x20
+#define LYRICS_FOOTER_SIZE 	0x0f
+
+
+static gint lame_vcmp(gchar a[5], gchar b[5]) {
+	int r;
+
+	r = strncmp(a, b, 4);
+	if (r) return r;
+
+	if (a[4] == b[4]) return 0;
+
+	/* check for '.': indicates subminor version */
+	if (a[4] == '.') return 1;
+	if (b[4] == '.') return -1;
+	
+	/* check for alpha or beta versions */
+	if (a[4] == ' ') return 1;
+	if (b[4] == ' ') return -1;
+
+	/* check for alpha, beta etc. indicated by a, b... */
+	return strncmp(&a[4], &b[4], 1);
+}
+
+
+/* buf[] must be declared unsigned -- otherwise the casts, shifts and
+   additions below produce funny results */             
+static void read_lame_replaygain(unsigned char buf[],
+				 GainData *gd, int gain_adjust) {
+	char oc, nc;
+	gint gain;
+
+	g_return_if_fail (gd);
+
+	/* buf[0] and buf[1] are a bit field:
+	   3 bits: name  (mask: 0xe0 = 11100000)
+	   3 bits: originator (mask: 0x1c = 00011100)
+	   1 bit: negative if set (mask: 0x02 = 00000010)
+	   9 bits: value
+	*/
+
+	/* check originator */
+	oc = (buf[0] & 0x1c) >> 2;
+	if ((oc <= 0) || (oc > 3)) return;
+
+	/* check name code */
+	nc = buf[0] & 0xe0;
+	if (!((nc == 0x20) || (nc == 0x40))) return;
+	
+	gain = ((((guint)buf[0]) & 0x1) << 8) + buf[1];
+	
+	/* This would be a value of -0.
+	 * That value however is illegal by current standards and reserved for
+	 * future use. */
+	if ((!gain) && (buf[0] & 0x02)) return;
+	
+	if (buf[0] & 2) gain = -gain;
+	
+	gain += gain_adjust;
+
+	switch (nc) {
+		case 0x20:
+			if (gd->radio_gain_set) return;
+			gd->radio_gain = (gdouble)gain / 10;
+			gd->radio_gain_set = TRUE;
+/*			printf("radio_gain (lame): %i\n", gd->radio_gain); */
+			break;
+		case 0x40:
+			if (gd->audiophile_gain_set) return;
+			gd->audiophile_gain = (gdouble)gain / 10;
+			gd->audiophile_gain_set = TRUE;
+/*			printf("audiophile_gain (lame): %i\n", 
+					gd->audiophile_gain);*/
+			break;
+	}
+}
+
+
+static inline guint32 parse_ape_uint32(char *buf) {
+	return (buf[0] & 0xff) | (buf[1] & 0xff) << 8 
+		| (buf[2] & 0xff) << 16 | (buf[3] & 0xff) << 24;
+}
+
+static inline guint32 parse_lame_uint32(char *buf) {
+	return (buf[0] & 0xff) << 24 | (buf[1] & 0xff) << 16 
+		| (buf[2] & 0xff) << 8 | (buf[3] & 0xff);
+}
+
+
+/* 
+ * mp3_get_track_lame_replaygain - read the specified file and scan for LAME Tag
+ * ReplayGain information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * FIXME: Are there other encoders writing a LAME Tag using a different magic
+ * string?
+ * TODO: Check CRC.
+ */
+
+gboolean mp3_get_track_lame_replaygain (gchar *path, GainData *gd)
+{
+	struct {
+		/* All members are defined in terms of chars so padding does not
+		 * occur. Is there a cleaner way to keep the compiler from
+		 * padding? */
+		
+		char     id[3];
+		char     version[2];
+		char     flags;
+		char     size[4];
+	} id3head;
+
+	FILE *file = NULL;
+	char buf[4], version[5];
+	int gain_adjust = 0;
+	int sideinfo;
+	guint32 ps;
+
+	g_return_val_if_fail (gd, FALSE);
+
+	gd->radio_gain = 0;
+	gd->audiophile_gain = 0;
+	gd->peak_signal = 0;
+	gd->radio_gain_set = FALSE;
+	gd->audiophile_gain_set = FALSE;
+	gd->peak_signal_set = FALSE;
+	
+	if (!path)
+		goto rg_fail;
+	
+	file = fopen (path, "r");
+
+	if (!file)
+	    goto rg_fail;
+
+	/* Skip ID3 header if appropriate */
+	if (fread(&id3head, 1, sizeof(id3head), file) != 
+			sizeof(id3head))
+		goto rg_fail;
+	
+	if (!strncmp(id3head.id, "ID3", 3)) {
+		int realsize = 0;
+		
+		realsize = (id3head.size[0] & 0x7f) << 21 
+			| (id3head.size[1] & 0x7f) << 14 
+			| (id3head.size[2] & 0x7f) << 7 
+			| (id3head.size[3] & 0x7f);
+
+		if (id3head.flags & TAG_FOOTER) {
+			/* footer is copy of header */
+			realsize += sizeof(id3head);
+		}
+
+		if (fseek(file, realsize-1, SEEK_CUR) ||
+				(!fread(&buf[0], 1, 1, file)))
+			goto rg_fail;
+	} else {
+		/* no ID3 Tag - go back */
+		fseek(file, -sizeof(id3head), SEEK_CUR);
+	}
+
+	/* Search Xing header. The location is dependant on the MPEG Layer and
+	 * whether the stream is mono or not. */
+	if (fread(buf, 1, 4, file) != 4) goto rg_fail;
+	
+	/* should start with 0xff 0xf? (synch) */
+	if (((buf[0] & 0xff) != 0xff) 
+			|| ((buf[1] & 0xf0) != 0xf0)) goto rg_fail;
+	
+	/* determine the length of the sideinfo */
+	if (buf[1] & 0x08) {
+		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
+			SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
+	} else {
+		sideinfo = ((buf[3] & 0xc0) == 0xc0) ? 
+			SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
+	}
+	
+	if (fseek(file, sideinfo, SEEK_CUR) ||
+			(fread(&buf[0], 1, 4, file) != 4))
+		goto rg_fail;
+	
+	/* Is this really a Xing or Info Header? 
+	 * FIXME: Apparently (according to madplay sources) there is a different
+	 * possible location for the Xing header ("due to an unfortunate
+	 * historical event"). I do not thing we need to care though since
+	 * RaplayGain information is only conatined in recent files.  */
+	if (strncmp(buf, "Xing", 4) && strncmp(buf, "Info", 4))
+		goto rg_fail;
+
+	/* Check for LAME Tag */
+	if (fseek(file, LAME_OFFSET, SEEK_CUR) ||
+				(fread(&buf[0], 1, 4, file) != 4))
+		goto rg_fail;
+	if (strncmp(buf, "LAME", 4))
+		goto rg_fail;
+	
+	/* Check LAME Version */
+	if (fread(version, 1, 5, file) != 5)
+		goto rg_fail;
+	
+	/* Skip really old versions altogether. I am not sure when radio_gain
+	 * information was introduced. 3.89 does not seem to supprt it though.
+	 * */
+	if (lame_vcmp(version, "3.90") < 0) {
+/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Not used.\n",
+				version[0], version[1], version[2], version[3], version[4]); */
+		goto rg_fail;
+	}
+		
+	if (fseek(file, 0x2, SEEK_CUR) || (fread(buf, 1, 4, file) != 4))
+		goto rg_fail;
+
+	/* get the peak signal. */
+	ps = parse_lame_uint32(buf);
+	
+	/* Don't know when fixed-point PeakSingleAmplitude
+	 * was introduced exactly. 3.94b will be used for now.) */
+	if ((lame_vcmp(version, "3.94b") >= 0)) {
+		if ((!gd->peak_signal_set) && ps) {
+			gd->peak_signal = ps;
+			gd->peak_signal_set = TRUE;
+/*			printf("peak_signal (lame): %f\n", (double)
+					gd->peak_signal / 0x800000);*/
+		}
+	} else {
+		float f = *((float *) (void *) (&ps)) * 0x800000;
+		gd->peak_signal = (guint32) f;
+		/* I would like to see an example of that. */
+/*		printf("peak_signal (lame floating point): %f. PLEASE report.\n", 
+				(double) gd->peak_signal / 0x800000);*/
+	}
+
+	/*
+	 * Versions prior to 3.95.1 used a reference volume of 83dB.
+	 * (As compared to the currently used 89dB.)
+	 */
+	if ((lame_vcmp(version, "3.95.") < 0)) {
+		gain_adjust = 60;
+/*		fprintf(stderr, "Old lame version (%c%c%c%c%c). Adjusting gain.\n",
+				version[0], version[1], version[2], version[3], version[4]); */
+	}
+
+	if (fread(&buf[0], 1, 2, file) != 2)
+		goto rg_fail;
+
+	/* radio gain */
+	read_lame_replaygain (buf, gd, gain_adjust);
+
+	if (fread(&buf[0], 1, 2, file) != 2)
+		goto rg_fail;
+
+	/* audiophile gain */
+	read_lame_replaygain (buf, gd, gain_adjust);
+
+	fclose(file);
+	return TRUE;
+
+rg_fail:
+	if (file)
+		fclose(file);
+	return FALSE;
+}
+
+
+/* 
+ * mp3_get_track_ape_replaygain - read the specified file and scan for Ape Tag
+ * ReplayGain information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * The function only modifies the gains if they have not previously been set.
+ */
+
+gboolean mp3_get_track_ape_replaygain(gchar *path, GainData *gd)
+{
+	/* The Ape Tag is located a t the end of the file. Or at least that
+	 * seems where it can most likely be found. Either it is at the very end
+	 * or before a trailing ID3v1 Tag. Sometimes a Lyrics3 Tag is placed
+	 * between the ID3v1 and the Ape Tag.
+	 * If you find files that have the Tags located in different
+	 * positions please let me know. */
+
+	FILE *file = NULL;
+	char buf[16];
+	char *dbuf = NULL, *ep;
+
+	int offset = 0;
+	int i;
+	int pos = 0, pos2 = 0;
+	guint32 version;
+	guint32 data_length;
+	guint32 entry_length = 0;
+	guint32 entries;
+	double d;
+
+	g_return_val_if_fail (gd, FALSE);
+	g_return_val_if_fail (path, FALSE);
+
+	file = fopen (path, "r");
+
+	if (!file)
+	    goto rg_fail;
+
+	/* check for ID3v1 Tag */
+	if (fseek(file, -ID3V1_SIZE, SEEK_END) ||
+			fread(&buf, 1, 3, file) != 3)
+		goto rg_fail;
+	if (!strncmp(buf, "TAG", 3)) offset -= ID3V1_SIZE;
+
+	/* check for Lyrics3 Tag */
+	if (fseek(file, -9 + offset, SEEK_END) ||
+			fread(&buf, 1, 9, file) != 9)
+		goto rg_fail;
+	if (!strncmp(buf, "LYRICS200", 9)) {
+		if (fseek(file, -LYRICS_FOOTER_SIZE + offset, SEEK_END) ||
+				fread(&buf, 1, 9, file) != 9)
+			goto rg_fail;
+		data_length = buf[0] - '0';
+		for (i = 1; i < 6; i++) {
+			data_length *= 10;
+			data_length += buf[i] - '0';
+		}
+		if (fseek(file, -LYRICS_FOOTER_SIZE - data_length + offset,
+					SEEK_END) ||
+				fread(&buf, 1, 11, file) != 11)
+			goto rg_fail;
+		if (!strncmp(buf, "LYRICSBEGIN", 11)) 
+			offset -= LYRICS_FOOTER_SIZE + data_length;
+	}
+
+	/* check for APE Tag */
+	if (fseek(file, -APE_FOOTER_SIZE + offset, SEEK_END) ||
+			fread(&buf, 1, 8, file) != 8)
+		goto rg_fail;
+	if (strncmp(buf, "APETAGEX", 8)) goto rg_fail;
+
+	/* Check the version of the tag. 1000 and 2000 (v1.0 and 2.0) are the
+	 * only ones I know about. Make suer things do not break in the future.
+	 * */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	version = parse_ape_uint32(buf);
+	if (version != 1000 && version != 2000)
+		goto rg_fail;
+
+	/* determine data length */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	data_length = parse_ape_uint32(buf) - APE_FOOTER_SIZE;
+
+	/* determine number of entries */
+	if (fread(&buf, 1, 4, file) != 4)
+		goto rg_fail;
+	entries = parse_ape_uint32(buf);
+
+	/* seek to first entry and read the whole buffer*/
+	if (fseek(file, -APE_FOOTER_SIZE + offset - data_length, SEEK_END))
+		goto rg_fail;
+	if (!(dbuf = malloc(data_length)))
+		goto rg_fail;
+	if (fread(dbuf, 1, data_length, file) != data_length)
+		goto rg_fail;
+	
+	for (i = 0; i < entries; i++) {
+		if (gd->radio_gain_set && gd->peak_signal_set) break;
+		pos = pos2 + entry_length;
+		if (pos > data_length - 10) break;
+		
+		entry_length = parse_ape_uint32(&dbuf[pos]); pos += 4;
+		pos += 4;
+		
+		pos2 = pos;
+		while (dbuf[pos2] && pos2 < data_length) pos2++;
+		if (pos2 == data_length) break;
+		pos2++;
+		
+		if (entry_length + 1 > sizeof(buf))
+			continue;
+/* 		printf ("%s:%d:%d\n",&dbuf[pos], pos2, pos); */
+		if (!gd->radio_gain_set && !strcasecmp(&dbuf[pos],
+					"REPLAYGAIN_TRACK_GAIN")) {
+			memcpy(buf, &dbuf[pos2], entry_length);
+			buf[entry_length] = '\0';
+			
+			d = g_ascii_strtod(buf, &ep);
+/* 			printf("%f\n", d); */
+			if ((ep == buf + entry_length - 3) 
+					&& (!strncasecmp(ep, " dB", 3))) {
+			    gd->radio_gain = d;
+				gd->radio_gain_set = TRUE;
+/*				printf("radio_gain (ape): %i\n", gd->radio_gain);*/
+			}
+			
+			continue;
+		}
+		if (!gd->peak_signal_set && !strcasecmp(&dbuf[pos],
+					"REPLAYGAIN_TRACK_PEAK")) {
+			memcpy(buf, &dbuf[pos2], entry_length);
+			buf[entry_length] = '\0';
+			
+			d = g_ascii_strtod(buf, &ep);
+			if (ep == buf + entry_length) {
+				d *= 0x800000;
+				gd->peak_signal = (guint32) floor(d + 0.5);
+				gd->peak_signal_set = TRUE;
+/*				printf("peak_signal (ape): %f\n", (double) gd->peak_signal / 0x800000);*/
+			}
+
+			continue;
+		}
+	}
+
+	free(dbuf);
+	fclose(file);
+	return TRUE;
+
+rg_fail:
+	if (dbuf)
+		free(dbuf);
+	if (file)
+		fclose(file);
+	return FALSE;
+}
+
+
+/* ----------------------------------------------------------------------
+
+	      mp3gain code
+
+---------------------------------------------------------------------- */
+
+#include <sys/wait.h>
+#include <fcntl.h>
+
+
+
+
+
+
+/** 
+ * mp3_read_soundcheck:
+ *
+ * try to read the ReplayGain values from the LAME or Ape Tags and set
+ * the track's soundcheck field accordingly.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * The function always rereads the gain from the file.
+ *
+ * Returns TRUE if the soundcheck field could be set.
+ */
+gboolean mp3_read_soundcheck (gchar *path, Track *track)
+{
+    GainData gd;
+
+    g_return_val_if_fail (track, FALSE);
+
+    memset (&gd, 0, sizeof (GainData));
+
+    gd.radio_gain_set = FALSE;
+    gd.audiophile_gain_set = FALSE;
+    gd.peak_signal_set = FALSE;
+
+    mp3_get_track_lame_replaygain (path, &gd);
+    if (gd.radio_gain_set)
+    {
+	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
+	return TRUE;
+    }
+
+    mp3_get_track_ape_replaygain (path, &gd);
+    if (gd.radio_gain_set)
+    {
+	track->soundcheck = replaygain_to_soundcheck (gd.radio_gain);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+
+
+
+
+/* mp3 slot size in bytes */
+int slotsize[3] = {4,1,1}; /* layer 1, layer 2, layer 3 */
+
+int samplesperframe[2][3] = {
+  { /* MPEG 2.0 */
+    384,1152,576 /* layer 1, layer 2, layer 3 */
+  },
+
+  { /* MPEG 1.0 */
+    384,1152,1152 /* layer 1, layer 2, layer 3 */
+  }
+};
+
+
+/* 
+ * mp3_get_track_lame_gapless - read the specified file and scan for LAME Tag
+ * gapless information.
+ *
+ * @path: localtion of the file
+ * @track: structure holding track information
+ *
+ * TODO: Split off non-LAME stuff (samplecount, gapless_data) to a separate function since it's generic
+ */
+gboolean mp3_get_track_lame_gapless (gchar *path, GaplessData *gd)
+{
+    FILE *file = NULL;
+    char buf[4], version[5];
+    unsigned char ubuf[4];
+    int sideinfo;
+    int i;
+
+    g_return_val_if_fail (gd, FALSE);
+
+    if (!path)
+	goto gp_fail;
+
+    file = fopen (path, "rb");
+
+    if (!file)
+	goto gp_fail;
+
+    /* use get_first_header() to seek to the first mp3 header */
+    MP3Info *mp3i = NULL;
+    mp3i = g_malloc0 (sizeof (MP3Info));
+    mp3i->filename = path;
+    mp3i->file = file;
+    get_mp3_info (mp3i);
+    get_first_header (mp3i, 0);
+
+    int xing_header_offset = ftell (file);
+
+    MP3Header h;
+    if (!get_header (file, &h))
+	goto gp_fail;
+
+    int mysamplesperframe = samplesperframe[h.version & 1][3 - h.layer];
+
+    /* Determine offset of Xing header based on sideinfo size */
+    if (h.version & 0x1)
+    {
+	sideinfo = (h.mode & 0x2) ?
+	    SIDEINFO_MPEG1_MONO : SIDEINFO_MPEG1_MULTI;
+    }
+    else
+    {
+	sideinfo = (h.mode & 0x2) ?
+	    SIDEINFO_MPEG2_MONO : SIDEINFO_MPEG2_MULTI;
+    }
+
+    if (fseek (file, sideinfo, SEEK_CUR) ||
+	(fread (&buf[0], 1, 4, file) != 4))
+	goto gp_fail;
+
+    /* Is this really a Xing or Info Header? 
+     * FIXME: Apparently (according to madplay sources) there is a different
+     * possible location for the Xing header ("due to an unfortunate
+     * historical event"). I do not thing we need to care though since
+     * ReplayGain information is only contained in recent files.  */
+    if (strncmp (buf, "Xing", 4) && strncmp (buf, "Info", 4))
+	goto gp_fail;
+
+    /* Determine the offset of the LAME tag based on contents of the Xing header */
+    int flags;
+    fread (&flags, 4, 1, file);
+    int toskip = 0;
+    if (flags | 0x1)
+    {				/* frames field is set */
+	toskip += 4;
+    }
+    if (flags | 0x2)
+    {				/* bytes field is set */
+	toskip += 4;
+    }
+    if (flags | 0x4)
+    {				/* TOC field is set */
+	toskip += 100;
+    }
+    if (flags | 0x8)
+    {				/* quality field is set */
+	toskip += 4;
+    }
+
+    /* Check for LAME Tag */
+    if (fseek (file, toskip, SEEK_CUR) || (fread (&buf[0], 1, 4, file) != 4))
+	goto gp_fail;
+    if (strncmp (buf, "LAME", 4))
+	goto gp_fail;
+
+    /* Check LAME Version */
+    if (fread (version, 1, 5, file) != 5)
+	goto gp_fail;
+
+    /* XXX skip old LAME versions, or just assume that pre/postgap
+     * turn out zeros anyway, or check the CRC to vaidate the tag? */
+
+    gboolean cbr = FALSE;
+    if (fread (ubuf, 1, 1, file) != 1)
+	goto gp_fail;
+
+    if ((ubuf[0] & 0xf) == 0x1)
+	cbr = TRUE;
+
+    if (fseek (file, 0xB, SEEK_CUR) || (fread (ubuf, 1, 4, file) != 4))
+	goto gp_fail;
+
+    /* set pregap and postgap directly from LAME header */
+    gd->pregap = (ubuf[0] << 4) + (ubuf[1] >> 4);
+    gd->postgap = ((ubuf[1] & 0xf) << 8) + ubuf[2];
+
+    /* jump the end of the frame with the xing header */
+    if (fseek (file, xing_header_offset + frame_length (&h), SEEK_SET))
+	goto gp_fail;
+
+    /* counts bytes from the start of the 1st sync frame */
+    int totaldatasize = frame_length (&h);
+
+    /* keeps track of the last 8 frame sizes */
+    int lastframes[8];
+
+    /* counts number of music frames */
+    int totalframes = 0;
+
+    /* quickly parse the file, reading only frame headers */
+    int l = 0;
+    while ((l = get_header (file, &h)) != 0)
+    {
+	for (i = 7; i > 0; i--)
+	{
+	    lastframes[i] = lastframes[i - 1];
+	}
+	lastframes[0] = l;
+	totaldatasize += l;
+	totalframes++;
+
+	if (fseek (file, l - FRAME_HEADER_SIZE, SEEK_CUR))
+	    goto gp_fail;
+
+    }
+
+    int finaleight = 0;
+    for (i = 0; i < 8; i++)
+    {
+	finaleight += lastframes[i];
+    }
+
+    if (cbr)
+	totalframes++;
+
+    /* all but last eight frames */
+    gd->gapless_data = totaldatasize - finaleight;
+    /* total samples minus pre/postgap */
+    gd->samplecount = totalframes * mysamplesperframe - gd->pregap - gd->postgap;
+
+    return TRUE;
+
+
+  gp_fail:
+    if (file)
+	fclose (file);
+    return FALSE;
+
+}
+
+
+
+/** 
+ * mp3_read_gapless:
+ *
+ * try to read the gapless values from the LAME Tag and set
+ * the track's pregap, postgap, samplecount, and gapless_data fields
+ * accordingly.
+ *
+ * @path: location of the file
+ * @track: structure holding track information
+ *
+ * The function always rereads the data from the file.
+ *
+ * Returns TRUE if all four gapless fields could be
+ * set. etrack->tchanged is set to TRUE if data has been changed,
+ * FALSE otherwise.
+ */
+gboolean mp3_read_gapless (char *path, Track *track)
+{
+    GaplessData gd;
+    ExtraTrackData *etr;
+
+    g_return_val_if_fail (track, FALSE);
+
+    etr = track->userdata;
+
+    memset (&gd, 0, sizeof (GaplessData));
+
+    gd.pregap = 0;
+    gd.samplecount = 0;
+    gd.postgap = 0;
+    gd.gapless_data = 0;
+
+    mp3_get_track_lame_gapless (path, &gd);
+
+    etr->tchanged = FALSE;
+
+    if ((gd.pregap) && (gd.samplecount) && (gd.postgap) && (gd.gapless_data))
+    {
+	if ((track->pregap != gd.pregap) ||
+	    (track->samplecount != gd.samplecount) ||
+	    (track->postgap != gd.postgap) ||
+	    (track->gapless_data != gd.gapless_data) ||
+	    (track->gapless_track_flag == FALSE))
+	{
+	    etr->tchanged = TRUE;
+	    track->pregap = gd.pregap;
+	    track->samplecount = gd.samplecount;
+	    track->postgap = gd.postgap;
+	    track->gapless_data = gd.gapless_data;
+	    track->gapless_track_flag = TRUE;
+	}
+    }
+    return FALSE;
+}
+
+
+
+/* ----------------------------------------------------------------------
+
+	      From here starts original gtkpod code
+
+---------------------------------------------------------------------- */
+
+/* Return a Track structure with all information read from the mp3
+   file filled in */
+Track *mp3_get_file_info (gchar *name)
+{
+    Track *track = NULL;
+    File_Tag filetag;
+    MP3Info *mp3i=NULL;
+    FILE *file;
+    guchar *image_data = NULL;
+    gsize image_data_len = 0;
+
+    g_return_val_if_fail (name, NULL);
+
+    /* Attempt to open the file */
+    file = fopen (name, "r");
+    if (file)
+    {
+	mp3i = g_malloc0 (sizeof (MP3Info));
+	mp3i->filename = name;
+	mp3i->file = file;
+	get_mp3_info (mp3i);
+	mp3i->file = NULL;
+	fclose (file);
+    }
+    else
+    {
+	gchar *fbuf = charset_to_utf8 (name);
+    	gtkpod_warning(_("ERROR while opening file: '%s' (%s).\n"),
+		       fbuf, g_strerror(errno));
+	g_free (fbuf);
+	return NULL;
+    }
+
+    track = gp_track_new ();
+    track->filetype = g_strdup ("MPEG audio file");
+
+    if (prefs_get_int("readtags") && (id3_tag_read (name, &filetag) == TRUE))
+    {
+
+	if (filetag.album)
+	{
+	    track->album = filetag.album;
+	}
+
+	if (filetag.artist)
+	{
+	    track->artist = filetag.artist;
+	}
+
+	if (filetag.title)
+	{
+	    track->title = filetag.title;
+	}
+
+	if (filetag.genre)
+	{
+	    track->genre = filetag.genre;
+	}
+
+	if (filetag.composer)
+	{
+	    track->composer = filetag.composer;
+	}
+
+	if (filetag.comment)
+	{
+	    track->comment = filetag.comment;
+	}
+
+	if (filetag.podcasturl)
+	{
+	    track->podcasturl = filetag.podcasturl;
+	}
+
+	if (filetag.podcastrss)
+	{
+	    track->podcastrss = filetag.podcastrss;
+	}
+
+	if (filetag.subtitle)
+	{
+	    track->subtitle = filetag.subtitle;
+	}
+
+	if (filetag.description)
+	{
+	    track->description = filetag.description;
+	}
+
+	if (filetag.sort_artist)
+	{
+	    track->sort_artist = filetag.sort_artist;
+	}
+
+	if (filetag.sort_title)
+	{
+	    track->sort_title = filetag.sort_title;
+	}
+
+	if (filetag.sort_album)
+	{
+	    track->sort_album = filetag.sort_album;
+	}
+
+	if (filetag.sort_albumartist)
+	{
+	    track->sort_albumartist = filetag.sort_albumartist;
+	}
+
+	if (filetag.sort_composer)
+	{
+	    track->sort_composer = filetag.sort_composer;
+	}
+
+	if (filetag.year == NULL)
+	{
+	    track->year = 0;
+	}
+	else
+	{
+	    track->year = atoi(filetag.year);
+	    g_free (filetag.year);
+	}
+
+	if (filetag.trackstring == NULL)
+	{
+	    track->track_nr = 0;
+	}
+	else
+	{
+	    track->track_nr = atoi(filetag.trackstring);
+	    g_free (filetag.trackstring);
+	}
+
+	if (filetag.track_total == NULL)
+	{
+	    track->tracks = 0;
+	}
+	else
+	{
+	    track->tracks = atoi(filetag.track_total);
+	    g_free (filetag.track_total);
+	}
+	/* CD/disc number handling */
+	if (filetag.cdnostring == NULL)
+	{
+	    track->cd_nr = 0;
+	}
+	else
+	{
+	    track->cd_nr = atoi(filetag.cdnostring);
+	    g_free (filetag.cdnostring);
+	}
+	
+	if (filetag.cdno_total == NULL)
+	{
+	    track->cds = 0;
+	}
+	else
+	{
+	    track->cds = atoi(filetag.cdno_total);
+	    g_free (filetag.cdno_total);
+	}
+
+	if (filetag.compilation == NULL)
+	{
+	    track->compilation = 0;
+	}
+	else
+	{
+	    track->compilation = atoi(filetag.compilation);
+	    g_free (filetag.compilation);
+	}
+
+	if (filetag.BPM == NULL)
+	{
+	    track->BPM = 0;
+	}
+	else
+	{
+	    track->BPM = atoi(filetag.BPM);
+	    g_free (filetag.BPM);
+	}
+
+	if (filetag.lyrics)
+	{
+	    track->lyrics_flag = 0x01;
+	    g_free (filetag.lyrics);
+	}
+	else
+	{
+	    track->lyrics_flag = 0x00;
+	}
+    }
+
+    if (prefs_get_int("coverart_apic") &&
+	(id3_apic_read (name, &image_data, &image_data_len) == TRUE))
+    {
+	if (image_data)
+	{
+	    gp_track_set_thumbnails_from_data (track,
+					       image_data,
+					       image_data_len);
+	    g_free (image_data);
+	}
+    }
+
+    mp3_read_soundcheck (name, track);
+
+    mp3_read_gapless (name, track);
+
+#if LOCALDEBUG
+	printf("%s\n", name);
+    printf("\tpregap: %i\n", track->pregap);
+    printf("\tpostgap: %i\n", track->postgap);
+    printf("\tsamplecount: %li\n", track->samplecount);
+    printf("\tgaplessdata: %i\n", track->gapless_data);
+#endif
+
+
+    /* Get additional info (play time and bitrate */
+    if (mp3i)
+    {
+	track->tracklen = mp3i->milliseconds;
+	track->bitrate = (gint)(mp3i->vbr_average);
+ 	track->samplerate = mp3file_header_frequency (&mp3i->header);
+	g_free (mp3i);
+    }
+    /* Fall back to xmms code if tracklen is 0 */
+    if (track->tracklen == 0)
+    {
+	track->tracklen = get_track_time (name);
+	if (track->tracklen)
+	    track->bitrate = (float)track->size*8/track->tracklen;
+    }
+
+    if (track->tracklen == 0)
+    {
+	/* Tracks with zero play length are ignored by iPod... */
+	gtkpod_warning (_("File \"%s\" has zero play length. Ignoring.\n"),
+			name);
+	gp_track_free (track);
+	track = NULL;
+    }
+    return track;
+}

Deleted: gtkpod/tags/0.99.10-5/src/prefs.c
===================================================================
--- gtkpod/trunk/src/prefs.c	2007-11-13 14:54:03 UTC (rev 259)
+++ gtkpod/tags/0.99.10-5/src/prefs.c	2007-11-20 13:46:35 UTC (rev 280)
@@ -1,2281 +0,0 @@
-/*
-|  Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
-|  Copyright (C) 2006 James Liggett <jrliggett at cox.net>
-|  Part of the gtkpod project.
-|
-|  URL: http://www.gtkpod.org/
-|  URL: http://gtkpod.sourceforge.net/
-|
-|  This program is free software; you can redistribute it and/or modify
-|  it under the terms of the GNU General Public License as published by
-|  the Free Software Foundation; either version 2 of the License, or
-|  (at your option) any later version.
-|
-|  This program is distributed in the hope that it will be useful,
-|  but WITHOUT ANY WARRANTY; without even the implied warranty of
-|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-|  GNU General Public License for more details.
-|
-|  You should have received a copy of the GNU General Public License
-|  along with this program; if not, write to the Free Software
-|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-|
-|  iTunes and iPod are trademarks of Apple
-|
-|  This product is not supported/written/published by Apple!
-|
-|  $Id: prefs.c 1597 2007-06-26 14:35:18Z dforsi $
-*/
-
-/* -------------------------------------------------------------------
- *
- * HOWTO add a new_option to the prefs dialog
- *
- * - add the desired option to the prefs window using glade-2
- *
- * - set the default value of new_option in set_default_preferences() in prefs.c
- *
- * - add a callback on_new_option_*() to prefs_windows.c to set the
- *   new value.
- *   The value is applied to the actual prefs when pressing the "OK"
- *   or "Apply" button in the prefs window.
- *
- * - add code to prefs_window_create() in prefs_window.c to set the
- *   correct state of the option in the prefs window.
- *
- * - if you want new_option to be a command line option as well, add
- *   code to usage() and read_commandline().
- *
- * - for environment variables, add code to read_environment().
- *
- * ---------------------------------------------------------------- */
-
-/* ----------------------------------------------------------------
- *
- * The prefs module should be thread safe. The hash table is locked
- * before each read or write access.
- *
- * The temp_prefs module is not thread-safe. If necessary a locking
- * mechanism can be implemented.
- *
- * ---------------------------------------------------------------- */
-
-
-
-
-/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
-   Ditto for AIX 3.2 and <stdlib.h>.  */
-#ifndef _NO_PROTO
-# define _NO_PROTO
-#endif
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <glib/gstdio.h>
-#ifdef HAVE_GETOPT_LONG_ONLY
-#  include <getopt.h>
-#else
-#  include "getopt.h"
-#endif
-
-#include "clientserver.h"
-#include "misc.h"
-#include "prefs.h"
-
-/*
- * Data global to this module only
- */
-
-/* End-of-list marker for variable-length lists */
-#define LIST_END_MARKER "----++++----"
-
-struct temp_prefs_save
-{
-    GIOChannel *gio;
-    GError **error;
-    gboolean success;
-};
-
-struct sub_data
-{
-    TempPrefs *temp_prefs;
-    TempPrefs *temp_prefs_orig;
-    const gchar *subkey;
-    const gchar *subkey2;
-    gboolean exists;
-};
-
-/* Pointer to preferences hash table */
-static GHashTable *prefs_table = NULL;
-static GMutex *prefs_table_mutex = NULL;
-
-/*
- * Functions used by this module only
- */
-void discard_prefs (void);
-
-/* Different paths that can be set in the prefs window */
-typedef enum
-{
-    PATH_PLAY_NOW = 0,
-    PATH_PLAY_ENQUEUE,
-    PATH_MP3GAIN,
-    PATH_SYNC_CONTACTS,
-    PATH_SYNC_CALENDAR,
-    PATH_MSERV_MUSIC_ROOT,
-    PATH_MSERV_TRACKINFO_ROOT,
-    PATH_SYNC_NOTES,
-    PATH_AACGAIN,
-    PATH_NUM
-} PathType;
-
-/* enum for reading of options */
-enum {
-  GP_HELP,
-  GP_PLAYCOUNT,
-  GP_MOUNT,
-  GP_PRINT_HASH,
-};
-
-
-/* Lock the prefs table. If the table is already locked the calling
- * thread will remain blocked until the lock is released by the other thread. */
-static void lock_prefs_table ()
-{
-    g_return_if_fail (prefs_table_mutex);
-    g_mutex_lock (prefs_table_mutex);
-}
-
-/* Unlock the prefs table again. */
-static void unlock_prefs_table ()
-{
-    g_return_if_fail (prefs_table_mutex);
-    g_mutex_unlock (prefs_table_mutex);
-}
-
-
-/* Set default preferences */
-static void set_default_preferences()
-{
-    int i;
-    gchar *str;
-
-    prefs_set_int("update_existing", FALSE);
-    prefs_set_int("id3_write", FALSE);
-    prefs_set_int("id3_write_id3v24", FALSE);
-    prefs_set_int(KEY_SYNC_DELETE_TRACKS, TRUE);
-    prefs_set_int(KEY_SYNC_CONFIRM_DELETE, TRUE);
-    prefs_set_int(KEY_SYNC_SHOW_SUMMARY, TRUE);
-    prefs_set_int("show_duplicates", TRUE);
-    prefs_set_int("show_non_updated", TRUE);
-    prefs_set_int("show_updated", TRUE);
-    prefs_set_int("mserv_report_probs", TRUE);
-    prefs_set_int("delete_ipod", TRUE);
-    prefs_set_int("delete_file", TRUE);
-    prefs_set_int("delete_local_file", TRUE);
-    prefs_set_int("delete_database", TRUE);
-    prefs_set_string("initial_mountpoint", "/media/ipod");
-    prefs_set_string ("path_play_now", "xmms %s");
-    prefs_set_string ("path_play_enqueue", "xmms -e %s");
-    prefs_set_string ("path_mserv_trackinfo_root", "/var/lib/mserv/trackinfo/");
-
-    str = g_build_filename (SCRIPTDIR, "convert-ogg2mp3.sh", NULL);
-    prefs_set_string ("path_conv_ogg", str);
-    g_free (str);
-    prefs_set_int ("convert_ogg", TRUE);
-
-    str = g_build_filename (SCRIPTDIR, "convert-flac2mp3.sh", NULL);
-    prefs_set_string ("path_conv_flac", str);
-    g_free (str);
-    prefs_set_int ("convert_flac", TRUE);
-
-    str = g_build_filename (SCRIPTDIR, "convert-wav2mp3.sh", NULL);
-    prefs_set_string ("path_conv_wav", str);
-    g_free (str);
-    prefs_set_int ("convert_wav", FALSE);
-
-
-    /* Set sorting tab defaults */
-    for (i = 0; i < SORT_TAB_MAX; i++)
-    {
-	prefs_set_int_index("st_autoselect", i, TRUE);
-	prefs_set_int_index("st_category", i, (i < ST_CAT_NUM ? i : 0));
-	prefs_set_int_index("sp_or", i, FALSE);
-	prefs_set_int_index("sp_rating_cond", i, FALSE);
-	prefs_set_int_index("sp_playcount_cond", i, FALSE);
-	prefs_set_int_index("sp_played_cond", i, FALSE);
-	prefs_set_int_index("sp_modified_cond", i, FALSE);
-	prefs_set_int_index("sp_added_cond", i, FALSE);
-	prefs_set_int_index("sp_rating_state", i, 0);
-	prefs_set_string_index("sp_played_state", i, ">4w");
-	prefs_set_string_index("sp_modified_state", i, "<1d");
-	prefs_set_string_index("sp_added_state", i, "<1d");
-	prefs_set_int_index("sp_playcount_low", i, 0);
-	prefs_set_int_index("sp_playcount_high", i, -1);
-	prefs_set_int_index("sp_autodisplay", i, FALSE);
-    }
-    
-    prefs_set_int("sort_tab_num", 2);
-    
-    /* Set colum preferences */
-    for (i = 0; i < TM_NUM_COLUMNS; i++)
-    {
-	prefs_set_int_index("tm_col_width", i, 80);
-	prefs_set_int_index("col_visible", i, FALSE);
-	prefs_set_int_index("col_order", i, i);
-    }
-		
-    for (i = 0; i < TM_NUM_TAGS_PREFS; i++)
-	prefs_set_int_index("tag_autoset", i, FALSE);
-		
-    prefs_set_int_index("tag_autoset", TM_COLUMN_TITLE, TRUE);
-    
-    prefs_set_int_index("col_visible", TM_COLUMN_ARTIST, TRUE);
-    prefs_set_int_index("col_visible", TM_COLUMN_ALBUM, TRUE);
-    prefs_set_int_index("col_visible", TM_COLUMN_TITLE, TRUE);
-    prefs_set_int_index("col_visible", TM_COLUMN_GENRE, TRUE);
-    prefs_set_int_index("col_visible", TM_COLUMN_PLAYCOUNT, TRUE);
-    prefs_set_int_index("col_visible", TM_COLUMN_RATING, TRUE);
-
-    /* Set pane positions--Let gtk worry about position */
-    for (i = 0; i < PANED_NUM; i++)
-	prefs_set_int_index("paned_pos_", i, -1);
-	
-    prefs_set_int("mpl_autoselect", TRUE);
-	
-    /* Set window sizes */
-    prefs_set_int("size_gtkpod.x", 600);
-    prefs_set_int("size_gtkpod.y", 500);
-    prefs_set_int("size_cal.x", 500);
-    prefs_set_int("size_cal.y", 300);
-    prefs_set_int("size_conf_sw.x", 300);
-    prefs_set_int("size_conf_sw.y", 300);
-    prefs_set_int("size_conf.x", 300);
-    prefs_set_int("size_conf.y", -1);
-    prefs_set_int("size_dirbr.x", 300);
-    prefs_set_int("size_dirbr.y", 400);
-    prefs_set_int("size_prefs.x", -1);
-    prefs_set_int("size_prefs.y", 480);
-    prefs_set_int("size_info.x", 510);
-    prefs_set_int("size_info.y", 300);
-
-    /* size of file dialog if there is not a details textview */
-    prefs_set_int("size_file_dialog.x", 320);
-    prefs_set_int("size_file_dialog.y", 140);
-
-    /* size of file dialog if there is a details textview */
-    prefs_set_int("size_file_dialog_details.x", 320);
-    prefs_set_int("size_file_dialog_details.y", 140);
-
-    prefs_set_int("readtags", TRUE);
-    prefs_set_int("write_extended_info", TRUE);
-    prefs_set_int("parsetags", FALSE);
-    prefs_set_int("parsetags_overwrite", FALSE);
-    prefs_set_string("parsetags_template", "%a - %A/%T %t.mp3;%t.wav");
-    prefs_set_int("coverart_apic", TRUE);
-    prefs_set_int("coverart_file", TRUE);
-    prefs_set_string("coverart_template", "%A;folder.jpg");
-    prefs_set_int("mserv_use", FALSE);
-    prefs_set_string("mserv_username", "");
-    prefs_set_int("startup_messages", TRUE);
-    prefs_set_int("add_recursively", TRUE);
-    prefs_set_int("info_window", FALSE);
-    prefs_set_int("last_prefs_page", 0);
-    prefs_set_int("multi_edit_title", TRUE);
-    prefs_set_int("multi_edit", FALSE);
-    prefs_set_int("not_played_track", TRUE);
-    prefs_set_int("misc_track_nr", 25);
-    prefs_set_int("update_charset", FALSE);
-    prefs_set_int("display_tooltips_main", TRUE);
-    prefs_set_int("display_tooltips_prefs", TRUE);
-    prefs_set_int("display_toolbar", TRUE);
-    prefs_set_int("toolbar_style", GTK_TOOLBAR_BOTH);
-    prefs_set_int("sha1", TRUE);
-    prefs_set_string("export_template", "%o;%a - %t.mp3;%t.wav");
-    prefs_set_int("file_dialog_details_expanded", FALSE);
-
-    /* Set last browsed directory */
-    str = g_get_current_dir();
-
-    if (str)
-    {
-	prefs_set_string("last_dir_browsed", str);
-	g_free(str);
-    }
-    else
-	prefs_set_string("last_dir_browsed", g_get_home_dir());
-    
-    /* Set sorting prefs */
-    prefs_set_int("case_sensitive", FALSE);
-    prefs_set_int("tm_autostore", FALSE);
-    prefs_set_int("st_sort", SORT_NONE);
-    prefs_set_int("pm_sort", SORT_NONE);
-    prefs_set_int("tm_sortcol", TM_COLUMN_TITLE);
-    prefs_set_int("tm_sort", SORT_NONE);
-}
-
-/* Initialize default variable-length list entries */
-static void set_default_list_entries()
-{
-    if (!prefs_get_string_value_index("sort_ign_string_", 0, NULL))
-    {
-	prefs_set_string_index("sort_ign_string_", 0, "a ");
-	prefs_set_string_index("sort_ign_string_", 1, "an ");
-	prefs_set_string_index("sort_ign_string_", 2, LIST_END_MARKER);
-    }
-}
-
-/* A printf-like function that outputs in the system locale */
-static void locale_fprintf(FILE *fp, const gchar *format, ...)
-{
-    gchar *utf8_string; /* Raw UTF-8 string */
-    gchar *locale_string;  /* String in system locale format */
-    va_list format_list;  /* Printf-like formatting arguments */
-	
-    /* Create the locale format string based on the given format */
-    va_start(format_list, format);
-    utf8_string = g_strdup_vprintf(format, format_list);
-    va_end(format_list);
-	
-    locale_string = g_locale_from_utf8 (utf8_string, -1, NULL, NULL, NULL);
-	
-    if (fp)
-	fprintf(fp, "%s", locale_string);
-	
-    g_free(utf8_string);
-    g_free(locale_string);
-}
-
-/* Print commandline usage information */
-static void usage(FILE *fp)
-{
-  locale_fprintf(fp, _("gtkpod version %s usage:\n"), VERSION);
-  locale_fprintf(fp, _("  -h, --help:   display this message\n"));
-  locale_fprintf(fp, _("  -p <file>:    increment playcount for file by one\n"));
-  locale_fprintf(fp, _("  --hash <file>:print gtkpod hash for file\n"));
-  locale_fprintf(fp, _("  -m path:      define the mountpoint of your iPod\n"));
-  locale_fprintf(fp, _("  --mountpoint: same as '-m'.\n"));
-  locale_fprintf(fp, _("  -a:           import database automatically after start.\n"));
-  locale_fprintf(fp, _("  --auto:       same as '-a'.\n"));
-}
-
-/* Parse commandline based options */
-static void read_commandline(int argc, char *argv[])
-{
-    int option; /* Code returned by getopt */
-	
-    /* The options data structure. The format is standard getopt. */
-    struct option const options[] =
-	{
-	    { "h",           no_argument,	NULL, GP_HELP },
-	    { "help",        no_argument,	NULL, GP_HELP },
-	    { "p",           required_argument, NULL, GP_PLAYCOUNT },
-	    { "hash",        required_argument, NULL, GP_PRINT_HASH },
-	    { "m",           required_argument,	NULL, GP_MOUNT },
-	    { "mountpoint",  required_argument,	NULL, GP_MOUNT },
-	    { 0, 0, 0, 0 }
-	};
-	
-    /* Handle commandline options */
-    while ((option = getopt_long_only(argc, argv, "", options, NULL)) != -1)
-    {
-	switch (option)
-	{
-	case GP_HELP:
-	    usage(stdout);
-	    exit(0);
-	    break;
-	case GP_PLAYCOUNT:
-	    client_playcount(optarg);
-	    exit(0);
-	    break;
-	case GP_PRINT_HASH:
-	    print_sha1_hash (optarg);
-	    exit(0);
-	    break;
-	case GP_MOUNT:
-	    prefs_set_string("initial_mountpoint", optarg);
-	    break;
-	default:
-	    locale_fprintf(stderr, "Unknown option: %s\n", argv[optind]);
-	    usage(stderr);
-	    exit(1);
-	    break;
-	};
-    }
-}
-
-/* Read options from environment variables */
-static void read_environment()
-{
-    gchar *buf; 
-  
-    buf = convert_filename(getenv("IPOD_MOUNTPOINT"));
-    if (buf)
-	prefs_set_string("initial_mountpoint", buf);
-    g_free(buf);
-}
- 
-/* Create a full numbered key from a base key string and a number.
- * Free returned string. */
-static gchar *create_full_key(const gchar *base_key, gint index)
-{
-    if (base_key)
-	return g_strdup_printf("%s%i", base_key, index);
-    else 
-	return NULL;
-}
-
-/* Remove key present in the temp prefs tree from the hash table */
-static gboolean flush_key (gpointer key, gpointer value, gpointer user_data)
-{
-    g_return_val_if_fail (prefs_table, FALSE);
-
-    g_hash_table_remove (prefs_table, key);
-
-    return FALSE;
-}
-
-
-/* Copy key data from the temp prefs tree to the hash table (or to
- * sub_data->temp_prefs_orig if non-NULL). The old key is removed. */
-static gboolean subst_key (gpointer key, gpointer value, gpointer user_data)
-{
-    struct sub_data *sub_data = user_data;
-    gint len;
-
-    g_return_val_if_fail (key && value && user_data, FALSE);
-    g_return_val_if_fail (sub_data->subkey && sub_data->subkey2, FALSE);
-    if (!sub_data->temp_prefs_orig)
-	g_return_val_if_fail (prefs_table, FALSE);
-    if (sub_data->temp_prefs_orig)
-	g_return_val_if_fail (sub_data->temp_prefs_orig->tree, FALSE);
-
-    len = strlen (sub_data->subkey);
-
-    if (strncmp (key, sub_data->subkey, len) == 0)
-    {
-	gchar *new_key = g_strdup_printf ("%s%s",
-					  sub_data->subkey2,
-					  ((gchar *)key)+len);
-	if (sub_data->temp_prefs_orig)
-	{
-	    g_tree_remove (sub_data->temp_prefs_orig->tree, key);
-	    g_tree_insert (sub_data->temp_prefs_orig->tree,
-			   new_key, g_strdup(value));
-	}
-	else
-	{
-	    g_hash_table_remove (prefs_table, key);
-	    g_hash_table_insert (prefs_table, new_key, g_strdup(value));
-	}
-    }
-    return FALSE;
-}
-
-/* return TRUE if @key starts with @subkey */
-static gboolean match_subkey (gpointer key, gpointer value, gpointer subkey)
-{
-    g_return_val_if_fail (key && subkey, FALSE);
-
-    if (strncmp (key, subkey, strlen (subkey)) == 0)  return TRUE;
-    return FALSE;
-}
-
-
-/* return TRUE and set sub_data->exists to TRUE if @key starts with
- * @subkey */
-static gboolean check_subkey (gpointer key, gpointer value, gpointer user_data)
-{
-    struct sub_data *sub_data = user_data;
-
-    g_return_val_if_fail (key && user_data, TRUE);
-    g_return_val_if_fail (sub_data->subkey, TRUE);
-
-    if (strncmp (key, sub_data->subkey, strlen (sub_data->subkey)) == 0)
-    {
-	sub_data->exists = TRUE;
-	return TRUE;
-    }
-    return FALSE;
-}
-
-
-
-/* Add key/value to temp_prefs if it matches subkey -- called by
- * prefs_create_subset() and temp_prefs_create_subset() */
-static gboolean get_subset (gpointer key, gpointer value, gpointer user_data)
-{
-    struct sub_data *sub_data = user_data;
-
-    g_return_val_if_fail (key && value && user_data, TRUE);
-    g_return_val_if_fail (sub_data->subkey && sub_data->temp_prefs, TRUE);
-
-    if (strncmp (key, sub_data->subkey,
-		 strlen (sub_data->subkey)) == 0)
-    {  /* match */
-	temp_prefs_set_string (sub_data->temp_prefs, key, value);
-    }
-    return FALSE; /* continue traversal (g_tree), ignored for g_hash */
-}
-
-
-/* Copy a variable-length list to the prefs table */
-static gboolean copy_list(gpointer key, gpointer value, gpointer user_data)
-{
-	prefs_apply_list((gchar*)key, (GList*)value);
-	return FALSE;
-}
- 
-/* Callback that writes pref table data to a file */
-static void write_key(gpointer key, gpointer value, gpointer user_data)
-{
-    FILE *fp;  /* file pointer passed in through user_data */
-	
-    /* Write out each key and value to the given file */
-    fp = (FILE*)user_data;
-	
-    if (fp)
-	fprintf(fp, "%s=%s\n", (gchar*)key, (gchar*)value);
-}
-
-/* Gets a string that contains ~/.gtkpod/ If the folder doesn't exist,
- * create it. Free the string when you are done with it.
- * If the folder wasn't found, and couldn't be created, return NULL */
-gchar *prefs_get_cfgdir()
-{
-    gchar *folder;  /* Folder path */
-	
-    /* Create the folder path. If the folder doesn't exist, create it. */
-    folder = g_build_filename(g_get_home_dir(), ".gtkpod", NULL);
-	
-    if (!g_file_test(folder, G_FILE_TEST_IS_DIR))
-    {
-	if ((g_mkdir(folder, 0777)) == -1)
-	{
-	    printf(_("Couldn't create ~/.gtkpod\n"));
-	    return NULL;
-	}
-    }
-	
-    return folder;
-}
-
-
-/* get @key and @value from a string like "key=value" */
-static gboolean read_prefs_get_key_value (const gchar *buf,
-					  gchar **key, gchar **value)
-{
-    size_t len;  /* string length */
-    const gchar *buf_start; /* Pointer to where actual useful data starts in line */
-
-    g_return_val_if_fail (buf && key && value, FALSE);
-
-    /* Strip out any comments (lines that begin with ; or #) */
-    if ((buf[0] == ';') || (buf[0] == '#')) 
-	return FALSE;
-
-    /* Find the key and value, and look for malformed lines */
-    buf_start = strchr (buf, '=');
-
-    if ((!buf_start) || (buf_start == buf))
-    {
-	printf("Parse error reading prefs: %s", buf);
-	return FALSE;
-    }
-
-    /* Find the key name */
-    *key = g_strndup (buf, (buf_start - buf));
-
-    /* Strip whitespace */
-    g_strstrip (*key);
-
-    /* Find the value string */
-    *value = strdup (buf_start+1);
-
-    /* remove newline */
-    len = strlen (*value);
-    if ((len > 0) && ((*value)[len - 1] == 0x0a))
-	(*value)[len - 1] = 0;
-
-    /* Don't strip whitespace! If there is any, there's a reason for it. */
-    /* g_strstrip (*value); */
-
-    return TRUE;
-}
-
-
-/* Read preferences from a file */
-static void read_prefs_from_file(FILE *fp)
-{
-    gchar buf[PATH_MAX];  /* Buffer that contains one line */
-    gchar *key;  /* Pref value key */
-    gchar *value; /* Pref value */
-
-
-    g_return_if_fail (prefs_table && fp);
-
-    while (fgets(buf, PATH_MAX, fp))
-    {
-	if (read_prefs_get_key_value (buf, &key, &value))
-	{
-	    g_hash_table_insert (prefs_table, key, value);
-	}
-    }
-}
-
-/* Write prefs to file */
-static void write_prefs_to_file(FILE *fp)
-{
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    g_hash_table_foreach(prefs_table, write_key, (gpointer)fp);
-
-    unlock_prefs_table ();
-}
-
-/* Load preferences, first loading the defaults, and then overwrite that with
- * preferences in the user home folder. */
-static void load_prefs()
-{
-    gchar *filename; /* Config path to open */
-    gchar *config_dir;  /* Directory where config is (usually ~/.gtkpod) */
-    FILE *fp;
-	
-    /* Start by initializing the prefs to their default values */
-    set_default_preferences();
-	
-    /* and then override those values with those found in the home folder. */
-    config_dir = prefs_get_cfgdir();
-	
-    if (config_dir)
-    {
-	filename = g_build_filename(config_dir, "prefs", NULL);
-		
-	if (filename)
-	{
-	    fp = fopen(filename, "r");
-			
-	    if (fp)
-	    {
-		read_prefs_from_file(fp);
-		fclose(fp);
-	    }
-			
-	    g_free(filename);
-	}
-		
-	g_free(config_dir);
-    }
-	
-    /* Finally, initialize variable-length lists. Do this after everything else
-     * so that list defaults don't hang out in the table after prefs have been
-     * read from the file. */
-    set_default_list_entries();
-}
-
-/* Save preferences to user home folder (~/.gtkpod/prefs) */
-void prefs_save ()
-{
-    gchar *filename;  /* Path of file to write to */
-    gchar *config_dir;   /* Folder where prefs file is */
-    FILE *fp;  /* File pointer */
-	
-    /* Open $HOME/.gtkpod/prefs, and write prefs */
-    config_dir = prefs_get_cfgdir();
-	
-    if (config_dir)
-    {
-	filename = g_build_filename(config_dir, "prefs", NULL);
-		
-	if (filename)
-	{
-	    fp = fopen(filename, "w");
-
-	    if (fp)
-	    {
-		write_prefs_to_file(fp);
-		fclose(fp);
-	    }
-		
-	    g_free(filename);
-	}
-		
-	g_free(config_dir);
-    }
-}
-
-
-static gboolean temp_prefs_save_fe (gchar *key, gchar *value,
-				    struct temp_prefs_save *tps)
-{
-    gchar *buf;
-    GIOStatus status;
-
-    buf=g_strdup_printf ("%s=%s\n", key, value);
-    status = g_io_channel_write_chars (tps->gio, buf, -1, NULL, tps->error);
-    g_free (buf);
-    if (status != G_IO_STATUS_NORMAL)
-    {
-	tps->success = FALSE;
-	return TRUE;  /* stop traversal */
-    }
-    return FALSE;
-}
-
-
-/* Save @temp_prefs to @filename in the same manner as prefs_save is
- * saving to ~/.gtkpod/prefs. @error: location where to store
- * information about errors or NULL.
- * 
- * Return value: TRUE on success, FALSE if an error occured, in which
- * case @error will be set accordingly.
- */
-gboolean temp_prefs_save (TempPrefs *temp_prefs,
-			  const gchar *filename,
-			  GError **error)
-{
-    GIOChannel *gio;
-    struct temp_prefs_save tps;
-
-    g_return_val_if_fail (temp_prefs && filename, FALSE);
-
-    gio = g_io_channel_new_file (filename, "w", error);
-    tps.gio = gio;
-    tps.error = error;
-    tps.success = TRUE;
-    if (gio)
-    {
-	g_tree_foreach (temp_prefs->tree, (GTraverseFunc)temp_prefs_save_fe, &tps);
-	g_io_channel_unref (gio);
-    }
-
-    return tps.success;
-}
-
-
-TempPrefs *temp_prefs_load (const gchar *filename, GError **error)
-{
-    GIOChannel *gio;
-    TempPrefs *temp_prefs = NULL;
-
-    g_return_val_if_fail (filename, NULL);
-
-    gio = g_io_channel_new_file (filename, "r", error);
-    if (gio)
-    {
-	GIOStatus status;
-
-	temp_prefs = temp_prefs_create ();
-
-	do
-	{
-	    gchar *line;
-
-	    status = g_io_channel_read_line (gio, &line, NULL, NULL, error);
-	    if (status == G_IO_STATUS_NORMAL)
-	    {
-		gchar *key, *value;
-		if (read_prefs_get_key_value (line, &key, &value))
-		{
-		    temp_prefs_set_string (temp_prefs, key, value);
-		}
-		g_free (line);
-	    }
-	} while (status == G_IO_STATUS_NORMAL);
-
-	g_io_channel_unref (gio);
-
-	if (status != G_IO_STATUS_EOF)
-	{
-	    temp_prefs_destroy (temp_prefs);
-	    temp_prefs = NULL;
-	}
-    }
-
-    return temp_prefs;
-}
-
-
-/* Removes already existing list keys from the prefs table */
-static void wipe_list(const gchar *key)
-{
-    gchar *full_key; /* Complete key, with its number suffix */
-    guint i;  /* Loop counter */
-	
-    /* Go through the prefs table, starting at key<number>, delete it and go 
-     * through key<number+1>... until there are no keys left */
-	
-    for (i = 0;;i++)
-    {
-	full_key = create_full_key(key, i);
-		
-	if (g_hash_table_remove(prefs_table, full_key))
-	{
-	    g_free(full_key);
-	    continue;
-	}
-	else /* We got all the unneeded keys, leave the loop... */
-	{
-	    g_free(full_key);
-	    break;
-	}
-    }		
-}
-
-/* Delete and rename keys */
-static void cleanup_keys()
-{
-    gchar *buf;
-    gchar *sp = NULL;
-    gint int_buf;
-    gint i;
-    gint x, y, p;  /* Window position */
-    float version=0;
-
-    /* Get version */
-    version = prefs_get_double("version");
-
-    /* rename mountpoint to initial_mountpoint */
-    if (prefs_get_string_value(KEY_MOUNTPOINT, &buf))
-    {
-	prefs_set_string("initial_mountpoint", buf);
-	g_free(buf);
-	prefs_set_string(KEY_MOUNTPOINT, NULL);
-    }
-  
-    /* rename coverart to coverart_file */
-    if (prefs_get_string_value("coverart", &buf))
-    {
-	prefs_set_string("coverart_file", buf);
-	g_free(buf);
-	prefs_set_string("coverart", NULL);
-    }
-  
-    /* rename tm_sort_ to tm_sort */
-    if (prefs_get_string_value("tm_sort_", &buf))
-    {
-	prefs_set_string("tm_sort", buf);
-	g_free(buf);
-	prefs_set_string("tm_sort_", NULL);
-    }
-
-    /* rename md5 to sha1 */
-    if (prefs_get_string_value("md5", &buf))
-    {
-	prefs_set_string("sha1", buf);
-	g_free(buf);
-	prefs_set_string("md5", NULL);
-    }
-
-    /* Convert old path numbered keys to named ones */
-  
-    /* Play Now */
-    if (prefs_get_string_value_index("path", PATH_PLAY_NOW, &buf))
-    {
-	prefs_set_string("path_play_now", buf);
-	prefs_set_string_index("path", PATH_PLAY_NOW, NULL);
-	if (version < 0.87)
-	{  /* default changed from "xmms -p %s" to "xmms
-	      %s" which avoids xmms from hanging --
-	      thanks to Chris Vine */
-	    if (strcmp (buf, "xmms -p %s") == 0)
-	    {
-		prefs_set_string ("path_play_now", "xmms %s");
-	    }
-	}
-	g_free(buf);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_PLAY_NOW, &buf))
-    {
-	prefs_set_string("path_play_now", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_PLAY_NOW, NULL);
-    }
-  
-    /* Enqueue */
-    if (prefs_get_string_value_index("path", PATH_PLAY_ENQUEUE, &buf))
-    {
-	prefs_set_string("path_play_enqueue", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_PLAY_ENQUEUE, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_PLAY_ENQUEUE, &buf))
-    {
-	prefs_set_string("path_play_enqueue", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_PLAY_ENQUEUE, NULL);
-    }
-  
-    /* MP3 Gain */
-    if (prefs_get_string_value_index("path", PATH_MP3GAIN, &buf))
-    {
-	prefs_set_string("path_mp3gain", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_MP3GAIN, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_MP3GAIN, &buf))
-    {
-	prefs_set_string("path_mp3gain", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_MP3GAIN, NULL);
-    }
-  
-    /* Sync contacts */
-    if (prefs_get_string_value_index("path", PATH_SYNC_CONTACTS, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_contacts", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_SYNC_CONTACTS, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_SYNC_CONTACTS, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_contacts", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_SYNC_CONTACTS, NULL);
-    }
-  
-    /* Sync calendar */
-    if (prefs_get_string_value_index("path", PATH_SYNC_CALENDAR, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_calendar", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_SYNC_CALENDAR, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_SYNC_CALENDAR, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_calendar", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_SYNC_CALENDAR, NULL);
-    }
-  
-    /* Sync notes */
-    if (prefs_get_string_value_index("path", PATH_SYNC_NOTES, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_notes", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_SYNC_NOTES, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_SYNC_NOTES, &buf))
-    {
-	prefs_set_string("itdb_0_path_sync_notes", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_SYNC_NOTES, NULL);
-    }
-  
-    /* MSERV music root */
-    if (prefs_get_string_value_index("path", PATH_MSERV_MUSIC_ROOT, &buf))
-    {
-	prefs_set_string("path_mserv_music_root", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_MSERV_MUSIC_ROOT, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_MSERV_MUSIC_ROOT, &buf))
-    {
-	prefs_set_string("path_mserv_music_root", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_MSERV_MUSIC_ROOT, NULL);
-    }
-  
-    /* MSERV track info root */
-    if (prefs_get_string_value_index("path", PATH_MSERV_TRACKINFO_ROOT, &buf))
-    {
-	prefs_set_string("path_mserv_trackinfo_root", buf);
-	g_free(buf);
-	prefs_set_string_index("path", PATH_MSERV_TRACKINFO_ROOT, NULL);
-    }
-  
-    if (prefs_get_string_value_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, &buf))
-    {
-	prefs_set_string("path_mserv_trackinfo_root", buf);
-	g_free(buf);
-	prefs_set_string_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, NULL);
-    }
-
-    /* If there's an extra (PATH_NUM) key, delete it */
-    prefs_set_string_index("path", PATH_NUM, NULL);
-    prefs_set_string_index("toolpath", PATH_NUM, NULL);
-
-    /* Ignore/remove some keys */
-    prefs_set_string("play_now_path", NULL);
-    prefs_set_string("sync_remove", NULL);
-    prefs_set_string("sync_remove_confirm", NULL);
-    prefs_set_string("show_sync_dirs", NULL);
-    prefs_set_string("play_enqueue_path", NULL);
-    prefs_set_string("mp3gain_path", NULL);
-    prefs_set_string("statusbar_timeout", NULL);
-    prefs_set_string("offline", NULL);
-    prefs_set_string("time_format", NULL);
-    prefs_set_string("id3_all", NULL);
-    prefs_set_string("pm_autostore", NULL);
-    prefs_set_string("backups", NULL);
-    prefs_set_string("save_sorted_order", NULL);
-    prefs_set_string("fix_path", NULL);
-    prefs_set_string("write_gaintag", NULL);
-    prefs_set_string("automount", NULL);
-    prefs_set_string("display_artcovers", NULL);
-    prefs_set_string("block_display", NULL);
-    prefs_set_string("tmp_disable_sort", NULL);
-    prefs_set_string("size_file_dialog.x", NULL);
-    prefs_set_string("size_file_dialog.y", NULL);
-    prefs_set_string("size_file_dialog_details.x", NULL);
-    prefs_set_string("size_file_dialog_details.y", NULL);
-    prefs_set_string("autoimport", NULL);
-    prefs_set_string("auto_import", NULL);
-
-    /* sp_created_cond renamed to sp_added_cond */
-    for (i = 0; i < SORT_TAB_MAX; i++)
-    {
-	if (prefs_get_int_value_index("sp_created_cond", i, &int_buf))
-	{
-	    prefs_set_int_index("sp_added_cond", i, int_buf);
-	    prefs_set_string("sp_created_cond", NULL);
-	}
-    }
-  
-    /* sp_created_state renamed to sp_added_state */
-    for (i = 0; i < SORT_TAB_MAX; i++)
-    {
-	if (prefs_get_int_value_index("sp_created_state", i, &int_buf))
-	{
-	    prefs_set_int_index("sp_added_state", i, int_buf);
-	    prefs_set_string("sp_created_state", NULL);
-	}
-    }
-  
-    /* sm_col_width renamed to tm_col_width */
-    for (i = 0; i < TM_NUM_COLUMNS; i++)
-    {
-	if (prefs_get_int_value_index("sm_col_width", i, &int_buf))
-	{
-	    prefs_set_int_index("tm_col_width", i, int_buf);
-	    prefs_set_string_index("sm_col_width", i, NULL);
-	}
-    }
-  
-    /* handle version changes in prefs */
-    if (version == 0.0)
-    {
-	/* most likely prefs file written by V0.50 */
-	/* I added two new PANED elements since V0.50 --> shift */
-	for (i=PANED_NUM_ST-1; i>=0; --i)
-	{
-	    prefs_set_int_index("paned_pos_", PANED_NUM_GLADE + i,
-				prefs_get_int_index("paned_pos_", PANED_NUM_GLADE + i - 2));
-	}
-	prefs_set_int_index("paned_pos_", PANED_STATUS1, -1);
-	prefs_set_int_index("paned_pos_", PANED_STATUS2, -1);
-    }
-
-    /* set statusbar paned to a decent value if unset */
-    if (prefs_get_int_index("paned_pos_", PANED_STATUS1) == -1)
-    {
-	x = prefs_get_int("size_gtkpod.x");
-	/* set to about 2/3 of the window width */
-	if (x>0)   
-	    prefs_set_int_index("paned_pos_", PANED_STATUS1, 20*x/30);
-    }
-  
-    if (prefs_get_int_index("paned_pos_", PANED_STATUS2) == -1)
-    {
-	x = prefs_get_int("size_gtkpod.x");
-	y = prefs_get_int("size_gtkpod.y");
-	p = prefs_get_int_index("paned_pos_", PANED_STATUS1);
-	/* set to about half of the remaining window */
-	if (x>0)   
-	    prefs_set_int_index("paned_pos_", PANED_STATUS2, (x-p)/2 );
-    }
-
-    /* Changed layout of info window between 0.72 and 0.73 */
-    if (version < 0.73)
-    {
-	prefs_set_string("size_info.x", NULL);
-	prefs_set_string("size_info.y", NULL);
-    }
-    
-    /* not_played_song renamed to not_played_track */
-    if (prefs_get_int_value("not_played_song", &int_buf))
-    {
-	prefs_set_int("not_played_track", int_buf);
-	prefs_set_string("not_played_song", NULL);
-    }
-
-    /* misc_song_nr renamed to misc_track_nr */
-    if (prefs_get_int_value("misc_song_nr", &int_buf))
-    {
-	prefs_set_int("misc_track_nr", int_buf);
-	prefs_set_string("misc_song_nr", NULL);
-    }
-
-    /* sm_autostore renamed to tm_autostore */
-    if (prefs_get_int_value("sm_autostore", &int_buf))
-    {
-	prefs_set_int("tm_autostore", int_buf);
-	prefs_set_string("sm_autostore", NULL);
-    }
-
-    /* sm_sortcol renamed to tm_sortcol */
-    if (prefs_get_int_value("sm_sortcol", &int_buf))
-    {
-	prefs_set_int("tm_sortcol", int_buf);
-	prefs_set_string("sm_sortcol", NULL);
-    }
-
-    /* sm_sort_ renamed to tm_sort */
-    if (prefs_get_int_value("sm_sort_", &int_buf))
-    {
-	prefs_set_int("tm_sort", int_buf);
-	prefs_set_string("sm_sort_", NULL);
-    }
-
-    /* filename_format renamed to export_template */
-    if (prefs_get_string_value("filename_format", &buf))
-    {
-	prefs_set_string("export_template", buf);
-	g_free(buf);
-	prefs_set_string("filename_format", NULL);
-    }
-
-    /* This string was a wrong autoconvert--just ignore it */
-    buf = prefs_get_string("export_template");
-    
-    if (buf && strcmp(buf, "%a - %a/%T - %T.mp3") == 0)
-	prefs_set_string("export_template", NULL);
-
-    g_free (buf);
-
-    /* We changed the meaning of the %x in export_template */
-    if (version < 0.72)
-    {
-	/* changed the meaning of the %x in export_template */
-	if (sp) while (*sp)
-	{
-	    if (sp[0] == '%')
-	    {
-		switch (sp[1]) {
-		case 'A':
-		    sp[1] = 'a';
-		    break;
-		case 'd':
-		    sp[1] = 'A';
-		    break;
-		case 'n':
-		    sp[1] = 't';
-		    break;
-		case 't':
-		    sp[1] = 'T';
-		    break;
-		default:
-		    break;
-		}
-	    }
-	}
-    }
-
-    /* For versions < 0.91, remove all itdb keys */
-    if (version < 0.91)
-	prefs_flush_subkey("itdb_");
-   
-    prefs_set_string ("version", VERSION);
-}
-
-/* Initialize the prefs table and read configuration */
-void prefs_init (int argc, char *argv[])
-{
-    if (!prefs_table_mutex)
-	prefs_table_mutex = g_mutex_new ();
-
-    lock_prefs_table ();
-
-    /* Create the prefs hash table */
-    prefs_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-					g_free);
-
-    unlock_prefs_table ();
-
-    /* Load preferences */
-    load_prefs();
-
-    /* Clean up old prefs keys */
-    cleanup_keys();
-	
-    /* Read environment variables */
-    read_environment(); 
-	
-    /* Read commandline arguments */
-    read_commandline(argc, argv);  
-}
-
-/* Delete the hash table */
-void prefs_shutdown ()
-{
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    /* Delete the prefs hash table */
-    g_hash_table_destroy(prefs_table);
-    prefs_table = NULL;
-
-    unlock_prefs_table ();
-
-    /* We can't free the prefs_table_mutex in a thread-safe way */
-}
-
-/* Create the temp prefs tree */
-/* Free the returned structure with delete_temp_prefs() */
-TempPrefs *temp_prefs_create ()
-{
-    TempPrefs *temp_prefs;  /* Returned temp prefs structure */
-
-    temp_prefs = (TempPrefs*)g_malloc(sizeof(TempPrefs));
-
-    temp_prefs->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
-				       g_free, g_free);
-
-    return temp_prefs;	
-}
-
-/* Delete temp prefs */
-void temp_prefs_destroy (TempPrefs *temp_prefs)
-{
-    g_return_if_fail (temp_prefs);
-    g_return_if_fail (temp_prefs->tree);
-
-    g_tree_destroy(temp_prefs->tree);
-    g_free(temp_prefs);
-}
-
-/* Copy key data from the temp prefs tree to the hash table */
-static gboolean copy_key (gpointer key, gpointer value, gpointer user_data)
-{
-    prefs_set_string(key, value);
-	
-    return FALSE;
-}
-
-/* Copy the data from the temp prefs tree to the permanent prefs table */
-void temp_prefs_apply (TempPrefs *temp_prefs)
-{
-    g_return_if_fail (temp_prefs);
-    g_return_if_fail (temp_prefs->tree);
-
-    g_tree_foreach (temp_prefs->tree, copy_key, NULL);
-}
-
-
-/* Create a temp_prefs tree containing a subset of keys in the
-   permanent prefs table (those starting with @subkey */
-static TempPrefs *prefs_create_subset_unlocked (const gchar *subkey)
-{
-    struct sub_data sub_data;
-
-    g_return_val_if_fail (prefs_table, NULL);
-
-    sub_data.temp_prefs = temp_prefs_create ();
-    sub_data.subkey = subkey;
-
-    g_hash_table_foreach (prefs_table, (GHFunc)get_subset, &sub_data);
-
-    return sub_data.temp_prefs;
-}
-
-/* Create a temp_prefs tree containing a subset of keys in the
-   permanent prefs table (those starting with @subkey */
-TempPrefs *prefs_create_subset (const gchar *subkey)
-{
-    TempPrefs *temp_prefs;
-
-    lock_prefs_table ();
-
-    temp_prefs = prefs_create_subset_unlocked (subkey);
-
-    unlock_prefs_table ();
-
-    return temp_prefs;
-}
-
-
-/* Create a temp_prefs tree containing a subset of keys in the
-   permanent prefs table (those starting with @subkey */
-TempPrefs *temp_prefs_create_subset (TempPrefs *temp_prefs,
-				     const gchar *subkey)
-{
-    struct sub_data sub_data;
-
-    g_return_val_if_fail (temp_prefs, NULL);
-    g_return_val_if_fail (temp_prefs->tree, NULL);
-
-    sub_data.temp_prefs = temp_prefs_create ();
-    sub_data.subkey = subkey;
-
-    g_tree_foreach (temp_prefs->tree, get_subset, &sub_data);
-
-    return sub_data.temp_prefs;
-}
-
-
-/* Remove all keys in the temp prefs tree from the permanent prefs
-   table */
-void temp_prefs_flush (TempPrefs *temp_prefs)
-{
-    g_return_if_fail (temp_prefs);
-    g_return_if_fail (temp_prefs->tree);
-
-    lock_prefs_table ();
-
-    g_tree_foreach (temp_prefs->tree, flush_key, NULL);
-
-    unlock_prefs_table ();
-}
-
-/* Return the number of keys stored in @temp_prefs */
-gint temp_prefs_size (TempPrefs *temp_prefs)
-{
-    g_return_val_if_fail (temp_prefs, 0);
-    g_return_val_if_fail (temp_prefs->tree, 0);
-
-    return g_tree_nnodes (temp_prefs->tree);
-}
-
-
-/* Returns TRUE if at least one key starting with @subkey exists */
-gboolean temp_prefs_subkey_exists (TempPrefs *temp_prefs,
-				   const gchar *subkey)
-{
-    struct sub_data sub_data;
-
-    g_return_val_if_fail (temp_prefs && subkey, FALSE);
-
-    sub_data.temp_prefs = NULL;
-    sub_data.subkey = subkey;
-    sub_data.exists = FALSE;
-
-    g_tree_foreach (temp_prefs->tree, check_subkey, &sub_data);
-
-    return sub_data.exists;
-}
-
-
-/* Special functions */
-
-/* Remove all keys that start with @subkey */
-void prefs_flush_subkey (const gchar *subkey)
-{
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    g_hash_table_foreach_remove (prefs_table, match_subkey, (gchar *)subkey);
-
-    unlock_prefs_table ();
-}
-
-
-/* Rename all keys that start with @subkey_old in such a way that they
-   start with @subkey_new */
-void prefs_rename_subkey (const gchar *subkey_old, const gchar *subkey_new){
-    struct sub_data sub_data;
-
-    g_return_if_fail (subkey_old);
-    g_return_if_fail (subkey_new);
-
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    sub_data.temp_prefs = prefs_create_subset_unlocked (subkey_old);
-    sub_data.temp_prefs_orig = NULL;
-
-    if (temp_prefs_size (sub_data.temp_prefs) > 0)
-    {
-	sub_data.subkey = subkey_old;
-	sub_data.subkey2 = subkey_new;
-	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
-    }
-
-    temp_prefs_destroy (sub_data.temp_prefs);
-
-    unlock_prefs_table ();
-}
-
-
-/* Rename all keys that start with @subkey_old in such a way that they
-   start with @subkey_new */
-void temp_prefs_rename_subkey (TempPrefs *temp_prefs,
-			       const gchar *subkey_old,
-			       const gchar *subkey_new)
-{
-    struct sub_data sub_data;
-
-    g_return_if_fail (temp_prefs);
-    g_return_if_fail (subkey_old);
-    g_return_if_fail (subkey_new);
-
-    sub_data.temp_prefs_orig = temp_prefs;
-    sub_data.temp_prefs = temp_prefs_create_subset (temp_prefs,
-						    subkey_old);
-
-    if (temp_prefs_size (sub_data.temp_prefs) > 0)
-    {
-	sub_data.subkey = subkey_old;
-	sub_data.subkey2 = subkey_new;
-	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
-    }
-
-    temp_prefs_destroy (sub_data.temp_prefs);
-}
-
-/* Functions for non-numbered pref keys */
-
-/* Set a string value with the given key, or remove key if @value is
-   NULL */
-void prefs_set_string(const gchar *key, const gchar *value)
-{
-    g_return_if_fail (key);
-
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    if (value)
-	g_hash_table_insert (prefs_table,
-			     g_strdup(key), g_strdup(value));
-    else
-	g_hash_table_remove (prefs_table, key);
-
-    unlock_prefs_table ();
-}
-
-/* Set a key value to a given integer */
-void prefs_set_int(const gchar *key, const gint value)
-{
-    gchar *strvalue; /* String value converted from integer */
-
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    strvalue = g_strdup_printf("%i", value);
-    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
-
-    unlock_prefs_table ();
-}
-
-/* Set a key to an int64 value */
-void prefs_set_int64(const gchar *key, const gint64 value)
-{
-    gchar *strvalue; /* String value converted from int64 */
-	
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
-    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);	
-
-    unlock_prefs_table ();
-}
-
-void prefs_set_double(const gchar *key, gdouble value)
-{
-    gchar *strvalue; /* String value converted from integer */
-
-    lock_prefs_table ();
-
-    if (!prefs_table)
-    {
-	unlock_prefs_table ();
-	g_return_if_reached ();
-    }
-
-    strvalue = g_strdup_printf("%f", value);
-    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
-
-    unlock_prefs_table ();
-}
-
-/* Get a string value associated with a key. Free returned string. */
-gchar *prefs_get_string(const gchar *key)
-{
-    gchar *string = NULL;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), NULL));
-
-    string = g_strdup(g_hash_table_lookup(prefs_table, key));
-
-    unlock_prefs_table ();
-
-    return string;
-}
-
-/* Use this if you need to know if the given key actually exists */
-/* The value parameter can be NULL if you don't need the value itself. */
-gboolean prefs_get_string_value(const gchar *key, gchar **value)
-{
-    const gchar *string;  /* String value from prefs table */
-    gboolean valid = FALSE;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
-
-    string = g_hash_table_lookup(prefs_table, key);
-		
-    if (value)
-	*value = g_strdup (string);
-    if (string)
-	valid = TRUE;
-
-    unlock_prefs_table ();
-
-    return valid;
-}
-
-/* Get an integer value from a key */
-gint prefs_get_int(const gchar *key)
-{
-    gchar *string; /* Hash value string */
-    gint value;  /* Returned value */
-	
-    value = 0;
-	
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
-
-    string = g_hash_table_lookup(prefs_table, key);
-		
-    if (string)
-	value = atoi(string);
-
-    unlock_prefs_table ();
-
-    return value;
-}
-
-/* Use this if you need to know if the given key actually exists */
-/* The value parameter can be NULL if you don't need the value itself. */
-gboolean prefs_get_int_value(const gchar *key, gint *value)
-{
-    gchar *string;  /* String value from prefs table */
-    gboolean valid = FALSE;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
-
-    string = g_hash_table_lookup(prefs_table, key);
-
-    if (value)
-    {
-	if (string)
-	    *value = atoi(string);
-	else
-	    *value = 0;
-    }
-
-    if (string)
-	valid = TRUE;
-
-    unlock_prefs_table ();
-
-    return valid;
-}
-
-/* Get a 64 bit integer value from a key */
-gint64 prefs_get_int64(const gchar *key)
-{
-    gchar *string;  /* Key value string */
-    gint64 value;  /* Returned value */
-	
-    value = 0;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
-
-    string = g_hash_table_lookup(prefs_table, key);
-
-    if (string)
-	value = g_ascii_strtoull(string, NULL, 10);
-
-    unlock_prefs_table ();
-	
-    return value;
-}
-
-/* Get a 64 bit integer value from a key */
-/* Use this if you need to know if the given key actually exists */
-/* The value parameter can be NULL if you don't need the value itself. */
-gboolean prefs_get_int64_value(const gchar *key, gint64 *value)
-{
-    gchar *string;  /* String value from prefs table */
-    gboolean valid = FALSE;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
-
-    string = g_hash_table_lookup(prefs_table, key);
-		
-    if (value)
-    {
-	if (string)
-	    *value = g_ascii_strtoull(string, NULL, 10);
-	else
-	    *value = 0;
-    }
-
-    if (string)
-	valid = TRUE;
-
-    unlock_prefs_table ();
-
-    return valid;
-}
-
-gdouble prefs_get_double(const gchar *key)
-{
-    gchar *string;  /* Key value string */
-    gdouble value;  /* Returned value */
-	
-    value = 0;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
-
-    string = g_hash_table_lookup(prefs_table, key);
-
-    if (string)
-	value = g_ascii_strtod(string, NULL);
-
-    unlock_prefs_table ();
-	
-    return value;
-}
-
-gboolean prefs_get_double_value(const gchar *key, gdouble *value)
-{
-    gchar *string;  /* String value from prefs table */
-    gboolean valid = FALSE;
-
-    lock_prefs_table ();
-
-    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
-
-    string = g_hash_table_lookup(prefs_table, key);
-
-    if (value)
-    {
-	if (string)
-	    *value = g_ascii_strtod(string, NULL);
-	else
-	    *value = 0;
-    }
-
-    if (string)
-	valid = TRUE;
-
-    unlock_prefs_table ();
-
-    return valid;
-}
-
-/* Functions for numbered pref keys */
-
-/* Set a string value with the given key */
-void prefs_set_string_index(const gchar *key, const guint index, 
-			    const gchar *value)
-{
-    gchar *full_key; /* Complete numbered key */
-	
-    full_key = create_full_key(key, index);
-    prefs_set_string(full_key, value);
-	
-    g_free(full_key);
-}
-
-/* Set a key value to a given integer */
-void prefs_set_int_index(const gchar *key, const guint index, 
-			 const gint value)
-{
-    gchar *full_key; /* Complete numbered key */
-	
-    full_key = create_full_key(key, index);
-    prefs_set_int(full_key, value);
-	
-    g_free(full_key);
-}
-
-/* Set a key to an int64 value */
-void prefs_set_int64_index(const gchar *key, const guint index, 
-			   const gint64 value)
-{
-    gchar *full_key; /* Complete numbered key */
-	
-    full_key = create_full_key(key, index);
-    prefs_set_int64(full_key, value);
-	
-    g_free(full_key);
-}
-
-/* Set a key to a gdouble value */
-void prefs_set_double_index(const gchar *key, guint index,
-			     gdouble value)
-{
-    gchar *full_key; /* Complete numbered key */
-	
-    full_key = create_full_key(key, index);
-    prefs_set_double(full_key, value);
-	
-    g_free(full_key);
-}
-
-/* Get a string value associated with a key. Free returned string. */
-gchar *prefs_get_string_index(const gchar *key, const guint index)
-{	
-    gchar *full_key; /* Complete numbered key */
-    gchar *string;  /* Return string */
-	
-    full_key = create_full_key(key, index);
-    string = prefs_get_string(full_key);
-	
-    g_free(full_key);
-    return string;
-}
-
-/* Get a string value associated with a key. Free returned string. */
-/* Use this if you need to know if the given key actually exists */
-gboolean prefs_get_string_value_index(const gchar *key, const guint index, 
-				      gchar **value)
-{
-    gchar *full_key; /* Complete numbered key */
-    gboolean ret; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    ret = prefs_get_string_value(full_key, value);
-	
-    g_free(full_key);
-    return ret;
-}
-
-/* Get an integer value from a key */
-gint prefs_get_int_index(const gchar *key, const guint index)
-{
-    gchar *full_key; /* Complete numbered key */
-    gint value;  /* Returned integer value */
-
-    full_key = create_full_key(key, index);
-    value = prefs_get_int(full_key);
-	
-    g_free(full_key);
-    return value;
-}
-
-/* Get an integer value from a key */
-/* Use this if you need to know if the given key actually exists */
-gboolean prefs_get_int_value_index(const gchar *key, const guint index,  
-				   gint *value)
-{
-    gchar *full_key; /* Complete numbered key */
-    gboolean ret; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    ret = prefs_get_int_value(full_key, value);
-	
-    g_free(full_key);
-    return ret;
-}
-
-/* Get a 64 bit integer value from a key */
-gint64 prefs_get_int64_index(const gchar *key, const guint index)
-{
-    gchar *full_key; /* Complete numbered key */
-    gint64 value; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    value = prefs_get_int64(full_key);
-	
-    g_free(full_key);
-    return value;
-}
-
-/* Get a 64 bit integer value from a key */
-/* Use this if you need to know if the given key actually exists */
-gboolean prefs_get_int64_value_index(const gchar *key, const guint index, 
-				     gint64 *value)
-{
-    gchar *full_key; /* Complete numbered key */
-    gboolean ret; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    ret = prefs_get_int64_value(full_key, value);
-	
-    g_free(full_key);
-    return ret;
-}
-
-gdouble prefs_get_double_index(const gchar *key, guint index)
-{
-    gchar *full_key; /* Complete numbered key */
-    gdouble value; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    value = prefs_get_double(full_key);
-	
-    g_free(full_key);
-    return value;
-}
-
-gboolean prefs_get_double_value_index(const gchar *key, guint index,
-				      gdouble *value)
-{
-    gchar *full_key; /* Complete numbered key */
-    gboolean ret; /* Return value */
-	
-    full_key = create_full_key(key, index);
-    ret = prefs_get_double_value(full_key, value);
-	
-    g_free(full_key);
-    return ret;
-}
-
-/* Add string value with the given key to temp prefs. Note: use
- * temp_prefs_remove_key() to remove key from the temp prefs. Setting
- * it to NULL will not remove the key. It will instead remove the key
- * in the main prefs table when you call temp_prefs_apply(). */
-void temp_prefs_set_string (TempPrefs *temp_prefs, const gchar *key, 
-			   const gchar *value)
-{
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    g_tree_insert (temp_prefs->tree, g_strdup(key), g_strdup(value));
-}
-
-/* Add string value with the given key to temp prefs. Remove the key
- * if @value is NULL. */
-void temp_prefs_remove_key (TempPrefs *temp_prefs, const gchar *key)
-{
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    g_tree_remove (temp_prefs->tree, key);
-}
-
-/* Add an integer value to temp prefs */
-void temp_prefs_set_int(TempPrefs *temp_prefs, const gchar *key, 
-			const gint value)
-{
-    gchar *strvalue; /* String value converted from integer */
-
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    strvalue = g_strdup_printf("%i", value);
-    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
-}
-
-/* Add an int64 to temp prefs */
-void temp_prefs_set_int64(TempPrefs *temp_prefs, const gchar *key, 
-			  const gint64 value)
-{
-    gchar *strvalue; /* String value converted from int64 */
-	
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
-    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
-}
-
-void temp_prefs_set_double(TempPrefs *temp_prefs, const gchar *key,
-			   gdouble value)
-{
-    gchar *strvalue; /* String value converted from int64 */
-	
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    strvalue = g_strdup_printf("%fu", value);
-    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
-}
-
-/* Get a string value associated with a key. Free returned string. */
-gchar *temp_prefs_get_string(TempPrefs *temp_prefs, const gchar *key)
-{	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, NULL);
-    g_return_val_if_fail (key, NULL);
-
-    return g_strdup (g_tree_lookup (temp_prefs->tree, key));
-}
-
-/* Use this if you need to know if the given key actually exists */
-/* The value parameter can be NULL if you don't need the value itself. */
-gboolean temp_prefs_get_string_value(TempPrefs *temp_prefs,
-				     const gchar *key, gchar **value)
-{
-    gchar *string;  /* String value from prefs table */
-	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
-    g_return_val_if_fail (key, FALSE);
-
-    string = g_tree_lookup (temp_prefs->tree, key);
-
-    if (value)
-	*value = g_strdup (string);
-
-    if (string)
-	return TRUE;
-    else
-	return FALSE;
-}
-
-/* Get an integer value from a key */
-gint temp_prefs_get_int(TempPrefs *temp_prefs, const gchar *key)
-{
-    gchar *string; /* Hash value string */
-    gint value;  /* Returned value */
-	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
-    g_return_val_if_fail (key, 0);
-
-    value = 0;
-	
-    string = g_tree_lookup (temp_prefs->tree, key);
-		
-    if (string)
-	value = atoi(string);
-
-    return value;
-}
-
-/* Use this if you need to know if the given key actually exists */
-/* The value parameter can be NULL if you don't need the value itself. */
-gboolean temp_prefs_get_int_value(TempPrefs *temp_prefs,
-				  const gchar *key, gint *value)
-{
-    gchar *string;  /* String value from prefs table */
-	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
-    g_return_val_if_fail (key, FALSE);
-
-    string = g_tree_lookup (temp_prefs->tree, key);
-
-    if (value)
-    {
-	if (string)
-	    *value = atoi(string);
-	else
-	    *value = 0;
-    }
-
-    if (string)
-	return TRUE;
-    else
-	return FALSE;
-}
-
-gdouble temp_prefs_get_double(TempPrefs *temp_prefs,
-			      const gchar *key)
-{
-    gchar *string; /* Hash value string */
-    gdouble value;  /* Returned value */
-	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
-    g_return_val_if_fail (key, 0);
-
-    value = 0.0f;
-	
-    string = g_tree_lookup (temp_prefs->tree, key);
-		
-    if (string)
-	value = g_ascii_strtod(string, NULL);
-
-    return value;    
-}
-
-gboolean temp_prefs_get_double_value(TempPrefs *temp_prefs,
-				    const gchar *key, gdouble *value)
-{
-    gchar *string;  /* String value from prefs table */
-	
-    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
-    g_return_val_if_fail (key, FALSE);
-
-    string = g_tree_lookup (temp_prefs->tree, key);
-
-    if (value)
-    {
-	if (string)
-	    *value = g_ascii_strtod(string, NULL);
-	else
-	    *value = 0;
-    }
-
-    if (string)
-	return TRUE;
-    else
-	return FALSE;
-}
-
-/* Functions for numbered pref keys */
-
-/* Set a string value with the given key */
-void temp_prefs_set_string_index(TempPrefs *temp_prefs, const gchar *key,
-				 const guint index, const gchar *value)
-{
-    gchar *full_key; /* Complete numbered key */
-	
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    full_key = create_full_key(key, index);
-    temp_prefs_set_string(temp_prefs, full_key, value);
-	
-    g_free(full_key);
-}
-
-/* Set a key value to a given integer */
-void temp_prefs_set_int_index(TempPrefs *temp_prefs, const gchar *key,
-			      const guint index, const gint value)
-{
-    gchar *full_key; /* Complete numbered key */
-
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    full_key = create_full_key(key, index);
-    temp_prefs_set_int(temp_prefs, full_key, value);
-
-    g_free(full_key);
-}
-
-/* Set a key to an int64 value */
-void temp_prefs_set_int64_index(TempPrefs *temp_prefs, const gchar *key,  
-				const guint index, const gint64 value)
-{
-    gchar *full_key; /* Complete numbered key */
-
-    g_return_if_fail (temp_prefs && temp_prefs->tree);
-    g_return_if_fail (key);
-
-    full_key = create_full_key(key, index);
-    temp_prefs_set_int64(temp_prefs, full_key, value);
-
-    g_free(full_key);
-}
-
-/* Functions for variable-length lists */
-
-/* Create a tree that contains lists that need to be rebuilt */
-/* Free the returned structure with destroy_temp_lists */
-TempLists *temp_lists_create()
-{
-    TempLists *temp_lists;  /* Allocated temp list structure */
-	
-    temp_lists = (TempLists*)g_malloc(sizeof(TempLists));
-	
-
-    temp_lists->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
-				       g_free,
-				       (GDestroyNotify)prefs_free_list);
-    return temp_lists;
-}
-
-/* Destroys the list tree */
-void temp_lists_destroy(TempLists *temp_lists)
-{
-    if (temp_lists)
-    {
-	if (temp_lists->tree)
-	    g_tree_destroy(temp_lists->tree);
-		
-	g_free(temp_lists);
-    }
-}
-
-/* Add a list with the given key prefix to a temp list tree */
-void temp_list_add(TempLists *temp_lists, const gchar *key, GList *list)
-{
-    if (temp_lists)
-    {
-	if (temp_lists->tree)
-	    g_tree_insert(temp_lists->tree, g_strdup(key), list);
-    }
-}
-		
-/* Copy the items of the lists in the given tree to the prefs table */
-void temp_lists_apply(TempLists *temp_lists)
-{
-    if (temp_lists)
-    {
-	if (temp_lists->tree)
-	    g_tree_foreach(temp_lists->tree, copy_list, NULL);
-    }
-}
-
-/* Copy one list to the prefs table. Useful for lists not changed by a window */
-void prefs_apply_list(gchar *key, GList *list)
-{
-    GList *node;  /* Current list node */
-    guint i;  /* Counter */
-	
-    i = 0;
-	
-    if (prefs_table)
-    {
-	/* Clean the existing list */
-	wipe_list(key);
-		
-	node = list;
-		
-	/* Add the new list items to the table */
-	while (node)
-	{
-	    g_hash_table_insert(prefs_table, create_full_key(key, i), 
-				g_strdup(node->data));
-				
-	    node = g_list_next(node);
-	    i++;
-	}
-		
-	/* Add the end marker */
-	g_hash_table_insert(prefs_table, create_full_key(key, i),
-			    g_strdup(LIST_END_MARKER));
-    }
-}
-
-/* Get the items in a variable-length list from the prefs table */
-GList *prefs_get_list(const gchar *key)
-{
-    guint end_marker_hash;  /* Hash value of the list end marker */
-    guint item_hash;  /* Hash value of current list string */
-    gchar *item_string;  /* List item string */
-    guint i;  /* Counter */
-    GList *list;  /* List that contains items */
-	
-    /* Go through each key in the table until we find the end marker */
-    end_marker_hash = g_str_hash(LIST_END_MARKER);
-    list = NULL;
-	
-    for (i = 0;;i++)
-    {
-	item_string = prefs_get_string_index(key, i);
-		
-	if (item_string)
-	{
-	    item_hash = g_str_hash(item_string);
-			
-	    if (item_hash != end_marker_hash)
-	    {
-		list = g_list_append(list, item_string);
-		continue;
-	    }
-	    else
-	    {
-		g_free(item_string);
-		break;
-	    }
-	}
-    }
-	
-    return list;
-}
-
-/* Free a list and its strings */
-void prefs_free_list(GList *list)
-{
-    GList *node;  /* Current list node */
-	
-    node = list;
-	
-    /* Go through the list, freeing the strings */
-	
-    while (node)
-    {
-	if (node->data)
-	    g_free(node->data);
-		
-	node = g_list_next(node);
-    }
-	
-    g_list_free(list);
-}
-
-/* Creates a list from lines in a GtkTextBuffer. Free the list when done. */
-GList *get_list_from_buffer(GtkTextBuffer *buffer)
-{
-    GtkTextIter start_iter; /* Start of buffer text */
-    GtkTextIter end_iter; /* End of buffer text */
-    gchar *text_buffer; /* Raw text buffer */
-    gchar **string_array; /* Contains each line of the buffer */
-    gchar **string_iter;  /* Pointer for iterating through the string vector */
-    GList *list; /* List that contains each string */
-	
-    list = NULL;
-	
-    /* Grab the text from the buffer, and then split it up by lines */
-    gtk_text_buffer_get_start_iter(buffer, &start_iter);
-    gtk_text_buffer_get_end_iter(buffer, &end_iter);
-	
-    text_buffer = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
-    string_array = g_strsplit(text_buffer, "\n", -1);
-    string_iter = string_array;
-	
-    /* Go through each string and put it in the list */
-    while (*string_iter)
-    {
-	if (strlen(*string_iter) != 0)
-	    list = g_list_append(list, g_strdup(*string_iter));
-		
-	string_iter++;
-    }
-    
-    return list;
-}

Copied: gtkpod/tags/0.99.10-5/src/prefs.c (from rev 268, gtkpod/trunk/src/prefs.c)
===================================================================
--- gtkpod/tags/0.99.10-5/src/prefs.c	                        (rev 0)
+++ gtkpod/tags/0.99.10-5/src/prefs.c	2007-11-20 13:46:35 UTC (rev 280)
@@ -0,0 +1,2281 @@
+/*
+|  Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
+|  Copyright (C) 2006 James Liggett <jrliggett at cox.net>
+|  Part of the gtkpod project.
+|
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  This program is free software; you can redistribute it and/or modify
+|  it under the terms of the GNU General Public License as published by
+|  the Free Software Foundation; either version 2 of the License, or
+|  (at your option) any later version.
+|
+|  This program is distributed in the hope that it will be useful,
+|  but WITHOUT ANY WARRANTY; without even the implied warranty of
+|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+|  GNU General Public License for more details.
+|
+|  You should have received a copy of the GNU General Public License
+|  along with this program; if not, write to the Free Software
+|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+|
+|  iTunes and iPod are trademarks of Apple
+|
+|  This product is not supported/written/published by Apple!
+|
+|  $Id: prefs.c 1597 2007-06-26 14:35:18Z dforsi $
+*/
+
+/* -------------------------------------------------------------------
+ *
+ * HOWTO add a new_option to the prefs dialog
+ *
+ * - add the desired option to the prefs window using glade-2
+ *
+ * - set the default value of new_option in set_default_preferences() in prefs.c
+ *
+ * - add a callback on_new_option_*() to prefs_windows.c to set the
+ *   new value.
+ *   The value is applied to the actual prefs when pressing the "OK"
+ *   or "Apply" button in the prefs window.
+ *
+ * - add code to prefs_window_create() in prefs_window.c to set the
+ *   correct state of the option in the prefs window.
+ *
+ * - if you want new_option to be a command line option as well, add
+ *   code to usage() and read_commandline().
+ *
+ * - for environment variables, add code to read_environment().
+ *
+ * ---------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------
+ *
+ * The prefs module should be thread safe. The hash table is locked
+ * before each read or write access.
+ *
+ * The temp_prefs module is not thread-safe. If necessary a locking
+ * mechanism can be implemented.
+ *
+ * ---------------------------------------------------------------- */
+
+
+
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#ifdef HAVE_GETOPT_LONG_ONLY
+#  include <getopt.h>
+#else
+#  include "getopt.h"
+#endif
+
+#include "clientserver.h"
+#include "misc.h"
+#include "prefs.h"
+
+/*
+ * Data global to this module only
+ */
+
+/* End-of-list marker for variable-length lists */
+#define LIST_END_MARKER "----++++----"
+
+struct temp_prefs_save
+{
+    GIOChannel *gio;
+    GError **error;
+    gboolean success;
+};
+
+struct sub_data
+{
+    TempPrefs *temp_prefs;
+    TempPrefs *temp_prefs_orig;
+    const gchar *subkey;
+    const gchar *subkey2;
+    gboolean exists;
+};
+
+/* Pointer to preferences hash table */
+static GHashTable *prefs_table = NULL;
+static GMutex *prefs_table_mutex = NULL;
+
+/*
+ * Functions used by this module only
+ */
+void discard_prefs (void);
+
+/* Different paths that can be set in the prefs window */
+typedef enum
+{
+    PATH_PLAY_NOW = 0,
+    PATH_PLAY_ENQUEUE,
+    PATH_MP3GAIN,
+    PATH_SYNC_CONTACTS,
+    PATH_SYNC_CALENDAR,
+    PATH_MSERV_MUSIC_ROOT,
+    PATH_MSERV_TRACKINFO_ROOT,
+    PATH_SYNC_NOTES,
+    PATH_AACGAIN,
+    PATH_NUM
+} PathType;
+
+/* enum for reading of options */
+enum {
+  GP_HELP,
+  GP_PLAYCOUNT,
+  GP_MOUNT,
+  GP_PRINT_HASH,
+};
+
+
+/* Lock the prefs table. If the table is already locked the calling
+ * thread will remain blocked until the lock is released by the other thread. */
+static void lock_prefs_table ()
+{
+    g_return_if_fail (prefs_table_mutex);
+    g_mutex_lock (prefs_table_mutex);
+}
+
+/* Unlock the prefs table again. */
+static void unlock_prefs_table ()
+{
+    g_return_if_fail (prefs_table_mutex);
+    g_mutex_unlock (prefs_table_mutex);
+}
+
+
+/* Set default preferences */
+static void set_default_preferences()
+{
+    int i;
+    gchar *str;
+
+    prefs_set_int("update_existing", FALSE);
+    prefs_set_int("id3_write", FALSE);
+    prefs_set_int("id3_write_id3v24", FALSE);
+    prefs_set_int(KEY_SYNC_DELETE_TRACKS, TRUE);
+    prefs_set_int(KEY_SYNC_CONFIRM_DELETE, TRUE);
+    prefs_set_int(KEY_SYNC_SHOW_SUMMARY, TRUE);
+    prefs_set_int("show_duplicates", TRUE);
+    prefs_set_int("show_non_updated", TRUE);
+    prefs_set_int("show_updated", TRUE);
+    prefs_set_int("mserv_report_probs", TRUE);
+    prefs_set_int("delete_ipod", TRUE);
+    prefs_set_int("delete_file", TRUE);
+    prefs_set_int("delete_local_file", TRUE);
+    prefs_set_int("delete_database", TRUE);
+    prefs_set_string("initial_mountpoint", "/mnt/ipod");
+    prefs_set_string ("path_play_now", "xmms %s");
+    prefs_set_string ("path_play_enqueue", "xmms -e %s");
+    prefs_set_string ("path_mserv_trackinfo_root", "/var/lib/mserv/trackinfo/");
+
+    str = g_build_filename (SCRIPTDIR, "convert-ogg2mp3.sh", NULL);
+    prefs_set_string ("path_conv_ogg", str);
+    g_free (str);
+    prefs_set_int ("convert_ogg", TRUE);
+
+    str = g_build_filename (SCRIPTDIR, "convert-flac2mp3.sh", NULL);
+    prefs_set_string ("path_conv_flac", str);
+    g_free (str);
+    prefs_set_int ("convert_flac", TRUE);
+
+    str = g_build_filename (SCRIPTDIR, "convert-wav2mp3.sh", NULL);
+    prefs_set_string ("path_conv_wav", str);
+    g_free (str);
+    prefs_set_int ("convert_wav", FALSE);
+
+
+    /* Set sorting tab defaults */
+    for (i = 0; i < SORT_TAB_MAX; i++)
+    {
+	prefs_set_int_index("st_autoselect", i, TRUE);
+	prefs_set_int_index("st_category", i, (i < ST_CAT_NUM ? i : 0));
+	prefs_set_int_index("sp_or", i, FALSE);
+	prefs_set_int_index("sp_rating_cond", i, FALSE);
+	prefs_set_int_index("sp_playcount_cond", i, FALSE);
+	prefs_set_int_index("sp_played_cond", i, FALSE);
+	prefs_set_int_index("sp_modified_cond", i, FALSE);
+	prefs_set_int_index("sp_added_cond", i, FALSE);
+	prefs_set_int_index("sp_rating_state", i, 0);
+	prefs_set_string_index("sp_played_state", i, ">4w");
+	prefs_set_string_index("sp_modified_state", i, "<1d");
+	prefs_set_string_index("sp_added_state", i, "<1d");
+	prefs_set_int_index("sp_playcount_low", i, 0);
+	prefs_set_int_index("sp_playcount_high", i, -1);
+	prefs_set_int_index("sp_autodisplay", i, FALSE);
+    }
+    
+    prefs_set_int("sort_tab_num", 2);
+    
+    /* Set colum preferences */
+    for (i = 0; i < TM_NUM_COLUMNS; i++)
+    {
+	prefs_set_int_index("tm_col_width", i, 80);
+	prefs_set_int_index("col_visible", i, FALSE);
+	prefs_set_int_index("col_order", i, i);
+    }
+		
+    for (i = 0; i < TM_NUM_TAGS_PREFS; i++)
+	prefs_set_int_index("tag_autoset", i, FALSE);
+		
+    prefs_set_int_index("tag_autoset", TM_COLUMN_TITLE, TRUE);
+    
+    prefs_set_int_index("col_visible", TM_COLUMN_ARTIST, TRUE);
+    prefs_set_int_index("col_visible", TM_COLUMN_ALBUM, TRUE);
+    prefs_set_int_index("col_visible", TM_COLUMN_TITLE, TRUE);
+    prefs_set_int_index("col_visible", TM_COLUMN_GENRE, TRUE);
+    prefs_set_int_index("col_visible", TM_COLUMN_PLAYCOUNT, TRUE);
+    prefs_set_int_index("col_visible", TM_COLUMN_RATING, TRUE);
+
+    /* Set pane positions--Let gtk worry about position */
+    for (i = 0; i < PANED_NUM; i++)
+	prefs_set_int_index("paned_pos_", i, -1);
+	
+    prefs_set_int("mpl_autoselect", TRUE);
+	
+    /* Set window sizes */
+    prefs_set_int("size_gtkpod.x", 600);
+    prefs_set_int("size_gtkpod.y", 500);
+    prefs_set_int("size_cal.x", 500);
+    prefs_set_int("size_cal.y", 300);
+    prefs_set_int("size_conf_sw.x", 300);
+    prefs_set_int("size_conf_sw.y", 300);
+    prefs_set_int("size_conf.x", 300);
+    prefs_set_int("size_conf.y", -1);
+    prefs_set_int("size_dirbr.x", 300);
+    prefs_set_int("size_dirbr.y", 400);
+    prefs_set_int("size_prefs.x", -1);
+    prefs_set_int("size_prefs.y", 480);
+    prefs_set_int("size_info.x", 510);
+    prefs_set_int("size_info.y", 300);
+
+    /* size of file dialog if there is not a details textview */
+    prefs_set_int("size_file_dialog.x", 320);
+    prefs_set_int("size_file_dialog.y", 140);
+
+    /* size of file dialog if there is a details textview */
+    prefs_set_int("size_file_dialog_details.x", 320);
+    prefs_set_int("size_file_dialog_details.y", 140);
+
+    prefs_set_int("readtags", TRUE);
+    prefs_set_int("write_extended_info", TRUE);
+    prefs_set_int("parsetags", FALSE);
+    prefs_set_int("parsetags_overwrite", FALSE);
+    prefs_set_string("parsetags_template", "%a - %A/%T %t.mp3;%t.wav");
+    prefs_set_int("coverart_apic", TRUE);
+    prefs_set_int("coverart_file", TRUE);
+    prefs_set_string("coverart_template", "%A;folder.jpg");
+    prefs_set_int("mserv_use", FALSE);
+    prefs_set_string("mserv_username", "");
+    prefs_set_int("startup_messages", TRUE);
+    prefs_set_int("add_recursively", TRUE);
+    prefs_set_int("info_window", FALSE);
+    prefs_set_int("last_prefs_page", 0);
+    prefs_set_int("multi_edit_title", TRUE);
+    prefs_set_int("multi_edit", FALSE);
+    prefs_set_int("not_played_track", TRUE);
+    prefs_set_int("misc_track_nr", 25);
+    prefs_set_int("update_charset", FALSE);
+    prefs_set_int("display_tooltips_main", TRUE);
+    prefs_set_int("display_tooltips_prefs", TRUE);
+    prefs_set_int("display_toolbar", TRUE);
+    prefs_set_int("toolbar_style", GTK_TOOLBAR_BOTH);
+    prefs_set_int("sha1", TRUE);
+    prefs_set_string("export_template", "%o;%a - %t.mp3;%t.wav");
+    prefs_set_int("file_dialog_details_expanded", FALSE);
+
+    /* Set last browsed directory */
+    str = g_get_current_dir();
+
+    if (str)
+    {
+	prefs_set_string("last_dir_browsed", str);
+	g_free(str);
+    }
+    else
+	prefs_set_string("last_dir_browsed", g_get_home_dir());
+    
+    /* Set sorting prefs */
+    prefs_set_int("case_sensitive", FALSE);
+    prefs_set_int("tm_autostore", FALSE);
+    prefs_set_int("st_sort", SORT_NONE);
+    prefs_set_int("pm_sort", SORT_NONE);
+    prefs_set_int("tm_sortcol", TM_COLUMN_TITLE);
+    prefs_set_int("tm_sort", SORT_NONE);
+}
+
+/* Initialize default variable-length list entries */
+static void set_default_list_entries()
+{
+    if (!prefs_get_string_value_index("sort_ign_string_", 0, NULL))
+    {
+	prefs_set_string_index("sort_ign_string_", 0, "a ");
+	prefs_set_string_index("sort_ign_string_", 1, "an ");
+	prefs_set_string_index("sort_ign_string_", 2, LIST_END_MARKER);
+    }
+}
+
+/* A printf-like function that outputs in the system locale */
+static void locale_fprintf(FILE *fp, const gchar *format, ...)
+{
+    gchar *utf8_string; /* Raw UTF-8 string */
+    gchar *locale_string;  /* String in system locale format */
+    va_list format_list;  /* Printf-like formatting arguments */
+	
+    /* Create the locale format string based on the given format */
+    va_start(format_list, format);
+    utf8_string = g_strdup_vprintf(format, format_list);
+    va_end(format_list);
+	
+    locale_string = g_locale_from_utf8 (utf8_string, -1, NULL, NULL, NULL);
+	
+    if (fp)
+	fprintf(fp, "%s", locale_string);
+	
+    g_free(utf8_string);
+    g_free(locale_string);
+}
+
+/* Print commandline usage information */
+static void usage(FILE *fp)
+{
+  locale_fprintf(fp, _("gtkpod version %s usage:\n"), VERSION);
+  locale_fprintf(fp, _("  -h, --help:   display this message\n"));
+  locale_fprintf(fp, _("  -p <file>:    increment playcount for file by one\n"));
+  locale_fprintf(fp, _("  --hash <file>:print gtkpod hash for file\n"));
+  locale_fprintf(fp, _("  -m path:      define the mountpoint of your iPod\n"));
+  locale_fprintf(fp, _("  --mountpoint: same as '-m'.\n"));
+  locale_fprintf(fp, _("  -a:           import database automatically after start.\n"));
+  locale_fprintf(fp, _("  --auto:       same as '-a'.\n"));
+}
+
+/* Parse commandline based options */
+static void read_commandline(int argc, char *argv[])
+{
+    int option; /* Code returned by getopt */
+	
+    /* The options data structure. The format is standard getopt. */
+    struct option const options[] =
+	{
+	    { "h",           no_argument,	NULL, GP_HELP },
+	    { "help",        no_argument,	NULL, GP_HELP },
+	    { "p",           required_argument, NULL, GP_PLAYCOUNT },
+	    { "hash",        required_argument, NULL, GP_PRINT_HASH },
+	    { "m",           required_argument,	NULL, GP_MOUNT },
+	    { "mountpoint",  required_argument,	NULL, GP_MOUNT },
+	    { 0, 0, 0, 0 }
+	};
+	
+    /* Handle commandline options */
+    while ((option = getopt_long_only(argc, argv, "", options, NULL)) != -1)
+    {
+	switch (option)
+	{
+	case GP_HELP:
+	    usage(stdout);
+	    exit(0);
+	    break;
+	case GP_PLAYCOUNT:
+	    client_playcount(optarg);
+	    exit(0);
+	    break;
+	case GP_PRINT_HASH:
+	    print_sha1_hash (optarg);
+	    exit(0);
+	    break;
+	case GP_MOUNT:
+	    prefs_set_string("initial_mountpoint", optarg);
+	    break;
+	default:
+	    locale_fprintf(stderr, "Unknown option: %s\n", argv[optind]);
+	    usage(stderr);
+	    exit(1);
+	    break;
+	};
+    }
+}
+
+/* Read options from environment variables */
+static void read_environment()
+{
+    gchar *buf; 
+  
+    buf = convert_filename(getenv("IPOD_MOUNTPOINT"));
+    if (buf)
+	prefs_set_string("initial_mountpoint", buf);
+    g_free(buf);
+}
+ 
+/* Create a full numbered key from a base key string and a number.
+ * Free returned string. */
+static gchar *create_full_key(const gchar *base_key, gint index)
+{
+    if (base_key)
+	return g_strdup_printf("%s%i", base_key, index);
+    else 
+	return NULL;
+}
+
+/* Remove key present in the temp prefs tree from the hash table */
+static gboolean flush_key (gpointer key, gpointer value, gpointer user_data)
+{
+    g_return_val_if_fail (prefs_table, FALSE);
+
+    g_hash_table_remove (prefs_table, key);
+
+    return FALSE;
+}
+
+
+/* Copy key data from the temp prefs tree to the hash table (or to
+ * sub_data->temp_prefs_orig if non-NULL). The old key is removed. */
+static gboolean subst_key (gpointer key, gpointer value, gpointer user_data)
+{
+    struct sub_data *sub_data = user_data;
+    gint len;
+
+    g_return_val_if_fail (key && value && user_data, FALSE);
+    g_return_val_if_fail (sub_data->subkey && sub_data->subkey2, FALSE);
+    if (!sub_data->temp_prefs_orig)
+	g_return_val_if_fail (prefs_table, FALSE);
+    if (sub_data->temp_prefs_orig)
+	g_return_val_if_fail (sub_data->temp_prefs_orig->tree, FALSE);
+
+    len = strlen (sub_data->subkey);
+
+    if (strncmp (key, sub_data->subkey, len) == 0)
+    {
+	gchar *new_key = g_strdup_printf ("%s%s",
+					  sub_data->subkey2,
+					  ((gchar *)key)+len);
+	if (sub_data->temp_prefs_orig)
+	{
+	    g_tree_remove (sub_data->temp_prefs_orig->tree, key);
+	    g_tree_insert (sub_data->temp_prefs_orig->tree,
+			   new_key, g_strdup(value));
+	}
+	else
+	{
+	    g_hash_table_remove (prefs_table, key);
+	    g_hash_table_insert (prefs_table, new_key, g_strdup(value));
+	}
+    }
+    return FALSE;
+}
+
+/* return TRUE if @key starts with @subkey */
+static gboolean match_subkey (gpointer key, gpointer value, gpointer subkey)
+{
+    g_return_val_if_fail (key && subkey, FALSE);
+
+    if (strncmp (key, subkey, strlen (subkey)) == 0)  return TRUE;
+    return FALSE;
+}
+
+
+/* return TRUE and set sub_data->exists to TRUE if @key starts with
+ * @subkey */
+static gboolean check_subkey (gpointer key, gpointer value, gpointer user_data)
+{
+    struct sub_data *sub_data = user_data;
+
+    g_return_val_if_fail (key && user_data, TRUE);
+    g_return_val_if_fail (sub_data->subkey, TRUE);
+
+    if (strncmp (key, sub_data->subkey, strlen (sub_data->subkey)) == 0)
+    {
+	sub_data->exists = TRUE;
+	return TRUE;
+    }
+    return FALSE;
+}
+
+
+
+/* Add key/value to temp_prefs if it matches subkey -- called by
+ * prefs_create_subset() and temp_prefs_create_subset() */
+static gboolean get_subset (gpointer key, gpointer value, gpointer user_data)
+{
+    struct sub_data *sub_data = user_data;
+
+    g_return_val_if_fail (key && value && user_data, TRUE);
+    g_return_val_if_fail (sub_data->subkey && sub_data->temp_prefs, TRUE);
+
+    if (strncmp (key, sub_data->subkey,
+		 strlen (sub_data->subkey)) == 0)
+    {  /* match */
+	temp_prefs_set_string (sub_data->temp_prefs, key, value);
+    }
+    return FALSE; /* continue traversal (g_tree), ignored for g_hash */
+}
+
+
+/* Copy a variable-length list to the prefs table */
+static gboolean copy_list(gpointer key, gpointer value, gpointer user_data)
+{
+	prefs_apply_list((gchar*)key, (GList*)value);
+	return FALSE;
+}
+ 
+/* Callback that writes pref table data to a file */
+static void write_key(gpointer key, gpointer value, gpointer user_data)
+{
+    FILE *fp;  /* file pointer passed in through user_data */
+	
+    /* Write out each key and value to the given file */
+    fp = (FILE*)user_data;
+	
+    if (fp)
+	fprintf(fp, "%s=%s\n", (gchar*)key, (gchar*)value);
+}
+
+/* Gets a string that contains ~/.gtkpod/ If the folder doesn't exist,
+ * create it. Free the string when you are done with it.
+ * If the folder wasn't found, and couldn't be created, return NULL */
+gchar *prefs_get_cfgdir()
+{
+    gchar *folder;  /* Folder path */
+	
+    /* Create the folder path. If the folder doesn't exist, create it. */
+    folder = g_build_filename(g_get_home_dir(), ".gtkpod", NULL);
+	
+    if (!g_file_test(folder, G_FILE_TEST_IS_DIR))
+    {
+	if ((g_mkdir(folder, 0777)) == -1)
+	{
+	    printf(_("Couldn't create ~/.gtkpod\n"));
+	    return NULL;
+	}
+    }
+	
+    return folder;
+}
+
+
+/* get @key and @value from a string like "key=value" */
+static gboolean read_prefs_get_key_value (const gchar *buf,
+					  gchar **key, gchar **value)
+{
+    size_t len;  /* string length */
+    const gchar *buf_start; /* Pointer to where actual useful data starts in line */
+
+    g_return_val_if_fail (buf && key && value, FALSE);
+
+    /* Strip out any comments (lines that begin with ; or #) */
+    if ((buf[0] == ';') || (buf[0] == '#')) 
+	return FALSE;
+
+    /* Find the key and value, and look for malformed lines */
+    buf_start = strchr (buf, '=');
+
+    if ((!buf_start) || (buf_start == buf))
+    {
+	printf("Parse error reading prefs: %s", buf);
+	return FALSE;
+    }
+
+    /* Find the key name */
+    *key = g_strndup (buf, (buf_start - buf));
+
+    /* Strip whitespace */
+    g_strstrip (*key);
+
+    /* Find the value string */
+    *value = strdup (buf_start+1);
+
+    /* remove newline */
+    len = strlen (*value);
+    if ((len > 0) && ((*value)[len - 1] == 0x0a))
+	(*value)[len - 1] = 0;
+
+    /* Don't strip whitespace! If there is any, there's a reason for it. */
+    /* g_strstrip (*value); */
+
+    return TRUE;
+}
+
+
+/* Read preferences from a file */
+static void read_prefs_from_file(FILE *fp)
+{
+    gchar buf[PATH_MAX];  /* Buffer that contains one line */
+    gchar *key;  /* Pref value key */
+    gchar *value; /* Pref value */
+
+
+    g_return_if_fail (prefs_table && fp);
+
+    while (fgets(buf, PATH_MAX, fp))
+    {
+	if (read_prefs_get_key_value (buf, &key, &value))
+	{
+	    g_hash_table_insert (prefs_table, key, value);
+	}
+    }
+}
+
+/* Write prefs to file */
+static void write_prefs_to_file(FILE *fp)
+{
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    g_hash_table_foreach(prefs_table, write_key, (gpointer)fp);
+
+    unlock_prefs_table ();
+}
+
+/* Load preferences, first loading the defaults, and then overwrite that with
+ * preferences in the user home folder. */
+static void load_prefs()
+{
+    gchar *filename; /* Config path to open */
+    gchar *config_dir;  /* Directory where config is (usually ~/.gtkpod) */
+    FILE *fp;
+	
+    /* Start by initializing the prefs to their default values */
+    set_default_preferences();
+	
+    /* and then override those values with those found in the home folder. */
+    config_dir = prefs_get_cfgdir();
+	
+    if (config_dir)
+    {
+	filename = g_build_filename(config_dir, "prefs", NULL);
+		
+	if (filename)
+	{
+	    fp = fopen(filename, "r");
+			
+	    if (fp)
+	    {
+		read_prefs_from_file(fp);
+		fclose(fp);
+	    }
+			
+	    g_free(filename);
+	}
+		
+	g_free(config_dir);
+    }
+	
+    /* Finally, initialize variable-length lists. Do this after everything else
+     * so that list defaults don't hang out in the table after prefs have been
+     * read from the file. */
+    set_default_list_entries();
+}
+
+/* Save preferences to user home folder (~/.gtkpod/prefs) */
+void prefs_save ()
+{
+    gchar *filename;  /* Path of file to write to */
+    gchar *config_dir;   /* Folder where prefs file is */
+    FILE *fp;  /* File pointer */
+	
+    /* Open $HOME/.gtkpod/prefs, and write prefs */
+    config_dir = prefs_get_cfgdir();
+	
+    if (config_dir)
+    {
+	filename = g_build_filename(config_dir, "prefs", NULL);
+		
+	if (filename)
+	{
+	    fp = fopen(filename, "w");
+
+	    if (fp)
+	    {
+		write_prefs_to_file(fp);
+		fclose(fp);
+	    }
+		
+	    g_free(filename);
+	}
+		
+	g_free(config_dir);
+    }
+}
+
+
+static gboolean temp_prefs_save_fe (gchar *key, gchar *value,
+				    struct temp_prefs_save *tps)
+{
+    gchar *buf;
+    GIOStatus status;
+
+    buf=g_strdup_printf ("%s=%s\n", key, value);
+    status = g_io_channel_write_chars (tps->gio, buf, -1, NULL, tps->error);
+    g_free (buf);
+    if (status != G_IO_STATUS_NORMAL)
+    {
+	tps->success = FALSE;
+	return TRUE;  /* stop traversal */
+    }
+    return FALSE;
+}
+
+
+/* Save @temp_prefs to @filename in the same manner as prefs_save is
+ * saving to ~/.gtkpod/prefs. @error: location where to store
+ * information about errors or NULL.
+ * 
+ * Return value: TRUE on success, FALSE if an error occured, in which
+ * case @error will be set accordingly.
+ */
+gboolean temp_prefs_save (TempPrefs *temp_prefs,
+			  const gchar *filename,
+			  GError **error)
+{
+    GIOChannel *gio;
+    struct temp_prefs_save tps;
+
+    g_return_val_if_fail (temp_prefs && filename, FALSE);
+
+    gio = g_io_channel_new_file (filename, "w", error);
+    tps.gio = gio;
+    tps.error = error;
+    tps.success = TRUE;
+    if (gio)
+    {
+	g_tree_foreach (temp_prefs->tree, (GTraverseFunc)temp_prefs_save_fe, &tps);
+	g_io_channel_unref (gio);
+    }
+
+    return tps.success;
+}
+
+
+TempPrefs *temp_prefs_load (const gchar *filename, GError **error)
+{
+    GIOChannel *gio;
+    TempPrefs *temp_prefs = NULL;
+
+    g_return_val_if_fail (filename, NULL);
+
+    gio = g_io_channel_new_file (filename, "r", error);
+    if (gio)
+    {
+	GIOStatus status;
+
+	temp_prefs = temp_prefs_create ();
+
+	do
+	{
+	    gchar *line;
+
+	    status = g_io_channel_read_line (gio, &line, NULL, NULL, error);
+	    if (status == G_IO_STATUS_NORMAL)
+	    {
+		gchar *key, *value;
+		if (read_prefs_get_key_value (line, &key, &value))
+		{
+		    temp_prefs_set_string (temp_prefs, key, value);
+		}
+		g_free (line);
+	    }
+	} while (status == G_IO_STATUS_NORMAL);
+
+	g_io_channel_unref (gio);
+
+	if (status != G_IO_STATUS_EOF)
+	{
+	    temp_prefs_destroy (temp_prefs);
+	    temp_prefs = NULL;
+	}
+    }
+
+    return temp_prefs;
+}
+
+
+/* Removes already existing list keys from the prefs table */
+static void wipe_list(const gchar *key)
+{
+    gchar *full_key; /* Complete key, with its number suffix */
+    guint i;  /* Loop counter */
+	
+    /* Go through the prefs table, starting at key<number>, delete it and go 
+     * through key<number+1>... until there are no keys left */
+	
+    for (i = 0;;i++)
+    {
+	full_key = create_full_key(key, i);
+		
+	if (g_hash_table_remove(prefs_table, full_key))
+	{
+	    g_free(full_key);
+	    continue;
+	}
+	else /* We got all the unneeded keys, leave the loop... */
+	{
+	    g_free(full_key);
+	    break;
+	}
+    }		
+}
+
+/* Delete and rename keys */
+static void cleanup_keys()
+{
+    gchar *buf;
+    gchar *sp = NULL;
+    gint int_buf;
+    gint i;
+    gint x, y, p;  /* Window position */
+    float version=0;
+
+    /* Get version */
+    version = prefs_get_double("version");
+
+    /* rename mountpoint to initial_mountpoint */
+    if (prefs_get_string_value(KEY_MOUNTPOINT, &buf))
+    {
+	prefs_set_string("initial_mountpoint", buf);
+	g_free(buf);
+	prefs_set_string(KEY_MOUNTPOINT, NULL);
+    }
+  
+    /* rename coverart to coverart_file */
+    if (prefs_get_string_value("coverart", &buf))
+    {
+	prefs_set_string("coverart_file", buf);
+	g_free(buf);
+	prefs_set_string("coverart", NULL);
+    }
+  
+    /* rename tm_sort_ to tm_sort */
+    if (prefs_get_string_value("tm_sort_", &buf))
+    {
+	prefs_set_string("tm_sort", buf);
+	g_free(buf);
+	prefs_set_string("tm_sort_", NULL);
+    }
+
+    /* rename md5 to sha1 */
+    if (prefs_get_string_value("md5", &buf))
+    {
+	prefs_set_string("sha1", buf);
+	g_free(buf);
+	prefs_set_string("md5", NULL);
+    }
+
+    /* Convert old path numbered keys to named ones */
+  
+    /* Play Now */
+    if (prefs_get_string_value_index("path", PATH_PLAY_NOW, &buf))
+    {
+	prefs_set_string("path_play_now", buf);
+	prefs_set_string_index("path", PATH_PLAY_NOW, NULL);
+	if (version < 0.87)
+	{  /* default changed from "xmms -p %s" to "xmms
+	      %s" which avoids xmms from hanging --
+	      thanks to Chris Vine */
+	    if (strcmp (buf, "xmms -p %s") == 0)
+	    {
+		prefs_set_string ("path_play_now", "xmms %s");
+	    }
+	}
+	g_free(buf);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_PLAY_NOW, &buf))
+    {
+	prefs_set_string("path_play_now", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_PLAY_NOW, NULL);
+    }
+  
+    /* Enqueue */
+    if (prefs_get_string_value_index("path", PATH_PLAY_ENQUEUE, &buf))
+    {
+	prefs_set_string("path_play_enqueue", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_PLAY_ENQUEUE, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_PLAY_ENQUEUE, &buf))
+    {
+	prefs_set_string("path_play_enqueue", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_PLAY_ENQUEUE, NULL);
+    }
+  
+    /* MP3 Gain */
+    if (prefs_get_string_value_index("path", PATH_MP3GAIN, &buf))
+    {
+	prefs_set_string("path_mp3gain", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_MP3GAIN, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_MP3GAIN, &buf))
+    {
+	prefs_set_string("path_mp3gain", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_MP3GAIN, NULL);
+    }
+  
+    /* Sync contacts */
+    if (prefs_get_string_value_index("path", PATH_SYNC_CONTACTS, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_contacts", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_SYNC_CONTACTS, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_SYNC_CONTACTS, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_contacts", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_SYNC_CONTACTS, NULL);
+    }
+  
+    /* Sync calendar */
+    if (prefs_get_string_value_index("path", PATH_SYNC_CALENDAR, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_calendar", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_SYNC_CALENDAR, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_SYNC_CALENDAR, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_calendar", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_SYNC_CALENDAR, NULL);
+    }
+  
+    /* Sync notes */
+    if (prefs_get_string_value_index("path", PATH_SYNC_NOTES, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_notes", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_SYNC_NOTES, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_SYNC_NOTES, &buf))
+    {
+	prefs_set_string("itdb_0_path_sync_notes", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_SYNC_NOTES, NULL);
+    }
+  
+    /* MSERV music root */
+    if (prefs_get_string_value_index("path", PATH_MSERV_MUSIC_ROOT, &buf))
+    {
+	prefs_set_string("path_mserv_music_root", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_MSERV_MUSIC_ROOT, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_MSERV_MUSIC_ROOT, &buf))
+    {
+	prefs_set_string("path_mserv_music_root", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_MSERV_MUSIC_ROOT, NULL);
+    }
+  
+    /* MSERV track info root */
+    if (prefs_get_string_value_index("path", PATH_MSERV_TRACKINFO_ROOT, &buf))
+    {
+	prefs_set_string("path_mserv_trackinfo_root", buf);
+	g_free(buf);
+	prefs_set_string_index("path", PATH_MSERV_TRACKINFO_ROOT, NULL);
+    }
+  
+    if (prefs_get_string_value_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, &buf))
+    {
+	prefs_set_string("path_mserv_trackinfo_root", buf);
+	g_free(buf);
+	prefs_set_string_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, NULL);
+    }
+
+    /* If there's an extra (PATH_NUM) key, delete it */
+    prefs_set_string_index("path", PATH_NUM, NULL);
+    prefs_set_string_index("toolpath", PATH_NUM, NULL);
+
+    /* Ignore/remove some keys */
+    prefs_set_string("play_now_path", NULL);
+    prefs_set_string("sync_remove", NULL);
+    prefs_set_string("sync_remove_confirm", NULL);
+    prefs_set_string("show_sync_dirs", NULL);
+    prefs_set_string("play_enqueue_path", NULL);
+    prefs_set_string("mp3gain_path", NULL);
+    prefs_set_string("statusbar_timeout", NULL);
+    prefs_set_string("offline", NULL);
+    prefs_set_string("time_format", NULL);
+    prefs_set_string("id3_all", NULL);
+    prefs_set_string("pm_autostore", NULL);
+    prefs_set_string("backups", NULL);
+    prefs_set_string("save_sorted_order", NULL);
+    prefs_set_string("fix_path", NULL);
+    prefs_set_string("write_gaintag", NULL);
+    prefs_set_string("automount", NULL);
+    prefs_set_string("display_artcovers", NULL);
+    prefs_set_string("block_display", NULL);
+    prefs_set_string("tmp_disable_sort", NULL);
+    prefs_set_string("size_file_dialog.x", NULL);
+    prefs_set_string("size_file_dialog.y", NULL);
+    prefs_set_string("size_file_dialog_details.x", NULL);
+    prefs_set_string("size_file_dialog_details.y", NULL);
+    prefs_set_string("autoimport", NULL);
+    prefs_set_string("auto_import", NULL);
+
+    /* sp_created_cond renamed to sp_added_cond */
+    for (i = 0; i < SORT_TAB_MAX; i++)
+    {
+	if (prefs_get_int_value_index("sp_created_cond", i, &int_buf))
+	{
+	    prefs_set_int_index("sp_added_cond", i, int_buf);
+	    prefs_set_string("sp_created_cond", NULL);
+	}
+    }
+  
+    /* sp_created_state renamed to sp_added_state */
+    for (i = 0; i < SORT_TAB_MAX; i++)
+    {
+	if (prefs_get_int_value_index("sp_created_state", i, &int_buf))
+	{
+	    prefs_set_int_index("sp_added_state", i, int_buf);
+	    prefs_set_string("sp_created_state", NULL);
+	}
+    }
+  
+    /* sm_col_width renamed to tm_col_width */
+    for (i = 0; i < TM_NUM_COLUMNS; i++)
+    {
+	if (prefs_get_int_value_index("sm_col_width", i, &int_buf))
+	{
+	    prefs_set_int_index("tm_col_width", i, int_buf);
+	    prefs_set_string_index("sm_col_width", i, NULL);
+	}
+    }
+  
+    /* handle version changes in prefs */
+    if (version == 0.0)
+    {
+	/* most likely prefs file written by V0.50 */
+	/* I added two new PANED elements since V0.50 --> shift */
+	for (i=PANED_NUM_ST-1; i>=0; --i)
+	{
+	    prefs_set_int_index("paned_pos_", PANED_NUM_GLADE + i,
+				prefs_get_int_index("paned_pos_", PANED_NUM_GLADE + i - 2));
+	}
+	prefs_set_int_index("paned_pos_", PANED_STATUS1, -1);
+	prefs_set_int_index("paned_pos_", PANED_STATUS2, -1);
+    }
+
+    /* set statusbar paned to a decent value if unset */
+    if (prefs_get_int_index("paned_pos_", PANED_STATUS1) == -1)
+    {
+	x = prefs_get_int("size_gtkpod.x");
+	/* set to about 2/3 of the window width */
+	if (x>0)   
+	    prefs_set_int_index("paned_pos_", PANED_STATUS1, 20*x/30);
+    }
+  
+    if (prefs_get_int_index("paned_pos_", PANED_STATUS2) == -1)
+    {
+	x = prefs_get_int("size_gtkpod.x");
+	y = prefs_get_int("size_gtkpod.y");
+	p = prefs_get_int_index("paned_pos_", PANED_STATUS1);
+	/* set to about half of the remaining window */
+	if (x>0)   
+	    prefs_set_int_index("paned_pos_", PANED_STATUS2, (x-p)/2 );
+    }
+
+    /* Changed layout of info window between 0.72 and 0.73 */
+    if (version < 0.73)
+    {
+	prefs_set_string("size_info.x", NULL);
+	prefs_set_string("size_info.y", NULL);
+    }
+    
+    /* not_played_song renamed to not_played_track */
+    if (prefs_get_int_value("not_played_song", &int_buf))
+    {
+	prefs_set_int("not_played_track", int_buf);
+	prefs_set_string("not_played_song", NULL);
+    }
+
+    /* misc_song_nr renamed to misc_track_nr */
+    if (prefs_get_int_value("misc_song_nr", &int_buf))
+    {
+	prefs_set_int("misc_track_nr", int_buf);
+	prefs_set_string("misc_song_nr", NULL);
+    }
+
+    /* sm_autostore renamed to tm_autostore */
+    if (prefs_get_int_value("sm_autostore", &int_buf))
+    {
+	prefs_set_int("tm_autostore", int_buf);
+	prefs_set_string("sm_autostore", NULL);
+    }
+
+    /* sm_sortcol renamed to tm_sortcol */
+    if (prefs_get_int_value("sm_sortcol", &int_buf))
+    {
+	prefs_set_int("tm_sortcol", int_buf);
+	prefs_set_string("sm_sortcol", NULL);
+    }
+
+    /* sm_sort_ renamed to tm_sort */
+    if (prefs_get_int_value("sm_sort_", &int_buf))
+    {
+	prefs_set_int("tm_sort", int_buf);
+	prefs_set_string("sm_sort_", NULL);
+    }
+
+    /* filename_format renamed to export_template */
+    if (prefs_get_string_value("filename_format", &buf))
+    {
+	prefs_set_string("export_template", buf);
+	g_free(buf);
+	prefs_set_string("filename_format", NULL);
+    }
+
+    /* This string was a wrong autoconvert--just ignore it */
+    buf = prefs_get_string("export_template");
+    
+    if (buf && strcmp(buf, "%a - %a/%T - %T.mp3") == 0)
+	prefs_set_string("export_template", NULL);
+
+    g_free (buf);
+
+    /* We changed the meaning of the %x in export_template */
+    if (version < 0.72)
+    {
+	/* changed the meaning of the %x in export_template */
+	if (sp) while (*sp)
+	{
+	    if (sp[0] == '%')
+	    {
+		switch (sp[1]) {
+		case 'A':
+		    sp[1] = 'a';
+		    break;
+		case 'd':
+		    sp[1] = 'A';
+		    break;
+		case 'n':
+		    sp[1] = 't';
+		    break;
+		case 't':
+		    sp[1] = 'T';
+		    break;
+		default:
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* For versions < 0.91, remove all itdb keys */
+    if (version < 0.91)
+	prefs_flush_subkey("itdb_");
+   
+    prefs_set_string ("version", VERSION);
+}
+
+/* Initialize the prefs table and read configuration */
+void prefs_init (int argc, char *argv[])
+{
+    if (!prefs_table_mutex)
+	prefs_table_mutex = g_mutex_new ();
+
+    lock_prefs_table ();
+
+    /* Create the prefs hash table */
+    prefs_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+					g_free);
+
+    unlock_prefs_table ();
+
+    /* Load preferences */
+    load_prefs();
+
+    /* Clean up old prefs keys */
+    cleanup_keys();
+	
+    /* Read environment variables */
+    read_environment(); 
+	
+    /* Read commandline arguments */
+    read_commandline(argc, argv);  
+}
+
+/* Delete the hash table */
+void prefs_shutdown ()
+{
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    /* Delete the prefs hash table */
+    g_hash_table_destroy(prefs_table);
+    prefs_table = NULL;
+
+    unlock_prefs_table ();
+
+    /* We can't free the prefs_table_mutex in a thread-safe way */
+}
+
+/* Create the temp prefs tree */
+/* Free the returned structure with delete_temp_prefs() */
+TempPrefs *temp_prefs_create ()
+{
+    TempPrefs *temp_prefs;  /* Returned temp prefs structure */
+
+    temp_prefs = (TempPrefs*)g_malloc(sizeof(TempPrefs));
+
+    temp_prefs->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
+				       g_free, g_free);
+
+    return temp_prefs;	
+}
+
+/* Delete temp prefs */
+void temp_prefs_destroy (TempPrefs *temp_prefs)
+{
+    g_return_if_fail (temp_prefs);
+    g_return_if_fail (temp_prefs->tree);
+
+    g_tree_destroy(temp_prefs->tree);
+    g_free(temp_prefs);
+}
+
+/* Copy key data from the temp prefs tree to the hash table */
+static gboolean copy_key (gpointer key, gpointer value, gpointer user_data)
+{
+    prefs_set_string(key, value);
+	
+    return FALSE;
+}
+
+/* Copy the data from the temp prefs tree to the permanent prefs table */
+void temp_prefs_apply (TempPrefs *temp_prefs)
+{
+    g_return_if_fail (temp_prefs);
+    g_return_if_fail (temp_prefs->tree);
+
+    g_tree_foreach (temp_prefs->tree, copy_key, NULL);
+}
+
+
+/* Create a temp_prefs tree containing a subset of keys in the
+   permanent prefs table (those starting with @subkey */
+static TempPrefs *prefs_create_subset_unlocked (const gchar *subkey)
+{
+    struct sub_data sub_data;
+
+    g_return_val_if_fail (prefs_table, NULL);
+
+    sub_data.temp_prefs = temp_prefs_create ();
+    sub_data.subkey = subkey;
+
+    g_hash_table_foreach (prefs_table, (GHFunc)get_subset, &sub_data);
+
+    return sub_data.temp_prefs;
+}
+
+/* Create a temp_prefs tree containing a subset of keys in the
+   permanent prefs table (those starting with @subkey */
+TempPrefs *prefs_create_subset (const gchar *subkey)
+{
+    TempPrefs *temp_prefs;
+
+    lock_prefs_table ();
+
+    temp_prefs = prefs_create_subset_unlocked (subkey);
+
+    unlock_prefs_table ();
+
+    return temp_prefs;
+}
+
+
+/* Create a temp_prefs tree containing a subset of keys in the
+   permanent prefs table (those starting with @subkey */
+TempPrefs *temp_prefs_create_subset (TempPrefs *temp_prefs,
+				     const gchar *subkey)
+{
+    struct sub_data sub_data;
+
+    g_return_val_if_fail (temp_prefs, NULL);
+    g_return_val_if_fail (temp_prefs->tree, NULL);
+
+    sub_data.temp_prefs = temp_prefs_create ();
+    sub_data.subkey = subkey;
+
+    g_tree_foreach (temp_prefs->tree, get_subset, &sub_data);
+
+    return sub_data.temp_prefs;
+}
+
+
+/* Remove all keys in the temp prefs tree from the permanent prefs
+   table */
+void temp_prefs_flush (TempPrefs *temp_prefs)
+{
+    g_return_if_fail (temp_prefs);
+    g_return_if_fail (temp_prefs->tree);
+
+    lock_prefs_table ();
+
+    g_tree_foreach (temp_prefs->tree, flush_key, NULL);
+
+    unlock_prefs_table ();
+}
+
+/* Return the number of keys stored in @temp_prefs */
+gint temp_prefs_size (TempPrefs *temp_prefs)
+{
+    g_return_val_if_fail (temp_prefs, 0);
+    g_return_val_if_fail (temp_prefs->tree, 0);
+
+    return g_tree_nnodes (temp_prefs->tree);
+}
+
+
+/* Returns TRUE if at least one key starting with @subkey exists */
+gboolean temp_prefs_subkey_exists (TempPrefs *temp_prefs,
+				   const gchar *subkey)
+{
+    struct sub_data sub_data;
+
+    g_return_val_if_fail (temp_prefs && subkey, FALSE);
+
+    sub_data.temp_prefs = NULL;
+    sub_data.subkey = subkey;
+    sub_data.exists = FALSE;
+
+    g_tree_foreach (temp_prefs->tree, check_subkey, &sub_data);
+
+    return sub_data.exists;
+}
+
+
+/* Special functions */
+
+/* Remove all keys that start with @subkey */
+void prefs_flush_subkey (const gchar *subkey)
+{
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    g_hash_table_foreach_remove (prefs_table, match_subkey, (gchar *)subkey);
+
+    unlock_prefs_table ();
+}
+
+
+/* Rename all keys that start with @subkey_old in such a way that they
+   start with @subkey_new */
+void prefs_rename_subkey (const gchar *subkey_old, const gchar *subkey_new){
+    struct sub_data sub_data;
+
+    g_return_if_fail (subkey_old);
+    g_return_if_fail (subkey_new);
+
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    sub_data.temp_prefs = prefs_create_subset_unlocked (subkey_old);
+    sub_data.temp_prefs_orig = NULL;
+
+    if (temp_prefs_size (sub_data.temp_prefs) > 0)
+    {
+	sub_data.subkey = subkey_old;
+	sub_data.subkey2 = subkey_new;
+	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
+    }
+
+    temp_prefs_destroy (sub_data.temp_prefs);
+
+    unlock_prefs_table ();
+}
+
+
+/* Rename all keys that start with @subkey_old in such a way that they
+   start with @subkey_new */
+void temp_prefs_rename_subkey (TempPrefs *temp_prefs,
+			       const gchar *subkey_old,
+			       const gchar *subkey_new)
+{
+    struct sub_data sub_data;
+
+    g_return_if_fail (temp_prefs);
+    g_return_if_fail (subkey_old);
+    g_return_if_fail (subkey_new);
+
+    sub_data.temp_prefs_orig = temp_prefs;
+    sub_data.temp_prefs = temp_prefs_create_subset (temp_prefs,
+						    subkey_old);
+
+    if (temp_prefs_size (sub_data.temp_prefs) > 0)
+    {
+	sub_data.subkey = subkey_old;
+	sub_data.subkey2 = subkey_new;
+	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
+    }
+
+    temp_prefs_destroy (sub_data.temp_prefs);
+}
+
+/* Functions for non-numbered pref keys */
+
+/* Set a string value with the given key, or remove key if @value is
+   NULL */
+void prefs_set_string(const gchar *key, const gchar *value)
+{
+    g_return_if_fail (key);
+
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    if (value)
+	g_hash_table_insert (prefs_table,
+			     g_strdup(key), g_strdup(value));
+    else
+	g_hash_table_remove (prefs_table, key);
+
+    unlock_prefs_table ();
+}
+
+/* Set a key value to a given integer */
+void prefs_set_int(const gchar *key, const gint value)
+{
+    gchar *strvalue; /* String value converted from integer */
+
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    strvalue = g_strdup_printf("%i", value);
+    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
+
+    unlock_prefs_table ();
+}
+
+/* Set a key to an int64 value */
+void prefs_set_int64(const gchar *key, const gint64 value)
+{
+    gchar *strvalue; /* String value converted from int64 */
+	
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
+    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);	
+
+    unlock_prefs_table ();
+}
+
+void prefs_set_double(const gchar *key, gdouble value)
+{
+    gchar *strvalue; /* String value converted from integer */
+
+    lock_prefs_table ();
+
+    if (!prefs_table)
+    {
+	unlock_prefs_table ();
+	g_return_if_reached ();
+    }
+
+    strvalue = g_strdup_printf("%f", value);
+    g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
+
+    unlock_prefs_table ();
+}
+
+/* Get a string value associated with a key. Free returned string. */
+gchar *prefs_get_string(const gchar *key)
+{
+    gchar *string = NULL;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), NULL));
+
+    string = g_strdup(g_hash_table_lookup(prefs_table, key));
+
+    unlock_prefs_table ();
+
+    return string;
+}
+
+/* Use this if you need to know if the given key actually exists */
+/* The value parameter can be NULL if you don't need the value itself. */
+gboolean prefs_get_string_value(const gchar *key, gchar **value)
+{
+    const gchar *string;  /* String value from prefs table */
+    gboolean valid = FALSE;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
+
+    string = g_hash_table_lookup(prefs_table, key);
+		
+    if (value)
+	*value = g_strdup (string);
+    if (string)
+	valid = TRUE;
+
+    unlock_prefs_table ();
+
+    return valid;
+}
+
+/* Get an integer value from a key */
+gint prefs_get_int(const gchar *key)
+{
+    gchar *string; /* Hash value string */
+    gint value;  /* Returned value */
+	
+    value = 0;
+	
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
+
+    string = g_hash_table_lookup(prefs_table, key);
+		
+    if (string)
+	value = atoi(string);
+
+    unlock_prefs_table ();
+
+    return value;
+}
+
+/* Use this if you need to know if the given key actually exists */
+/* The value parameter can be NULL if you don't need the value itself. */
+gboolean prefs_get_int_value(const gchar *key, gint *value)
+{
+    gchar *string;  /* String value from prefs table */
+    gboolean valid = FALSE;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
+
+    string = g_hash_table_lookup(prefs_table, key);
+
+    if (value)
+    {
+	if (string)
+	    *value = atoi(string);
+	else
+	    *value = 0;
+    }
+
+    if (string)
+	valid = TRUE;
+
+    unlock_prefs_table ();
+
+    return valid;
+}
+
+/* Get a 64 bit integer value from a key */
+gint64 prefs_get_int64(const gchar *key)
+{
+    gchar *string;  /* Key value string */
+    gint64 value;  /* Returned value */
+	
+    value = 0;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
+
+    string = g_hash_table_lookup(prefs_table, key);
+
+    if (string)
+	value = g_ascii_strtoull(string, NULL, 10);
+
+    unlock_prefs_table ();
+	
+    return value;
+}
+
+/* Get a 64 bit integer value from a key */
+/* Use this if you need to know if the given key actually exists */
+/* The value parameter can be NULL if you don't need the value itself. */
+gboolean prefs_get_int64_value(const gchar *key, gint64 *value)
+{
+    gchar *string;  /* String value from prefs table */
+    gboolean valid = FALSE;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
+
+    string = g_hash_table_lookup(prefs_table, key);
+		
+    if (value)
+    {
+	if (string)
+	    *value = g_ascii_strtoull(string, NULL, 10);
+	else
+	    *value = 0;
+    }
+
+    if (string)
+	valid = TRUE;
+
+    unlock_prefs_table ();
+
+    return valid;
+}
+
+gdouble prefs_get_double(const gchar *key)
+{
+    gchar *string;  /* Key value string */
+    gdouble value;  /* Returned value */
+	
+    value = 0;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
+
+    string = g_hash_table_lookup(prefs_table, key);
+
+    if (string)
+	value = g_ascii_strtod(string, NULL);
+
+    unlock_prefs_table ();
+	
+    return value;
+}
+
+gboolean prefs_get_double_value(const gchar *key, gdouble *value)
+{
+    gchar *string;  /* String value from prefs table */
+    gboolean valid = FALSE;
+
+    lock_prefs_table ();
+
+    g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
+
+    string = g_hash_table_lookup(prefs_table, key);
+
+    if (value)
+    {
+	if (string)
+	    *value = g_ascii_strtod(string, NULL);
+	else
+	    *value = 0;
+    }
+
+    if (string)
+	valid = TRUE;
+
+    unlock_prefs_table ();
+
+    return valid;
+}
+
+/* Functions for numbered pref keys */
+
+/* Set a string value with the given key */
+void prefs_set_string_index(const gchar *key, const guint index, 
+			    const gchar *value)
+{
+    gchar *full_key; /* Complete numbered key */
+	
+    full_key = create_full_key(key, index);
+    prefs_set_string(full_key, value);
+	
+    g_free(full_key);
+}
+
+/* Set a key value to a given integer */
+void prefs_set_int_index(const gchar *key, const guint index, 
+			 const gint value)
+{
+    gchar *full_key; /* Complete numbered key */
+	
+    full_key = create_full_key(key, index);
+    prefs_set_int(full_key, value);
+	
+    g_free(full_key);
+}
+
+/* Set a key to an int64 value */
+void prefs_set_int64_index(const gchar *key, const guint index, 
+			   const gint64 value)
+{
+    gchar *full_key; /* Complete numbered key */
+	
+    full_key = create_full_key(key, index);
+    prefs_set_int64(full_key, value);
+	
+    g_free(full_key);
+}
+
+/* Set a key to a gdouble value */
+void prefs_set_double_index(const gchar *key, guint index,
+			     gdouble value)
+{
+    gchar *full_key; /* Complete numbered key */
+	
+    full_key = create_full_key(key, index);
+    prefs_set_double(full_key, value);
+	
+    g_free(full_key);
+}
+
+/* Get a string value associated with a key. Free returned string. */
+gchar *prefs_get_string_index(const gchar *key, const guint index)
+{	
+    gchar *full_key; /* Complete numbered key */
+    gchar *string;  /* Return string */
+	
+    full_key = create_full_key(key, index);
+    string = prefs_get_string(full_key);
+	
+    g_free(full_key);
+    return string;
+}
+
+/* Get a string value associated with a key. Free returned string. */
+/* Use this if you need to know if the given key actually exists */
+gboolean prefs_get_string_value_index(const gchar *key, const guint index, 
+				      gchar **value)
+{
+    gchar *full_key; /* Complete numbered key */
+    gboolean ret; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    ret = prefs_get_string_value(full_key, value);
+	
+    g_free(full_key);
+    return ret;
+}
+
+/* Get an integer value from a key */
+gint prefs_get_int_index(const gchar *key, const guint index)
+{
+    gchar *full_key; /* Complete numbered key */
+    gint value;  /* Returned integer value */
+
+    full_key = create_full_key(key, index);
+    value = prefs_get_int(full_key);
+	
+    g_free(full_key);
+    return value;
+}
+
+/* Get an integer value from a key */
+/* Use this if you need to know if the given key actually exists */
+gboolean prefs_get_int_value_index(const gchar *key, const guint index,  
+				   gint *value)
+{
+    gchar *full_key; /* Complete numbered key */
+    gboolean ret; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    ret = prefs_get_int_value(full_key, value);
+	
+    g_free(full_key);
+    return ret;
+}
+
+/* Get a 64 bit integer value from a key */
+gint64 prefs_get_int64_index(const gchar *key, const guint index)
+{
+    gchar *full_key; /* Complete numbered key */
+    gint64 value; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    value = prefs_get_int64(full_key);
+	
+    g_free(full_key);
+    return value;
+}
+
+/* Get a 64 bit integer value from a key */
+/* Use this if you need to know if the given key actually exists */
+gboolean prefs_get_int64_value_index(const gchar *key, const guint index, 
+				     gint64 *value)
+{
+    gchar *full_key; /* Complete numbered key */
+    gboolean ret; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    ret = prefs_get_int64_value(full_key, value);
+	
+    g_free(full_key);
+    return ret;
+}
+
+gdouble prefs_get_double_index(const gchar *key, guint index)
+{
+    gchar *full_key; /* Complete numbered key */
+    gdouble value; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    value = prefs_get_double(full_key);
+	
+    g_free(full_key);
+    return value;
+}
+
+gboolean prefs_get_double_value_index(const gchar *key, guint index,
+				      gdouble *value)
+{
+    gchar *full_key; /* Complete numbered key */
+    gboolean ret; /* Return value */
+	
+    full_key = create_full_key(key, index);
+    ret = prefs_get_double_value(full_key, value);
+	
+    g_free(full_key);
+    return ret;
+}
+
+/* Add string value with the given key to temp prefs. Note: use
+ * temp_prefs_remove_key() to remove key from the temp prefs. Setting
+ * it to NULL will not remove the key. It will instead remove the key
+ * in the main prefs table when you call temp_prefs_apply(). */
+void temp_prefs_set_string (TempPrefs *temp_prefs, const gchar *key, 
+			   const gchar *value)
+{
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    g_tree_insert (temp_prefs->tree, g_strdup(key), g_strdup(value));
+}
+
+/* Add string value with the given key to temp prefs. Remove the key
+ * if @value is NULL. */
+void temp_prefs_remove_key (TempPrefs *temp_prefs, const gchar *key)
+{
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    g_tree_remove (temp_prefs->tree, key);
+}
+
+/* Add an integer value to temp prefs */
+void temp_prefs_set_int(TempPrefs *temp_prefs, const gchar *key, 
+			const gint value)
+{
+    gchar *strvalue; /* String value converted from integer */
+
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    strvalue = g_strdup_printf("%i", value);
+    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
+}
+
+/* Add an int64 to temp prefs */
+void temp_prefs_set_int64(TempPrefs *temp_prefs, const gchar *key, 
+			  const gint64 value)
+{
+    gchar *strvalue; /* String value converted from int64 */
+	
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
+    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
+}
+
+void temp_prefs_set_double(TempPrefs *temp_prefs, const gchar *key,
+			   gdouble value)
+{
+    gchar *strvalue; /* String value converted from int64 */
+	
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    strvalue = g_strdup_printf("%fu", value);
+    g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
+}
+
+/* Get a string value associated with a key. Free returned string. */
+gchar *temp_prefs_get_string(TempPrefs *temp_prefs, const gchar *key)
+{	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, NULL);
+    g_return_val_if_fail (key, NULL);
+
+    return g_strdup (g_tree_lookup (temp_prefs->tree, key));
+}
+
+/* Use this if you need to know if the given key actually exists */
+/* The value parameter can be NULL if you don't need the value itself. */
+gboolean temp_prefs_get_string_value(TempPrefs *temp_prefs,
+				     const gchar *key, gchar **value)
+{
+    gchar *string;  /* String value from prefs table */
+	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
+    g_return_val_if_fail (key, FALSE);
+
+    string = g_tree_lookup (temp_prefs->tree, key);
+
+    if (value)
+	*value = g_strdup (string);
+
+    if (string)
+	return TRUE;
+    else
+	return FALSE;
+}
+
+/* Get an integer value from a key */
+gint temp_prefs_get_int(TempPrefs *temp_prefs, const gchar *key)
+{
+    gchar *string; /* Hash value string */
+    gint value;  /* Returned value */
+	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
+    g_return_val_if_fail (key, 0);
+
+    value = 0;
+	
+    string = g_tree_lookup (temp_prefs->tree, key);
+		
+    if (string)
+	value = atoi(string);
+
+    return value;
+}
+
+/* Use this if you need to know if the given key actually exists */
+/* The value parameter can be NULL if you don't need the value itself. */
+gboolean temp_prefs_get_int_value(TempPrefs *temp_prefs,
+				  const gchar *key, gint *value)
+{
+    gchar *string;  /* String value from prefs table */
+	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
+    g_return_val_if_fail (key, FALSE);
+
+    string = g_tree_lookup (temp_prefs->tree, key);
+
+    if (value)
+    {
+	if (string)
+	    *value = atoi(string);
+	else
+	    *value = 0;
+    }
+
+    if (string)
+	return TRUE;
+    else
+	return FALSE;
+}
+
+gdouble temp_prefs_get_double(TempPrefs *temp_prefs,
+			      const gchar *key)
+{
+    gchar *string; /* Hash value string */
+    gdouble value;  /* Returned value */
+	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
+    g_return_val_if_fail (key, 0);
+
+    value = 0.0f;
+	
+    string = g_tree_lookup (temp_prefs->tree, key);
+		
+    if (string)
+	value = g_ascii_strtod(string, NULL);
+
+    return value;    
+}
+
+gboolean temp_prefs_get_double_value(TempPrefs *temp_prefs,
+				    const gchar *key, gdouble *value)
+{
+    gchar *string;  /* String value from prefs table */
+	
+    g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
+    g_return_val_if_fail (key, FALSE);
+
+    string = g_tree_lookup (temp_prefs->tree, key);
+
+    if (value)
+    {
+	if (string)
+	    *value = g_ascii_strtod(string, NULL);
+	else
+	    *value = 0;
+    }
+
+    if (string)
+	return TRUE;
+    else
+	return FALSE;
+}
+
+/* Functions for numbered pref keys */
+
+/* Set a string value with the given key */
+void temp_prefs_set_string_index(TempPrefs *temp_prefs, const gchar *key,
+				 const guint index, const gchar *value)
+{
+    gchar *full_key; /* Complete numbered key */
+	
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    full_key = create_full_key(key, index);
+    temp_prefs_set_string(temp_prefs, full_key, value);
+	
+    g_free(full_key);
+}
+
+/* Set a key value to a given integer */
+void temp_prefs_set_int_index(TempPrefs *temp_prefs, const gchar *key,
+			      const guint index, const gint value)
+{
+    gchar *full_key; /* Complete numbered key */
+
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    full_key = create_full_key(key, index);
+    temp_prefs_set_int(temp_prefs, full_key, value);
+
+    g_free(full_key);
+}
+
+/* Set a key to an int64 value */
+void temp_prefs_set_int64_index(TempPrefs *temp_prefs, const gchar *key,  
+				const guint index, const gint64 value)
+{
+    gchar *full_key; /* Complete numbered key */
+
+    g_return_if_fail (temp_prefs && temp_prefs->tree);
+    g_return_if_fail (key);
+
+    full_key = create_full_key(key, index);
+    temp_prefs_set_int64(temp_prefs, full_key, value);
+
+    g_free(full_key);
+}
+
+/* Functions for variable-length lists */
+
+/* Create a tree that contains lists that need to be rebuilt */
+/* Free the returned structure with destroy_temp_lists */
+TempLists *temp_lists_create()
+{
+    TempLists *temp_lists;  /* Allocated temp list structure */
+	
+    temp_lists = (TempLists*)g_malloc(sizeof(TempLists));
+	
+
+    temp_lists->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
+				       g_free,
+				       (GDestroyNotify)prefs_free_list);
+    return temp_lists;
+}
+
+/* Destroys the list tree */
+void temp_lists_destroy(TempLists *temp_lists)
+{
+    if (temp_lists)
+    {
+	if (temp_lists->tree)
+	    g_tree_destroy(temp_lists->tree);
+		
+	g_free(temp_lists);
+    }
+}
+
+/* Add a list with the given key prefix to a temp list tree */
+void temp_list_add(TempLists *temp_lists, const gchar *key, GList *list)
+{
+    if (temp_lists)
+    {
+	if (temp_lists->tree)
+	    g_tree_insert(temp_lists->tree, g_strdup(key), list);
+    }
+}
+		
+/* Copy the items of the lists in the given tree to the prefs table */
+void temp_lists_apply(TempLists *temp_lists)
+{
+    if (temp_lists)
+    {
+	if (temp_lists->tree)
+	    g_tree_foreach(temp_lists->tree, copy_list, NULL);
+    }
+}
+
+/* Copy one list to the prefs table. Useful for lists not changed by a window */
+void prefs_apply_list(gchar *key, GList *list)
+{
+    GList *node;  /* Current list node */
+    guint i;  /* Counter */
+	
+    i = 0;
+	
+    if (prefs_table)
+    {
+	/* Clean the existing list */
+	wipe_list(key);
+		
+	node = list;
+		
+	/* Add the new list items to the table */
+	while (node)
+	{
+	    g_hash_table_insert(prefs_table, create_full_key(key, i), 
+				g_strdup(node->data));
+				
+	    node = g_list_next(node);
+	    i++;
+	}
+		
+	/* Add the end marker */
+	g_hash_table_insert(prefs_table, create_full_key(key, i),
+			    g_strdup(LIST_END_MARKER));
+    }
+}
+
+/* Get the items in a variable-length list from the prefs table */
+GList *prefs_get_list(const gchar *key)
+{
+    guint end_marker_hash;  /* Hash value of the list end marker */
+    guint item_hash;  /* Hash value of current list string */
+    gchar *item_string;  /* List item string */
+    guint i;  /* Counter */
+    GList *list;  /* List that contains items */
+	
+    /* Go through each key in the table until we find the end marker */
+    end_marker_hash = g_str_hash(LIST_END_MARKER);
+    list = NULL;
+	
+    for (i = 0;;i++)
+    {
+	item_string = prefs_get_string_index(key, i);
+		
+	if (item_string)
+	{
+	    item_hash = g_str_hash(item_string);
+			
+	    if (item_hash != end_marker_hash)
+	    {
+		list = g_list_append(list, item_string);
+		continue;
+	    }
+	    else
+	    {
+		g_free(item_string);
+		break;
+	    }
+	}
+    }
+	
+    return list;
+}
+
+/* Free a list and its strings */
+void prefs_free_list(GList *list)
+{
+    GList *node;  /* Current list node */
+	
+    node = list;
+	
+    /* Go through the list, freeing the strings */
+	
+    while (node)
+    {
+	if (node->data)
+	    g_free(node->data);
+		
+	node = g_list_next(node);
+    }
+	
+    g_list_free(list);
+}
+
+/* Creates a list from lines in a GtkTextBuffer. Free the list when done. */
+GList *get_list_from_buffer(GtkTextBuffer *buffer)
+{
+    GtkTextIter start_iter; /* Start of buffer text */
+    GtkTextIter end_iter; /* End of buffer text */
+    gchar *text_buffer; /* Raw text buffer */
+    gchar **string_array; /* Contains each line of the buffer */
+    gchar **string_iter;  /* Pointer for iterating through the string vector */
+    GList *list; /* List that contains each string */
+	
+    list = NULL;
+	
+    /* Grab the text from the buffer, and then split it up by lines */
+    gtk_text_buffer_get_start_iter(buffer, &start_iter);
+    gtk_text_buffer_get_end_iter(buffer, &end_iter);
+	
+    text_buffer = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
+    string_array = g_strsplit(text_buffer, "\n", -1);
+    string_iter = string_array;
+	
+    /* Go through each string and put it in the list */
+    while (*string_iter)
+    {
+	if (strlen(*string_iter) != 0)
+	    list = g_list_append(list, g_strdup(*string_iter));
+		
+	string_iter++;
+    }
+    
+    return list;
+}




More information about the Pkg-gtkpod-devel mailing list