#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell

#eval 'exec perl -w -S $0 ${1+"$@"}'
#    if 0; # not running under some shell

###########################################################################
#
#  gscmxx - a gtk frontend for scmxx
#  Copyright (C) 2002 koppi@weirdoz.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
# 
#  about scmxx 
#  scmxx is written by Hendrik Sattler <post@hendrik-sattler.de> 
#  find more information at http://www.hendrik-sattler.de/scmxx/
#
#  CHANGELOG
#  2002-11-23:   undef phonedefs after saveing preferences
#  2002-11-11:   added some translations (SMS related)
#  2002-11-09:   show 'Show all' in phonebook if search does not match any entry
#  2002-11-06:   added a new @INC path for privat debian installation
#                removed all the forking code, which caused problems
#                with perl 5.8.0
#  2002-11-04:   sorry no final version (still waiting for translations)
#                a lot of code reorganization
#                tested forking ($USEFORK = 1) of phone-detection (allows skipping)
#                skip detection of phone unless there are preferences
#                save number from incoming sms to phone/addressbook
#                save sms as txt
#                save phonebook/addressbook only if changed (cache)
#                "Save as File" -> check if file exists
#  2002-10-31:   version 0.4 (final, only waiting for translations)
#                retrieving %phonedefs is now handled in SCMxx.pm
#                removed some unneeded code
#  2002-10-19:   version 0.4pre6: =comment breaks 'make' (pod2man)
#                fixed number check in SCMxx.pm
#  2002-10-13:   version 0.4pre5
#                initialize SCMxx _after_ reading preferences!
#                sort phonebook after changeing or adding a new entry
#                dialog before deleting a phonebook item
#                new function: uniq_phonebook (wipe out duplicate entries)
#                new function: save_addressbook (saves whole addressbook
#                at the phone, first deletes all entris on the phone)
#                some small layout and i18n fixes
#  2002-09-25:   renamed Midi-Files to ringtones, some i18n stuff
#                new menu 'Multimedia' => Bitmaps, Ringtones 
#                changed 'Other Device' to integrate it into popup-menu
#  2002-09-23:   fixed a small bug (detection of available slots has been 
#                renamed in scmxx: Avail. Slots => Readable Slots)
#  2002-09-19:   ask before removing a vcard
#  2002-09-17:   sleep 1 sec between deleting and saving vcards
#                fixed: wrong slot number after saving vcard
#  2002-09-13:   check if at least name or firstname is filled out (vcards)
#                implemented popup for addressbook groups
#                changed -d option to -v (--verbose)
#                changes in saveing vcards
#  2002-09-12:   remember last used directory in file selection dialogs
#                removed the "Use Debug" option from the help menu (use -d)
#                all file selections and dialogs set to modal
#  2002-09-09:   fixed sendsms in popup-menu (phonebook)
#                display addressbook button / menu only if it is available
#  2002-09-04:   fixed displaying and uploading images
#                small layout changes at preferences screen
#                some more 18n stuff
#                changed timeout to 10sec steps
#                fixed a bug when opening .bmp files
#  2002-09-03:   added groups to phonebook and addressbook
#                allow adding of entries in empty phonebooks
#                compare function is now used for phone- and addressbook
#                sort phone- / addressbook by group
#                added group-popup to 'edit phonebook item' dialog
#                check number before saving phonebook item
#                renamed function 'show_address' to 'edit_address'
#                added sorting function to browse throu addresses
#                save phonebooks and addressbook to cache on exit
#  2002-09-02:   sorting of received sms, fixed a small bug in 'Records' list
#                small layout fixes
#  2002-09-01:   added man
#                cmd is active while detecting phone
#                use Image::Size to get width and height of bitmaps
#                use 'convert' to handle uploaded images and to convert 
#                bitmaps from the phone to xpm
#                load cached addressbook and phonebooks at startup
#				 new submenu /Preferences/Language to choose lang
#                status '$currentscreen' allows changing of lang easy
#                general timeout in prefs
#  2002-08-31:   new: list of records (received, missed, ... calls)
#                save, delete and open bitmaps (requires convert)
#                error as text (enables copying)
#  2002-08-30:   version changed to 0.4pre3
#                use Image::Size to display sizes of bitmaps
#                hash for bitmaps to store with and height
#                edit phonebook item: modal dialog, remove row if not saved
#  2002-08-29:   improved INC-pathes and pixmap/lang dirs
#  2002-08-28:   test if /proc/bus/usb/drivers is present before 
#                grepping a non existing file
#                find language files automatically
#                option -d to enable debug at startup
#                some more i18n, some debug info removed
#  2002-08-26:   Choose language at Preferences screen
#                removed some old stuff
#                CList instead of Table (for addressbook)
#                some more i18n
#                choose number to send sms from pbook and abook
#                (double click returns you to send sms screen)
#                different sort types for abook (thanx to CList)
#                removed old (pre-CList) code
#                cached addressbook will be loaded first
#                max size of entry boxes in edit address
#  2002-08-25:   i18n (alpha)
#  2002-08-23:   CList instead of Table (in list_phonebook)
#                all main wigets are now in $widgets = {};
#                edit phonebook entry in external window;
#                new help function popup_menu(\@items, $x, $y);
#  2002-08-22:   two versions of import addressbook / vcards 
#                (append and overwrite)
#                removed some old (not used) stuff
#  2002-08-21:   sensitivity of menu entries (for phone and addressbook)
#                import of vcards (append them to existing addrbook)
#                new menu 'Addressbook'
#  2002-08-20:   new main menu structure (alpha)
#                use cached phonebooks if available (info w/ date)
#                bugfix (pathes) in findpixmaps
#                save addressbook as file
#                load phonebook from file
#                PIN2 dialog for saving fixed dialing numbers (untestet)
#  2002-08-18:   major rewrites: moved SCMxx - related stuff into SCMxx.pm
#                support for all available phonebooks
#                improved sms-support
#                sms-types are now 'read', 'unread', 'sent', 'unsent'
#                improved error-handling
#                timeouts for fetching phone- and addressbook configurable
#  2002-08-16:   improved styles
#                SMS listings (sent and received)
#                midi-file listing ??
#                code cleanup
#  2002-08-15:   added gtk-style
#                small pixmaps for each screen
#                save phonebook as file (or only selected entries)
#                new function generate_phonebook_file
#                new function header($title, $pixmap) used in mainscreen
#                and waitscreen functions
#                implemented sorting of addressbook
#                added home- and mobile tel.nr. to addressbook list
#                added send-sms to addressbook list
#  2002-08-10:   layout changed (left frame for graphical buttons)
#                added support to write phonebook and addressbook entries
#                some code reorganized and cleaned up
#  2002-08-06:   added phonebook CS: Common sortable numbers (SM+ME+FD)
#                added search for address book
#                added send-sms function
#  2002-08-05:   initial alpha release 
#
###########################################################################

BEGIN {
    use Config;
    # find SCMxx.pm in developer dir
    use FindBin;
    my $bindir = $FindBin::Bin;
    push @INC, "$bindir/../SCMxx";

    # try to figure out the lib path if installed with prefix
    my $libp = $Config{'sitelib'};
    $libp  =~ s/^$Config{'siteprefix'}//;
    (my $libdir = $bindir) =~ s/bin$/$libp/;
    push @INC, $libdir;

	# 'vendor' installation with prefix (found at debian 3.0)
	$libp = $Config{'vendorlib'};
	$libp  =~ s/^$Config{'prefix'}//;
	($libdir = $bindir) =~ s/bin$/$libp/;
	push @INC, $libdir;
}

# if SCMxx is installed with /path/to/prefix
### special library path

use SCMxx;       # load SCMxx module

use Gtk;         # load the Gtk-Perl module

use Image::Size; # load Image::Size module (needed from img upload)

use strict;      # a good idea for all non-trivial Perl scripts

set_locale Gtk;  # internationalize ???

#use Data::Dumper; # for DEBUG only 
$|++; 

my $VERSION;
$VERSION = "0.4.1";

my $DEBUG = 0;

# TODO getopts
$DEBUG = 1 if grep /^-v$/, @ARGV;
$DEBUG = 1 if grep /^--verbose$/, @ARGV;
$SCMxx::DEBUG = $DEBUG;

# global vars
use vars qw(
	$widgets
	$i18n @languages
	$currentscreen

	%phonedefs
	%prefs @devices 
	%addressbook @mobileinfo %bitmaps @sounds %sms
	%phonebooks %available_phonebooks %groups
	%addresslabels %addresssizes
	$pin2
	$cmdactive
	%fonts %fontnames 
	%colors %colordefinitions
	%pixmaps
	%styles @states
	%opendirs 
	$scmxx 
	%tmpvals
);

$tmpvals{overwritefile} = 0; # temporary status values

# set phone independent preferences and init SCMxx
my $firststart = &set_startup_prefs(); 

init Gtk;        # initialize Gtk-Perl
my $splash = &startup;
unless ($firststart) {
	$prefs{phonetype} = &detect_phone;
}
$splash->destroy;
&main;

{
	local $^W = undef;
	main Gtk;
	# Should never get here
	exit( 0 );
}

sub main {
	#####
	# main window
	$widgets->{window} = new Gtk::Window( "toplevel" );
	# set signalhandler for window close
	$widgets->{window}->signal_connect("delete_event", \&CloseAppWindow);
	$widgets->{window}->set_title("gscmxx - " . &i18n("a frontend for siemens mobile phones"));
	$widgets->{window}->set_usize(600, 470);

	&setstyles();

	$widgets->{window}->set_style($styles{default});
	$widgets->{window}->realize;


	# Gtk event loop
	Gtk->main_iteration while (Gtk->events_pending);

	&mainwindow;

	if ($prefs{saved} == 0) {
		# show preferences if not set!
		&show_preferences;
	} else {
		# show the welcome splash screen
		&splashscreen;
	}
}

##################################################
# STARTUP
##################################################

sub startup {
	my $parent = shift;

	print "gscmxx version $VERSION
Written 2002 by koppi <koppi\@weirdoz.net>
Use it at your own risk!\n";

	my $scmxxversion = $scmxx->version();
	print "(using scmxx $scmxxversion by hendrik sattler <post\@hendrik-sattler.de>)\n\n\n";

	my $splash = new Gtk::Window;
	if ($parent) {
		$splash->signal_connect("delete_event", sub { 
				kill("TERM", $parent);
				$splash->destroy; 
				&main; }
		);
	}
	my $height = ($parent) ? 230 : 200;
	$splash->set_title("gscmxx - " . &i18n("a frontend for siemens mobile phones"));
	$splash->set_usize(200, $height);
	$splash->realize;

	my $style = new Gtk::Style;
	my $cm = $splash->get_colormap;
	$style->bg('normal', $cm->color_alloc({red=>65000, green=>65000, blue=>65000}));
	$splash->set_style($style);

	my $vbox = new Gtk::VBox();

	my $pixmap = &gscmxxpixmap($splash);
	$vbox->pack_start($pixmap, 0, 0, 0);
	$pixmap->show;

	my $txt = new Gtk::Label(&i18n("Detecting Phone") . "...");
	my $exfill = ($parent) ? 0 : 1;
	$vbox->pack_start($txt, $exfill, $exfill, 0);
	$txt->show;

	if ($parent) {	
		# Create a Adjusment object to hold the range of the progress bar
		my $adj = new Gtk::Adjustment( 0, 1, 100, 0, 0, 0 );

		# Create the GtkProgressBar using the adjustment
		$widgets->{pbar} = new_with_adjustment Gtk::ProgressBar( $adj );
	#	$widgets->{pbar}->set_format_string("Detecting Phone ...");
	#	$widgets->{pbar}->set_show_text(1);
		$widgets->{pbar}->set_activity_mode(1);
		$widgets->{pbar}->show();

		# Add a timer callback to update the value of the progress bar
		my $timer = Gtk->timeout_add( 150, \&progress_timeout );

		$vbox->pack_start($widgets->{pbar}, 0, 0, 0);

		my $button = new Gtk::Button("Skip detection");
		$button->signal_connect( "clicked", sub { 
				kill("TERM", $parent);
				$splash->destroy; 
				&main; });
		$vbox->pack_start($button, 0, 0, 0);
		$button->show;
	}
	$vbox->show;
	$splash->add($vbox);
	$splash->show;
	return $splash unless ($parent);
}

sub set_startup_prefs {
#	my $splash = shift;

	my @dirs = (".gscmxx", ".gscmxx/pbooks", ".gscmxx/bitmaps", ".gscmxx/midi");

	foreach my $d (@dirs) {
		if (! -e "$ENV{HOME}/$d") {
			print "Createing directory $ENV{HOME}/$d\n" if $DEBUG;
			mkdir ("$ENV{HOME}/$d", 0750);	
		} else {
			if (! -d "$ENV{HOME}/$d") {
				print "$ENV{HOME}/$d is no directory. Quitting!\n";
				&CloseAppWindow;
			}
			print "$ENV{HOME}/$d exists\n" if $DEBUG > 1;
		}
	}
	my ($firststart, $prefs) = &read_preferences;
	%prefs = %{$prefs};
	$i18n = &read_lang_file($prefs{language});

	# just get them one time
	@devices = &get_devices;

	if ($prefs{device} && !grep /$prefs{device}/, @devices) {
		if (-e $prefs{device}) {
			push @devices, $prefs{device};
		} else {
			$prefs{saved} = 0;	
			$prefs{errortxt} = &i18n("Your selected device") . " '$prefs{device}' " . &i18n("is not available") . "!";
		}
	}

	my $scmxxdoit = sub { Gtk->main_iteration while ( Gtk->events_pending ); };	
	$scmxx = new SCMxx (DOIT => $scmxxdoit, PREFERENCES => \%prefs);
#	$scmxx->set_preferences(\%prefs);

	unless ($addressbook{'__fetched'}) {
		%addressbook = ();
		%addressbook = &load_addressbook_from_file("$ENV{HOME}/.gscmxx/addressbook.cache");
	}

	opendir(DIR, "$ENV{HOME}/.gscmxx/pbooks");
	my @pbooks = grep { /\.pbook$/ } readdir(DIR);
	close(DIR);
	foreach (@pbooks) {
		s/\.pbook$//;
		$phonebooks{$_} = &load_phonebook_from_file($_, "$ENV{HOME}/.gscmxx/pbooks/$_.pbook");
		$available_phonebooks{$_} = "$SCMxx::pbookinfos{$_} (" . &i18n("cached") . ")";
	}

	# check wich groups are available at this phone
	%groups = %SCMxx::groups;
#	(
#		''		=> 'No Group',
#		'VIP'	=> 'VIP',
#		'OFF'	=> 'Office',
#		'FAM'	=> 'Family',
#		'LEI'	=> 'Leisure'
#	);


	%addresslabels = (
#		"FN"		=>	"00:Formatted Name",
		"N"			=> 	"01:Lastname",
		"SN"		=>	"02:Firstname",
		"ORG"		=>	"03:Company",
		"EMAIL;INTERNET"	=>	"04:Email",
		"TEL;HOME"	=>	"05:Tel, Home",
		"TEL;WORK"	=>	"06:Tel, Work",
		"TEL;CELL"	=>	"07:Tel, Mobile",
		"TEL;FAX"	=>	"08:Fax",
		"STREET"	=>	"09:Street",
		"ZIP"		=>	"10:ZIP",
		"CITY"		=>	"11:City",
		"COUNTRY"	=>	"12:Country",
		"URL"		=>	"13:URL",
	);
	%addresssizes = (
		"N"			=> 	"24",
		"SN"		=>	"16",
		"ORG"		=>	"16",
		"EMAIL;INTERNET"	=>	"40",
		"TEL;HOME"	=>	"40",
		"TEL;WORK"	=>	"40",
		"TEL;CELL"	=>	"40",
		"TEL;FAX"	=>	"40",
		"STREET"	=>	"40",
		"ZIP"		=>	"8",
		"CITY"		=>	"16",
		"COUNTRY"	=>	"16",
		"URL"		=>	"64",
	);


	return $firststart;
}

##################################################
# INFORMATION ABOUT THE PHONE 
##################################################
sub reload_information {
	$SCMxx::infotxt = "";
	@mobileinfo = ();
	&show_information;
}

sub show_information {

	return if $cmdactive;
	$currentscreen = sub { &show_information(@_) };

	unless (@mobileinfo) {
		&waitscreen('Information about your Mobile Phone', 'information.xpm');
		$cmdactive = 1;
		my $info = $scmxx->information();
		$cmdactive = 0;
		if ($info =~ /^ERROR /) {
			&errorscreen(&i18n('Information about your Mobile Phone'), $info);
			return;
		} else {
			@mobileinfo = split (/\n/, $info);
		}
	}
	&clean_main_box;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});
#	if (grep /ERROR/, @mobileinfo) {
#		my $error = new Gtk::VBox(0,0);
#
#		my $errortxt = join ("\n", @mobileinfo);
#		my $err = new Gtk::Text();
#		$err->insert(undef,undef,undef,$errortxt);
#		$err->set_alignment( 0, 0 );
# 		$err->set_justify( 'left' );
# 		$err->set_line_wrap( 1 );
#
#		$error->pack_start( $err, 1, 1, 5);
#		$err->show();
#
#		my $bbox = new Gtk::HBox(0,5);
#		my $button = new Gtk::Button(&i18n("Edit Preferences"));
#		$button->signal_connect( "clicked", \&show_preferences );
#		$bbox->pack_start( $button, 1, 0, 0 );
#		$button->show();
#		$error->pack_start( $bbox, 0, 0, 0 );
#		$bbox->show;
#		$content->add($error);
#		$error->show;
#
#	} else {
		my $rows = $#mobileinfo + 1;
		my $table = new Gtk::Table( $rows, 2, 0);	
		$table->set_row_spacings(3);
		$table->set_col_spacings(3);
		my $i = 0;	
		foreach my $line (@mobileinfo) {
			chomp $line;
			my ($k, $v) = split(/:\s+/, $line, 2);
			if ($k && $v) {
				my $txt;
				if ($k =~ /(\w+) \((\w+)\)/) {
					$txt = &i18n($1) . " (" . &i18n($2) . ")";
				} else {
					$txt = &i18n($k);
				}
				my $kl = new Gtk::Label("$txt: ");
				$kl->set_alignment( 0, 0 );
				$table->attach( $kl, 0, 1, $i, $i+1, 'fill', 'shrink',0,0 );
				$kl->show;
				my $vl = new Gtk::Label($v);
				$vl->set_alignment( 0, 0 );
				$vl->set_justify( 'left' );
				$vl->set_line_wrap( 1 );
				$table->attach( $vl, 1, 2, $i, $i+1, 'fill', 'shrink', 0,0 );
				$vl->show;
				$i++;
			} elsif ($k) {
				if ($i != 0) {
					my $space = new Gtk::Label("####");
					$table->attach($space, 0, 2, $i, $i+1, ['expand','fill'], 'fill', 0, 0);
					$i++;
				}
				my $txt;
				if ($k =~ /(\w+) \((\w+)\)/) {
					$txt = &i18n($1) . " (" . &i18n($2) . ")";
				} else {
					$txt = &i18n($k);
				}
				my $box = new Gtk::EventBox();
				$box->set_style($styles{row0});

				my $kl = new Gtk::Label("$txt");
				$kl->set_alignment( 0, 0 );
				$box->add($kl);
				$kl->show;
				$table->attach($box, 0, 2, $i, $i+1, ['expand','fill'], 'fill', 0, 0);
#				$table->attach( $kl, 0, 2, $i, $i+1, 'fill', 'shrink',0,0 );
				$box->show;
				$i++;
			}
		}
		$table->show();
		$content->add($table);	
#		my $text = new Gtk::Text();
#		$text->insert(undef,undef,undef,join("\n", @mobileinfo));
#		$text->show;
#		$content->add($text);
#	}
	$content->show();

	# buttons
	my $footer = new Gtk::HBox(0,5);

	my $reload = new Gtk::Button(&i18n("Reload"));
	$reload->signal_connect( "clicked", \&reload_information );
	my $tooltip = new Gtk::Tooltips();
	$tooltip->set_tip( $reload, &i18n("Reload Information"), "" );
	$tooltip->enable(); 
	$footer->pack_end( $reload, 0, 0, 0 );
	$reload->show();
	$footer->show();

	&mainscreen(HEADER => 'Information about your Mobile Phone',
			ICON	=> 'information.xpm',
			CONTENT => $content,
			FOOTER	=> $footer);
}

##################################################
# SMS RELATED FUNCTIONS
##################################################

sub list_sms {
	my $type = shift || 'unread';

	return if ($cmdactive);
	$currentscreen = sub { &list_sms($type) };


	if (ref($type) =~ /^Gtk::/) { $type = 'unread'; };

	my @types = qw(unread read unsent sent);

	unless ($sms{$type}) {
		&waitscreen("SMS", 'sms.xpm');
		$cmdactive = 1;
		foreach my $t(@types) {
			next if ($sms{$t});
			my $sms = $scmxx->get_sms($t, 'HASH');
			if ($sms =~ /^ERROR /) {
				&errorscreen(&i18n('SMS'), $sms);
			} else {
				$sms{$t} = $sms;
			}
		}
		$cmdactive = 0;
	}

	&clean_main_box;


	my %counts;
	foreach (keys %sms) {
		$counts{$_} = keys %{$sms{$_}};
	}
	my %types = ("unread" => &i18n("Received") . " / " . &i18n("unread") . ( (defined $counts{unread}) ? " ($counts{unread})" : '' ), 
			"read" => &i18n("Received") . " / " . &i18n("read") . ( (defined $counts{read}) ? " ($counts{read})" : '' ), 
			"sent" => &i18n("Sent") . ( (defined $counts{sent}) ? " ($counts{sent})" : '' ), 
			"unsent" => &i18n("Unsent") . ( (defined $counts{unsent}) ? " ($counts{unsent})" : '' ) 
	);
	my $menu = new Gtk::HBox(0,0);

	my $typelabel = new Gtk::Label(&i18n('Show') . ": ");
	$menu->pack_start($typelabel, 0, 0, 0);
	$typelabel->show();	

	my $typemenu = new Gtk::OptionMenu();
	my $typepopup = new Gtk::Menu();
	$typepopup->set_title(&i18n("SMS"));
	my $num = 0;
	my $seltype = 0;
	
	foreach my $i (@types) {
		my $item = new Gtk::MenuItem( $types{$i} );
		$item->signal_connect( 'activate', sub { &list_sms($i); });
		$typepopup->append($item);
		$item->show();
		if ($i eq $type) {
			$seltype = $num;
		}
		$num++;
	}
	$typemenu->set_menu($typepopup);	
	$typemenu->set_history( $seltype );
	$menu->pack_start($typemenu, 0, 0, 0);
	$typemenu->show();

	my $sendnew = create_pixmap_button('', sub { &sendsms_form('','','','smslist',$type,''); }, 'sendsms.xpm', 'hor', 'Send SMS');
	$menu->pack_end( $sendnew, 0, 0, 0 );
	
	$menu->show;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $rows = keys %{$sms{$type}};
	my $table = new Gtk::Table($rows*3, 3, 0);
	my $i = 0; my $j = 0;
	foreach my $slot(sort { 
			my $x = $sms{$type}->{$a}->{Date} || 0;
			my $y = $sms{$type}->{$b}->{Date} || 0;
			$x =~ s/\D//g;	
			$y =~ s/\D//g;	
			$y <=> $x;
			} keys %{$sms{$type}}) {
		my $num; my $numpre;
		if ($type eq "read" || $type eq "unread") {
			$num = $sms{$type}->{$slot}->{From};
			$numpre = &i18n("From") . ": ";
		} else {
			$num = $sms{$type}->{$slot}->{To};
			$numpre = &i18n("To") . ": ";
		}
		$num ||= "";
		my $rstyle = ($j % 2 == 0) ? $styles{row0} : $styles{default};

		my $name;
		if ($num) {
			if (%addressbook) {
				foreach (keys %addressbook) {
					next if ($_ =~ /^__/);
					if (( $addressbook{$_}->{"TEL;CELL"} && $addressbook{$_}->{"TEL;CELL"} eq $num ) ||
						( $addressbook{$_}->{"TEL;HOME"} && $addressbook{$_}->{"TEL;HOME"} eq $num ) ||
						( $addressbook{$_}->{"TEL;WORK"} && $addressbook{$_}->{"TEL;WORK"} eq $num )
					) {
						$name = $addressbook{$_}->{FN};
						last;
					}
				}
			}
			if (!$name && %phonebooks) {
				BOOKS: foreach my $type (keys %phonebooks) {
					next unless ref($phonebooks{$type}) eq "HASH";
					next unless $phonebooks{$type}->{__fetched};
					foreach (keys %{$phonebooks{$type}}) {
						next if ($_ =~ /^__/);
						if ($phonebooks{$type}->{$_}->{NUMBER} && $phonebooks{$type}->{$_}->{NUMBER} eq $num) {
							$name = $phonebooks{$type}->{$_}->{NAME};
							last BOOKS;
						}
					}
				}
			}
		}		  

		my $label = $numpre . ($name ? $name . "\n" . (" " x (length($numpre)+2) ) : "") . $num;
		my $box = new Gtk::EventBox();
		$box->set_style($rstyle);
		my $nl = new Gtk::Label($label);
		$nl->set_justify('left');
		$nl->show;
		if ($num && !$name &&
			(
				($phonebooks{SM} && $phonebooks{SM}->{__fetched} ) ||
				($phonebooks{ME} && $phonebooks{ME}->{__fetched} ) ||
				($phonedefs{vcf} && $addressbook{__fetched} )
			)
		) {
			
			my $hbox = new Gtk::HBox();
			$hbox->pack_start($nl, 0, 1, 0);
			
			my $takenum = create_pixmap_button('', sub { &takenumber($num, ''); }, 'save.xpm', 'hor', 'Save this Number', $rstyle);
			$hbox->pack_start($takenum, 0, 1, 0);
			$box->add($hbox);
			$hbox->show;
		} else {
			$nl->set_alignment(0, 0);
			$box->add($nl);
		}
		$table->attach($box, 0, 1, $i, $i+1, ['expand','fill'], ['fill'], 0, 0);
		$box->show;


		$box = new Gtk::EventBox();
		$box->set_style($rstyle);
		$nl = new Gtk::Label($sms{$type}->{$slot}->{Date} || " ");
#		$nl->set_alignment(0, 0);
		$nl->set_justify('left');
		$box->add($nl);
		$nl->show;
		$table->attach($box, 1, 2, $i, $i+1, ['expand','fill'], ['fill'], 0, 0);
		$box->show;

		$box = new Gtk::EventBox();
		$box->set_style($rstyle);

		my $vbox = new Gtk::VBox();
		my $del = create_pixmap_button('', sub { &delete_sms($slot, $type); }, 'delete.xpm', 'hor', 'Delete item', $rstyle);
		$vbox->pack_start($del, 0, 0, 0);
		if ($type eq "read" || $type eq "unread") {
			my $reply = create_pixmap_button('', sub { &sendsms_form($num, $name, '', 'smslist', $type, ''); }, 'sendsms.xpm', 'hor', 'Reply', $rstyle);
			$vbox->pack_start($reply, 0, 0, 0);
		}
		if ($type eq "unsent") {
			my $send = create_pixmap_button('', sub { &sendsms_form($num, $name, '', 'smslist', $type, $sms{$type}->{$slot}->{Message}); }, 'sendsms.xpm', 'hor', 'Send SMS', $rstyle);
			$vbox->pack_start($send, 0, 0, 0);
		}
		my $saveas = create_pixmap_button('', sub { &save_sms_as_file($numpre, $num, $name, $sms{$type}->{$slot}->{Date}, $sms{$type}->{$slot}->{Message}); }, 'saveas.xpm', 'hor', 'Save as File', $rstyle);
		$vbox->pack_start($saveas, 0, 0, 0);

		$vbox->show;
		$box->add($vbox);
		$table->attach( $box, 2, 3, $i, $i+2, ['shrink','fill'], 'fill', 0, 0 );
		$box->show;


		$box = new Gtk::EventBox();
		$box->set_style($rstyle);
		my $mess = new Gtk::Label($sms{$type}->{$slot}->{Message});
		$mess->set_line_wrap(1);
		$mess->set_alignment(0, 0);
		$box->add($mess);
		$table->attach($box, 0, 2, $i+1, $i+2, ['expand', 'fill'], 'fill', 0, 0);
		$mess->set_justify('fill');
		$mess->show;
		$box->set_sensitive(1);
		$box->show;

		$table->set_row_spacing(($i+1),5);
		$box = new Gtk::EventBox();
		$box->set_style($styles{default});
		my $sep = new Gtk::HSeparator();
		$box->add($sep);
		$table->attach($box, 0, 3, $i+2, $i+3, ['expand', 'fill'], 'fill', 0, 0);
		$sep->show;
		$box->show;
		$table->set_row_spacing(($i+2),5);

		$i=$i+3;
		$j++;
	}
	$content->add($table);
	$table->show();

	# buttons
	my $footer = new Gtk::HBox(0,5);

	my $reload = new Gtk::Button(&i18n("Reload"));
	$reload->signal_connect( "clicked", sub{ delete $sms{$type}; &list_sms($type); } );
	my $tooltip = new Gtk::Tooltips();
	$tooltip->set_tip( $reload, &i18n("Reload") . " " . &i18n("SMS") . " " . &i18n("from your Mobile Phone"), "" );
	$tooltip->enable(); 
	$footer->pack_end( $reload, 0, 0, 0 );
	$reload->show();
	$footer->show();
	
	&mainscreen (HEADER => "SMS",
				MENU => $menu,
				ICON => 'sms.xpm',
				CONTENT => $content,
				FOOTER => $footer
	);
}


sub takenumber {
	my $num = shift;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_style($styles{default});
	$dialog->set_modal(1);
	$dialog->border_width(10); 
	my $label = new Gtk::Label(&i18n("Save Number: ") . $num);
	$label->set_alignment(0,0);
	$label->set_justify('left');
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	# input box for name
	my $hbox = new Gtk::HBox();
	$label = new Gtk::Label(&i18n("Name") . ":");
	$label->set_alignment(0,0);
	$label->set_justify('left');
	$hbox->pack_start($label, 1, 1, 0);
	$label->show;
	my $nameentry = new Gtk::Entry();
	$hbox->pack_start($nameentry, 1, 1, 0);
	$nameentry->show;
	$dialog->vbox->pack_start($hbox, 1, 1, 0);
	$hbox->show;

	my $dest = "pb_SM";
	# select destination:
	$hbox = new Gtk::HBox();
	$label = new Gtk::Label(&i18n("Destination") . ":");
	$label->set_alignment(0,0);
	$label->set_justify('left');
	$hbox->pack_start($label, 1, 1, 0);
	$label->show;

	my $menu = new Gtk::OptionMenu();
	my $popup = new Gtk::Menu();
	$popup->set_title(&i18n("Select Destination"));
	my %dest = ();
	
	$dest{"pb_SM"}	= "pb_SM"		if ($phonebooks{SM} && $phonebooks{SM}->{__fetched});
	$dest{"pb_ME"}	= "pb_ME"		if ($phonebooks{ME} && $phonebooks{ME}->{__fetched});
	$dest{"ab"}		= "Addressbook" if ($phonedefs{slots}->{vcf} && $addressbook{__fetched});

	foreach my $d (sort { $dest{$b} cmp $dest{$a} } keys %dest ) {
		my $item = new Gtk::MenuItem( &i18n($dest{$d}) );
		$item->signal_connect( 'activate', sub { $dest = $d; print $dest; });
		$popup->append($item);
		$item->show();
	}
	$menu->set_menu($popup);	
	$hbox->pack_start($menu, 1, 1, 0);
	$menu->show();
	$dialog->vbox->pack_start($hbox, 0, 0, 0);
	$hbox->show;

	my $button = new Gtk::Button( &i18n("OK") );
   	$button->signal_connect( "clicked", sub { 
			if ($dest =~ /^pb_(\w+)/) {
				my $type = $1;
				my @slots = reverse sort { $a <=> $b } grep /^\d+$/, keys %{$phonebooks{$type}};
				my $slot = ($slots[0]) ? $slots[0]+1 : 1;
				$phonebooks{$type}->{$slot}->{NAME} = $nameentry->get_text();
				$phonebooks{$type}->{$slot}->{NUMBER} = $num;
				&list_phonebook('',$type);
			} elsif ($dest eq "ab") {
				my @slots = reverse sort { $a <=> $b } grep /^\d+$/, keys %addressbook;
				my $slot = $slots[0]+1;
				my $n = $nameentry->get_text();
				$addressbook{$slot} = { 
					"FN"		=> $n,
					"N"			=> $n,
					"TEL;CELL"	=> $num
				};
				&edit_address($slot,'','','',0);
			}
			$dialog->destroy(); } 
	);

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();

	my $cancel = new Gtk::Button( &i18n("Cancel") );
   	$cancel->signal_connect( "clicked", sub { $dialog->destroy(); } );
	$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
	$cancel->show();
	
	$dialog->show();
}

sub delete_sms {
	my $slot = shift;
	my $type = shift;

	return if $cmdactive;

	my $result = $scmxx->delete_sms($slot); 
	delete $sms{$type}->{$slot};
	print $result if $DEBUG;
	&list_sms($type);
}

sub save_sms_as_file {
	my $numpre = shift;
	my $num = shift;
	my $name = shift;
	my $date = shift;
	my $mess = shift;

	my $txt = "$numpre ";
	my $fn;
	if ($name) {
		$fn = $name;
		$txt .= "$name ($num)";
	} else {
		$fn = $num;
		$txt .= $num;
	}
	$txt .= "\n";
	if ($date) {
		$txt .= &i18n("Date") . ": " . $date . "\n";
	}
	$txt .= "\n" . $mess;

 	my $file_dialog = new Gtk::FileSelection(&i18n("Save SMS as text"));
	$file_dialog->set_modal(1);	

	my $dir;
	if ($opendirs{'sms'}) {
		($dir = $opendirs{'sms'}) =~ s/[^\/]+$//;
    }

	$fn =~ s/[^\w\d]+//;
	$file_dialog->set_filename( "$dir$fn" );
	$file_dialog->show_fileop_buttons(); 	

	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $dfile = $file_dialog->get_filename(); 
							$opendirs{'sms'} = $dfile;
							if (-e $dfile) {
								&check_if_file_exists($dfile);
								while ($tmpvals{overwritefile} == 0) {
									Gtk->main_iteration while (Gtk->events_pending);
									select(undef, undef, undef, 0.25);
								} 

								if ($tmpvals{overwritefile} == 1) {
									open (F, ">$dfile") || warn "Can't open $dfile: $!";
									print F $txt;
									close (F);
									$file_dialog->destroy(); 
								}
								$tmpvals{overwritefile} = 0;
							} else { 
								open (F, ">$dfile") || warn "Can't open $dfile: $!";
								print F $txt;
								close (F);
								$file_dialog->destroy(); 
							} 
						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();
}

sub sendsms_form {
	my $num = shift;
	my $name = shift || "";
	my $searchstr = shift || "";
	my $goback = shift || $tmpvals{smsgoback};
	my $type = shift || $tmpvals{smsgobacktype};
	my $mess = shift || $tmpvals{smstext};

	return if $cmdactive;
	$currentscreen = sub { &sendsms_form($num, $name, $searchstr, $goback, $type, $mess) };

	$tmpvals{smstext} = $mess;
	$tmpvals{smsgoback} = $goback;
	$tmpvals{smsgobacktype} = $type;

	my $header = &i18n("Send SMS");
	$header .= " " . &i18n("to") . " $num" if ($num);
	$header .= " ($name)"  if ($name);


	my $menu = new Gtk::HBox(0,0);
	my $number;
	if (!$num) {

		my $label = new Gtk::Label(&i18n("Number") . ": ");
		$label->set_alignment(0, 0);
		$label->set_justify('left');
		$menu->pack_start($label, 0, 0, 2);
		$label->show;
		$number = new Gtk::Entry();
#		$number->signal_connect( "activate", sub { $num = $number->get_text(); } );
		$menu->pack_start($number, 0, 0, 2);
		$number->show;

		my $gotopbook = create_pixmap_button('', sub { &list_phonebook('', '', '', '', 'coming from SMS'); }, 'phonebook_20.xpm', 'hor', 'Goto Phonebook');
		$menu->pack_start($gotopbook, 0, 0, 2);
		my $gotoabook = create_pixmap_button('', sub { &list_addressbook('', '', '', '', 'coming from SMS'); }, 'addressbook_20.xpm', 'hor', 'Goto Addressbook');
		$menu->pack_start($gotoabook, 0, 0, 2);
	}

	my $counter = new Gtk::Label(0);
#	$counter->signal_connect( "activate", sub { $num = $number->get_text(); } );
#	$counter->set_editable(0);
	$counter->set_usize( 40, 0 ); 
	$menu->pack_end($counter, 0, 0, 2);
	$counter->show;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $warn = 0;
	my $vbox = new Gtk::VBox(0, 0);
	my $smstext = new Gtk::Text( 0, 0 );

	$smstext->insert( undef, undef, undef, $mess) if ($mess); 	
	$smstext->signal_connect( "changed", 
		sub { 
				my $l = $smstext->get_length(); 
				$counter->set_text($l); 
				if ($l > 160) { 
					unless ($warn) {
						$warn = 1;
						&warndialog(&i18n('SMS text is too long (max. 160 characters).')); 
					}
					my $tmp = substr($smstext->get_chars(), 0, 160);
					$smstext->delete_text();
					$smstext->insert_text($tmp, 0);
				} else {
					$tmpvals{smstext} = $smstext->get_chars();
				}
		});
	$vbox->pack_start($smstext, 0, 0, 0);
	$smstext->set_editable( 1 );
	$smstext->show();

	my $x = new Gtk::HBox(0,10);
	my $send = new Gtk::Button(&i18n("Send SMS"));
	$x->pack_start( $send, 0, 0, 0 );
	$send->show();

	my $flashcheck = new Gtk::CheckButton(&i18n("Send as Flash-SMS")); 
	$x->pack_start( $flashcheck, 0, 0, 0 );
	$flashcheck->show();

	my $saveonphone = new Gtk::CheckButton(&i18n("Only Save on Phone")); 
	$x->pack_start( $saveonphone, 0, 0, 0 );
	$saveonphone->show();


	$send->signal_connect( "clicked", sub { my $n = $num || $number->get_text(); &sendsms($n, $name, $smstext->get_chars(), $flashcheck->active, $saveonphone->active, $goback); } );

	if ($goback) {
		my $back = new Gtk::Button(&i18n("Back"));
		if ($goback eq "address") {
			$back->signal_connect( "clicked", sub { $tmpvals{smsgoback} = ''; $tmpvals{smsgobacktype} = ''; &list_addressbook($searchstr); } );
		} elsif ($goback eq "smslist") {
			$back->signal_connect( "clicked", sub { $tmpvals{smsgoback} = ''; $tmpvals{smsgobacktype} = ''; &list_sms($type); } );
		} elsif ($goback eq "phonebook") {
			$back->signal_connect( "clicked", sub { $tmpvals{smsgoback} = ''; $tmpvals{smsgobacktype} = ''; &list_phonebook($searchstr, $type); } );
		}
		$x->pack_end( $back, 0, 0, 5 );
		$back->show();
	}

	$x->show;
	$vbox->pack_start($x, 0, 0, 5);
	
	$vbox->show();
	$content->add($vbox);
	# buttons
	my $footer = ""; 

	&mainscreen(HEADER => $header,
			ICON => 'sms.xpm',
			MENU => $menu,
			CONTENT => $content,
			FOOTER => $footer);

}

sub sendsms {
	my $num = shift;
	my $name = shift;
	my $text = shift || "";
	my $flash = shift;
	my $save = shift;
	my $goback = shift;
	
	return if $cmdactive;

	$cmdactive = 1;
	my ($ok, $result) = $scmxx->send_sms($num, $text, $flash, $save);
	$cmdactive = 0;
	$result =~ s/\x08//g;
	print "---- RESULT -----\n$result\n--------------\n" if $DEBUG;
 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_style($styles{default});
	$dialog->set_modal(1);
	$dialog->border_width(10); 
	my $label;
	if (!$ok) {
		my $txt;
		my $trans = 0;
		if ($result =~ /Sorry wrong format in number '([^']+)' \(only/) {
			my $num = $1;
			print $result;
			$txt = &i18n("Sorry wrong format in number '\$number' (only '+', '#', '*', and numbers allowed)");
			$txt =~ s/\$number/$num/;
			$trans = 1;
		}
		if ($result =~ /Please insert Number to send to!/) {
			$txt .= "\n" if ($txt);
			$txt .= &i18n("Please insert Number to send to!");
			$trans = 1;
		}
		if ($result =~ /No text given, will not send emtpy SMS!/) {
			$txt .= "\n" if ($txt);
			$txt .= &i18n("No text given, will not send emtpy SMS!");
			$trans = 1;
		}

		unless($trans) {
			$txt = $result;
		}
		$label = new Gtk::Label(&i18n("ERROR") . "\n\n" . $txt);
	} else {
		my $txt;
		if ($result =~ /The message was saved to SMS memory slot (\d+)/) {
			my $s = $1;
			$txt = &i18n("The message was saved to SMS memory slot \$slot.");
			$txt =~ s/\$slot/$s/;
		} elsif ($result =~ /The message was sent. Message referrer: (\d+)/) {
			my $s = $1;
			$txt = &i18n("The message was sent. Message referrer: \$slot.");
			$txt =~ s/\$slot/$s/;
		} else {
			$txt = $result;
		}
		$label = new Gtk::Label(&i18n("SUCCESS") . "\n\n" . $txt);
	}
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $button = new Gtk::Button( &i18n("OK") );
   	$button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();

	if ($ok == 1) {
		$tmpvals{smsgoback} = "";
		$tmpvals{smsgobacktype} = "";
		$tmpvals{smstext} = "";
		%sms = ();
	}
}


##########################################################
# PHONEBBOOK 
##########################################################

sub list_phonebook {
	my $searchstr = shift || "";
	my $type = shift || "SM";
	my $sortcol = shift || 1;
	my $sorttype = shift || 'ascending';
	my $fromsms = shift || '';
	my $listtype = shift || '';

	return if ($cmdactive);
	$currentscreen = sub { &list_phonebook($searchstr, $type, $sortcol, $sorttype, $fromsms, $listtype) };


	&reset_main_menu;

	my @sensitive = ("/" . &i18n("Phonebooks") . "/" . &i18n("Open File"));
	push @sensitive, "/" . &i18n("Phonebooks") . "/" . &i18n("Load all from Phone") if $prefs{phonetype};
	push @sensitive, "/" . &i18n("Phonebooks") . "/" . &i18n("Load from Phone") if $prefs{phonetype};
	push @sensitive, "/" . &i18n("Phonebooks") . "/" . &i18n("Remove Duplicates");

	$phonebooks{__active} = $type;
	print "Phonebook Type: $type\n" if $DEBUG;
	my $title = ("pb_$type" || $available_phonebooks{$type} ); #  . " ($type)";

	if (ref ($searchstr)) {
		$searchstr = "";
	} 

	my %phonebook;
	if ($phonebooks{$type}) {
		%phonebook = %{$phonebooks{$type}};
	} else {
		%phonebook = ();
	}

	if ($phonebook{"__type"} && $phonebook{"__type"} ne $type) {
		$searchstr = "";
	}
	%available_phonebooks = $scmxx->available_phonebooks() unless %available_phonebooks;
	if (!$prefs{phonetype} && ! keys %available_phonebooks) {
		opendir(DIR, "$ENV{HOME}/.gscmxx/pbooks");
		my @pbooks = grep { /\.pbook$/ } readdir(DIR);
		close(DIR);
		foreach (@pbooks) {
			s/\.pbook$//;
			$available_phonebooks{$_} = "$SCMxx::pbookinfos{$_} (" . &i18n("cached") . ")";
		}
	}

	my $date;
	unless ($phonebook{'__fetched'}) {
		$phonebooks{$type} = &load_phonebook_from_file($type, "$ENV{HOME}/.gscmxx/pbooks/$type.pbook");
		if ($phonebooks{$type}) {
			%phonebook = %{$phonebooks{$type}};
		}
	}
	&clean_main_box;

	my $ucsearchstr = uc($searchstr);
	my $rows;
	if ($ucsearchstr) {
		$rows = 0;
		foreach my $slot( keys %phonebook ) {
			next if $slot =~ /^__/;
			$rows++ if (uc($phonebook{$slot}->{NAME}) =~ /$ucsearchstr/);
		}
	} else {
		$rows = grep !/^__/, keys %phonebook;
	}

	push @sensitive, "/" . &i18n("Phonebooks") . "/" . &i18n("Save as File") if ($rows);

	my $menu = new Gtk::VBox(0,3);

	push @sensitive, "/" . &i18n("Phonebooks") . "/" . &i18n("Save on Phone") if ($phonebook{__editable} && $prefs{phonetype});
	

	unless ($listtype eq "Records") {
#		$title = (&i18n("pb_$type") || $available_phonebooks{$type} ) . " ($type)";
		my $menu1 = new Gtk::HBox(0,0);
		my $typemenu = new Gtk::OptionMenu();
		my $typepopup = new Gtk::Menu();
		$typepopup->set_title(&i18n("Select Phonebook"));
		my $num = 0;
		my $seltype = 0;
		my @phonebooktypes;
		@phonebooktypes = qw(SM ME FD RD CS);
#		@phonebooktypes = qw( MC MS RD FD LD DC MD SD RC CD ON OW BD BL MB) if $listtype eq "Records"; 
		foreach my $i (@phonebooktypes) {
			next unless $available_phonebooks{$i};
			# my $item = new Gtk::MenuItem( "$available_phonebooks{$i} ($i)" );
			my $item = new Gtk::MenuItem( ( &i18n("pb_$i") || $available_phonebooks{$i} ) . " ($i)" );
			$item->signal_connect( 'activate', sub { $type = $i; &list_phonebook($searchstr, $i, '', '', $fromsms); });
			$typepopup->append($item);
			$item->show();
			if ($i eq $type) {
				$seltype = $num;
			}
			$num++;
		}
		$typemenu->set_menu($typepopup);	
		$typemenu->set_history( $seltype );
		$menu1->pack_start($typemenu, 0, 0, 0);
		$typemenu->show();

		if ($prefs{phonetype}) {
			my $load = $phonebook{__fetched} ? &i18n("Reload") : &i18n("Load");
			my $button = new Gtk::Button(" $load ");
			$button->signal_connect( "clicked", sub { &load_phonebook($type, '', $listtype); } );
			my $tooltip = new Gtk::Tooltips();
			$tooltip->set_tip( $button, $load . " " . &i18n("Phonebook") . " " . &i18n("from your Mobile Phone"), "" );
			$tooltip->enable(); 
			$menu1->pack_start($button, 0, 0, 0);
			$button->show;
		}

		$menu->pack_start($menu1, 0, 0, 0);
		$menu1->show;
	}
	$menu->show;	

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $clist = new_with_titles Gtk::CList('', &i18n('Name'), &i18n('Number'));
	$clist->set_selection_mode( 'browse' ); 
	$clist->set_shadow_type( 'in' );
	$clist->set_column_width(0, 20);
	$clist->set_column_width(1, 200);

	my $menu2 = new Gtk::HBox(0,0);

	if (!$phonebook{__fetched}) {

		my $vbox = new Gtk::VBox(0,0);

		my $txt;
#		if (!$phonebook{__fetched}) {
			$txt = new Gtk::Label("\n\n" . &i18n("This Phonebook ist not available yet.") . "\n" . &i18n("Please load it from phone first!") . "\n\n");
#		} else {
#			$txt = new Gtk::Label("\n\n" . &i18n("Sorry, there are not entries in this phonebook!")  . "\n\n");
#		}
		$vbox->pack_start($txt,0,0,0);
		$txt->show;

		my $hbox = new Gtk::HBox(0,0);
		my $button = new Gtk::Button(&i18n("Load from Phone") . ": " . &i18n("Phonebook") . " ($type)" );
		$button->signal_connect( "clicked", sub { &load_phonebook($type, '', $listtype); } );
		$button->show;
		$hbox->pack_start($button,1,0,0);
		$hbox->show;
		$vbox->pack_start($hbox,0,0,0);

		$vbox->show;

		$content->add($vbox);

	} elsif ($rows == 0 && !$searchstr) {
		$clist->show;		
		$clist->signal_connect( "click_column", \&click_column_phonebook);
		$clist->signal_connect("button_press_event", \&select_row_phonebook, { type => $type, searchstr => $searchstr, fromsms => $fromsms, editable => $phonebook{__editable} } );
		$content = $clist;
	} else {

		my $sort = sub { uc($phonebook{$a}->{NAME}) cmp uc($phonebook{$b}->{NAME}) };
		my $autosort = 1;
		if ($type eq "LD" || $type eq "MD" || $type eq "MC" || $type eq "MS" || $type eq "CD") {
			$sort = sub { $a <=> $b };
			$autosort = 0;
		}
		$clist->set_auto_sort(0);
		my @slots = grep !/^__/, keys %phonebook;
		my $i = 0;
		foreach my $slot(sort $sort @slots) {
			next unless ($phonebook{$slot}->{NAME} || $phonebook{$slot}->{NUMBER});
			if ($ucsearchstr) {
				next unless (uc($phonebook{$slot}->{NAME}) =~ /$ucsearchstr/);
			}
			my $group = $phonebook{$slot}->{GROUP} || "";
			my $row = $clist->append($group, $phonebook{$slot}->{NAME} || "", $phonebook{$slot}->{NUMBER} || "");
			&set_row_group_icon($clist, $i, $group);
			$clist->set_row_data ($row, \$slot);
			$i++;
		}
		$clist->set_compare_func( \&list_compare_function );
		$clist->show;
		if ($autosort) {
			$clist->signal_connect( "click_column", \&click_column_phonebook);
		}
		$clist->signal_connect("button_press_event", \&select_row_phonebook, { type => $type, searchstr => $searchstr, fromsms => $fromsms, editable => $phonebook{__editable} } );

		$content = $clist;

#		my $menu2 = new Gtk::HBox(0,0);

		if ($rows || $searchstr) {
				my $search = new Gtk::Entry();
				$search->set_text($searchstr || "");
				$search->signal_connect( "activate", sub { &list_phonebook($search->get_text(), $type, $sortcol, $sorttype, $fromsms); } );
				$menu2->pack_start($search, 0, 0, 2);
				$search->show;

				my $button = new Gtk::Button(&i18n("Search"));
				$button->signal_connect( "clicked", sub { &list_phonebook($search->get_text(), $type, $sortcol, $sorttype, $fromsms); } );
				$menu2->pack_start($button, 0, 0, 2);
				$button->show;

				$button = new Gtk::Button(&i18n("Show all"));
				$button->signal_connect( "clicked", sub { &list_phonebook('', $type, $sortcol, $sorttype, $fromsms); });
				$menu2->pack_start($button, 0, 0, 2);
				$button->show if ($searchstr);
		}

	}
		if ($prefs{phonetype} && $listtype eq "Records") {
			my $load = $phonebook{__fetched} ? &i18n("Reload") : &i18n("Load");
			my $button = new Gtk::Button(" $load ");
			$button->signal_connect( "clicked", sub { &load_phonebook($type, '', $listtype); } );
			my $tooltip = new Gtk::Tooltips();
			$tooltip->set_tip( $button, $load . " " . &i18n("Phonebook") . " " . &i18n("from your Mobile Phone"), "" );
			$tooltip->enable(); 
			$menu2->pack_end($button, 0, 0, 0);
			$button->show;
		}

		if ($phonebook{__editable}) {
			my $button = new Gtk::Button(&i18n("New item"));
			$button->signal_connect( "clicked", sub { &new_phonebook_entry($clist, $searchstr, $type); });
			$menu2->pack_end($button, 0, 0, 2);
			$button->show;
		}

		$menu2->show;

		$menu->pack_start($menu2, 0, 0, 0);

#	}


	my $footer = new Gtk::HBox(0,5);

	if ($phonebook{__cachedate}) {
		my $ebox = new Gtk::EventBox();
		my $txt = "Cached Phonebook from " . $phonebook{__cachedate};
		my $label = new Gtk::Label($txt);
		$ebox->add($label);
		$label->show();
		my $tooltip = new Gtk::Tooltips();
		$tooltip->set_tip( $ebox, &i18n("Use the 'Reload'-Button to get the latest version from your phone"), "" );
		$tooltip->enable(); 
		$footer->pack_end($ebox, 0, 0, 0);
		$ebox->show;
	}
	$footer->show();

	&show_main_menu_items(@sensitive);
	
	&mainscreen(HEADER => $title,
			ICON => "phonebook.xpm",
			MENU => $menu,
			CONTENT => $content,
			FOOTER => $footer);
}

#TODO
sub sort_phonebook_by_group {
	my ($clist, $col, $stype) = @_;

	my $type = $phonebooks{__active};
	my $rows = $clist->rows;
	my @tmp;
	foreach (0..$rows-1) {
		my $data = $clist->get_row_data($_);
		push @tmp, $$data;
	}

	my $sort;
	if ($stype eq 'descending') {
		$sort =  sub { 
			$phonebooks{$type}->{$b}->{GROUP} cmp $phonebooks{$type}->{$a}->{GROUP} || 
			$phonebooks{$type}->{$a}->{NAME} cmp $phonebooks{$type}->{$b}->{NAME}
		}; 
	} else {
		$sort =  sub { 
			$phonebooks{$type}->{$a}->{GROUP} cmp $phonebooks{$type}->{$b}->{GROUP} || 
			$phonebooks{$type}->{$a}->{NAME} cmp $phonebooks{$type}->{$b}->{NAME}
		}; 
	}
	my $i = 0;
	foreach (sort $sort @tmp) {
		$clist->set_text($i, 1, $phonebooks{$type}->{$_}->{NAME});
		$clist->set_text($i, 2, $phonebooks{$type}->{$_}->{NUMBER});
		$clist->set_row_data($i, \$_);
		&set_row_group_icon($clist, $i, $phonebooks{$type}->{$_}->{GROUP});
		$i++;
	}
}

sub set_row_group_icon {
	my $clist = shift;
	my $row = shift;
	my $group = shift || "";

	my $file;
	if ($group) {
		if ($group eq "!") {
			$file = &findpixmap("groups/vip.xpm");
		} elsif ($group eq "") {
			$file = &findpixmap("groups/family.xpm");
		} elsif ($group eq "") {
			$file = &findpixmap("groups/office.xpm");
		} elsif ($group eq "") {
			$file = &findpixmap("groups/leisure.xpm");
		}
	} 
	if ($file && -e $file) {
   		my ($p,$m) = Gtk::Gdk::Pixmap->create_from_xpm($widgets->{window}->window,$widgets->{window}->style->bg('normal'),$file);
		if ($p && $m) {
			$clist->set_pixmap( $row, 0, $p, $m ); 
		}
	} else {
		$clist->set_text($row, 0, $group);
	}
}

sub select_row_phonebook {
	my ( $clist, $data, $event ) = @_;

	my $x = $event->{"x"};
	my $y = $event->{"y"};
	my ($r, $c) = $clist->get_selection_info($x, $y);
	
	return 1 unless defined $r;

	my $rowdata = $clist->get_row_data($r);
	my $s = ${$rowdata}; # slot

	return 1 unless defined $s;
    $clist->select_row($r, $c);

	if ($event->{type} eq "2button_press" && $event->{button} == 1) {
		if ($data->{fromsms}) {
			&sendsms_form($phonebooks{$data->{type}}->{$s}->{NUMBER}, $phonebooks{$data->{type}}->{$s}->{NAME}, '', '', '', '');
		} else {
			print "Edit Phonebook Entry Slot: $s\n" if $DEBUG;
			&edit_phonebook_entry($clist, $data->{type}, $r, $s) if $data->{editable};
		}
	} else {
		if ($event->{button} == 1) {
			# left button pressed
			print "Left button pressed: Row: $r Slot: $s\n" if $DEBUG > 1;
		}
		if ($event->{button} == 2 || $event->{button} == 3 ) {
			# right or middle button pressed
			print "Right or middle button pressed: Row: $r Slot: $s\n" if $DEBUG > 1;

			&show_phonebook_list_menu($clist, $data->{type}, $s, $r, $event->{'x_root'}, $event->{'y_root'}, $data->{searchstr});
		}
	}
	return 1;
}


sub edit_phonebook_entry {
	my $clist = shift;
	my $type = shift || $phonebooks{__active};
	my $row  = shift;
	my $slot = shift;
	my $new = shift;

	return unless defined $row;


	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->border_width(10); 


	my $txt = new Gtk::Label(&i18n("Edit Phonebook Item") . " (Slot $slot)");
	$dialog->vbox->pack_start($txt, 0, 0, 2);
	$txt->show;

	my $err = new Gtk::Label();
	$err->set_line_wrap(1);
	$dialog->vbox->pack_start($err, 0, 0, 2);
	$err->show;

	my $table = new Gtk::Table(3, 2, 0);


	my $label = new Gtk::Label(&i18n("Name") . ": ");
	$label->set_alignment(0,0);
	$table->attach($label, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0);
	$label->show;

	my $name = new Gtk::Entry(14);
	$name->set_text($phonebooks{$type}->{$slot}->{NAME});
	$table->attach($name, 1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0);
	$name->show;

	$label = new Gtk::Label(&i18n("Number") . ":   ");
	$label->set_alignment(0,0);
	$table->attach($label, 0, 1, 1, 2, ['expand','fill'], 'shrink', 0, 0);
	$label->show;

	my $number = new Gtk::Entry();
	$number->set_text($phonebooks{$type}->{$slot}->{NUMBER});
	$table->attach($number, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0);
	$number->show;

	$label = new Gtk::Label(&i18n("Group") . ": ");
	$label->set_alignment(0,0);
	$table->attach($label, 0, 1, 2, 3, ['expand','fill'], 'shrink', 0, 0);
	$label->show;

    my $num = 0;
    my $selgroup = 0;

	my $groupmenu = new Gtk::OptionMenu();
	my $grouppopup = new Gtk::Menu();
	$grouppopup->set_title("Group");

    foreach my $gr (sort keys %groups) {
        my $item = new Gtk::MenuItem( &i18n($groups{$gr}) );
        $item->signal_connect( 'activate', sub { $phonebooks{$type}->{$slot}->{GROUP} = $gr });
        $grouppopup->append($item);
        $item->show();
        if ($phonebooks{$type}->{$slot}->{GROUP} && $gr eq $phonebooks{$type}->{$slot}->{GROUP} ) {
            $selgroup = $num;
        }
        $num++;
    }
    $groupmenu->set_menu($grouppopup);
    $groupmenu->set_history( $selgroup );
    $table->attach( $groupmenu, 1, 2, 2, 3, ['fill','shrink'], 'shrink', 0, 0);
    $groupmenu->show();

	$dialog->vbox->pack_start($table, 0, 0, 2);
	$table->show;

	my $hbut = new Gtk::HButtonBox();

	my $ok = new Gtk::Button(&i18n("Save"));
	$ok->signal_connect( "clicked", sub {
			my ($num, $errtxt) = SCMxx::__control_number($number->get_text());
			if ($errtxt) {
				$err->set_text($errtxt);
			} else {
				$phonebooks{$type}->{$slot}->{NAME} = $name->get_text(); 
				$phonebooks{$type}->{$slot}->{NUMBER} = $num;
				$clist->set_text( $row, 1, $phonebooks{$type}->{$slot}->{NAME} ); 	
				$phonebooks{$type}->{__changed} = 1;
				$clist->set_text( $row, 2, $phonebooks{$type}->{$slot}->{NUMBER} ); 	
				&set_row_group_icon($clist, $row, $phonebooks{$type}->{$slot}->{GROUP});
				$clist->set_row_data ($row, \$slot);
				$dialog->destroy(); 
				# sort list!!
				$clist->set_sort_type("ascending") unless $clist->sort_type() eq "descending";
				$clist->set_sort_column(1) unless $clist->sort_column();
				$clist->sort;
			}
		} 
	);
	$hbut->add($ok);
	$ok->show;

	my $cancel = new Gtk::Button(&i18n("Cancel"));
	$cancel->signal_connect( "clicked", sub { 
			$clist->remove(0) if $new;
			$dialog->destroy(); 
		} 
	);
	$hbut->add($cancel);
	$cancel->show;


	$dialog->action_area->pack_start($hbut, 0, 0, 2);
	$hbut->show;

	$dialog->show;

}

sub show_phonebook_list_menu {
	my ($clist, $type, $slot, $row, $x, $y, $searchstr) = @_;

	my @items;
		
#		{ label => "Delete item", callback => sub { delete $phonebooks{$type}->{$slot}; $clist->remove($row) }, active => 1 };
	if ($phonebooks{$type}->{__editable}) {
		push @items, { label => "Edit item", callback => sub { &edit_phonebook_entry($clist, $type, $row, $slot); }, active => 1 },
		{ label => "Delete item", callback => sub { delete_phonebook_item($type, $slot, $clist, $row); }, active => 1 };
	} else {
		push @items, { label => "Edit item", active => 0 },
		{ label => "Delete item", active => 0 };
	}

	my $num = $clist->get_text($row, 2);
	if ($num) {
		my $name = $clist->get_text($row,1);
		push @items, { label => "Send SMS", callback => sub { &sendsms_form($num, $name, $searchstr, 'phonebook', $type, ''); }, active => 1 };
	} else {
		push @items, { label => "Send SMS", active => 0 };
	}

	if (@items) {
		&popup_menu(\@items, $x, $y);
	}
}

sub click_column_phonebook {
	my ($clist, $col) = @_;

	my $stype = $clist->sort_type;
	my $scol = $clist->sort_column;
	if ($scol == $col) {
		if ($stype eq "ascending") {
			$clist->set_sort_type('descending');
			$stype = 'descending';
		} else {
			$clist->set_sort_type('ascending');
			$stype = 'ascending';
		}
	} else {
		$clist->set_sort_type('ascending');
		$stype = 'ascending';
	}

	$clist->set_sort_column($col);
	if ($col == 0) {
		&sort_phonebook_by_group($clist, $col, $stype);
	} else {
		$clist->sort;
	}
}


sub list_compare_function { 
	$_[1] = 1 unless defined $_[1];
	$_[2] = 1 unless defined $_[2];
#	my $scol = $_[0]->sort_column;
	# sort by group
#	if ($scol == 0) {
#		return 1 <=> 0;
#	}
#	else {
		if ($_[1] =~ /^[\+\d\s]+$/ && $_[2] =~ /^[\+\d\s]+$/) {
			$_[1] =~ s/\D//g;
			$_[2] =~ s/\D//g;
			return $_[1] cmp $_[2];
		} else {
			$_[1] ||= "ZZZZZZ";
			$_[2] ||= "ZZZZZZ";
			return uc($_[1]) cmp uc($_[2]); 
		}
#	}
} 

sub load_phonebook {
	my $type = shift || $phonebooks{__active};
	my $dontshow = shift;
	my $listtype = shift || "";
	my $phonebook;

	return if $cmdactive;

    my $title = ("pb_$type" || $available_phonebooks{$type} ); # . " ($type)";

	&waitscreen($title, 'phonebook.xpm');
	print "Fetching Phonebook $type ...\n" if $DEBUG;
	$cmdactive = 1;
	%available_phonebooks = $scmxx->available_phonebooks() unless %available_phonebooks;
	$phonebook = $scmxx->get_phonebook($type, 'HASH', $prefs{pbtimeout});
	$cmdactive = 0;

	if ($phonebook =~ /^ERROR ACCESSING MOBILE PHONE!/) {
		&errorscreen(&i18n("Phonebooks") . " ($type)", $phonebook);
		return;
	} else {
		my %phonebook = %{$phonebook};
		foreach (keys %phonebook) {
			next if /^__/;
			delete $phonebook{$_} unless $phonebook{$_}->{NUMBER} || $phonebook{$_}->{NAME};
		}
		$phonebook{"__fetched"} = 1;
		$phonebook{"__type"} = $type;
		$phonebook{"__editable"} = 1 if ($phonebook{__fetched} && ($type eq "SM" || $type eq "ME" || $type eq "FD" ) );
		$phonebooks{$type} = \%phonebook;
		print "Done ...\n" if $DEBUG;
		&do_save_phonebook_as_file("$ENV{HOME}/.gscmxx/pbooks/$type.pbook", '', $type);
		&list_phonebook('', $type, 0, '', '', $listtype) unless $dontshow;
	}

}

sub load_all_phonebooks {
	my $type = shift || "";
	$type = "" if (ref($type));
	return if $cmdactive;
	my %available = $scmxx->available_phonebooks;
	foreach (keys %available) {
		&load_phonebook($_, 1);
	}
	&list_phonebook('',$type);
}
sub load_phonebook_from_file_dialog {
	my $type = shift || $phonebooks{__active};
 	my $file_dialog = new Gtk::FileSelection(&i18n("Phonebook") . ": " . &i18n("Load from File"));
	$file_dialog->set_modal(1);	
	if ($opendirs{'phonebook'}) {
		$file_dialog->set_filename($opendirs{'phonebook'});
 	} 
	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $file = $file_dialog->get_filename(); 
							$opendirs{'phonebook'} = $file;
							$phonebooks{$type} = &load_phonebook_from_file($type,$file);
							$file_dialog->destroy(); 
							&list_phonebook('', $type);
						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();
}

sub load_phonebook_from_file {
	my $type = shift;
	my $file = shift;

	print "Loading $type from $file\n" if $DEBUG;
	return 0 unless -e $file;

	my @stat = stat($file);
	my $date = localtime($stat[9]);

	open (PBOOK, "$file") || warn "Can't open $file $!";
	my @tmp = (<PBOOK>);
	close (PBOOK);

	my $phonebook = $scmxx->create_phonebook_from_data(join("\n", @tmp), "HASH");
	foreach (keys %{$phonebook}) {
		next if /^__/;
		delete $phonebook->{$_} unless $phonebook->{$_}->{NUMBER} || $phonebook->{$_}->{NAME};
	}
	$phonebook->{__fetched} = 1;
	$phonebook->{__type} = $type;
	$phonebook->{__cachedate} = $date;
	$phonebook->{__editable} = 1 if ($type eq "SM" || $type eq "ME" || $type eq "FD");
	return $phonebook;
}

### TODO !!! ###
sub new_phonebook_entry {
	my $clist = shift;
	my $searchstr = shift;
	my $type = shift;
	my @slots = reverse sort { $a <=> $b } grep /^\d+$/, keys %{$phonebooks{$type}};
	my $slot = ($slots[0]) ? $slots[0]+1 : 1;
	$phonebooks{$type}->{$slot}->{NAME} = "";
	$phonebooks{$type}->{$slot}->{NUMBER} = "";
#	&list_phonebook('',$type); # $searchstr);
	$clist->insert(0, '', '');
	$clist->select_row(0,0);
	&edit_phonebook_entry($clist, $type, 0, $slot, 'new');
}

sub delete_phonebook_item {
	my $type = shift;
	my $slot = shift;
	my $clist = shift;
	my $row = shift;


	my $item = $phonebooks{$type}->{$slot};

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 

	my $txt = &i18n("Do you really want to delete this item?");

	my $label = new Gtk::Label($txt);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $i = 0;
	my $table = new Gtk::Table( 3, 2, 0);	

	my $k = new Gtk::Label(&i18n("Name") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
	$k->show;

   	my $v = new Gtk::Label($item->{NAME} || "");
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, 0, 1, 'fill', 'shrink',0 ,0);
	$v->show;

	$k = new Gtk::Label(&i18n("Number") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
	$k->show;

   	$v = new Gtk::Label($item->{NUMBER} || "");
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, 1, 2, 'fill', 'shrink',0 ,0);
	$v->show;

	$k = new Gtk::Label(&i18n("Group") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
	$k->show;

   	$v = new Gtk::Label(&i18n($groups{$item->{GROUP} || ""} || ""));
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, 2, 3, 'fill', 'shrink',0 ,0);
	$v->show;
	

	$dialog->vbox->pack_start( $table, 1, 1, 10 );
	$table->show();

	my $cancel = new Gtk::Button(&i18n("Cancel"));
   	$cancel->signal_connect( "clicked", sub { $dialog->destroy(); } );
	$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
	$cancel->show();

	my $ok = new Gtk::Button(&i18n("OK"));
	$ok->has_focus(1);
   	$ok->signal_connect( "clicked", sub {  
		delete $phonebooks{$type}->{$slot}; 
		$phonebooks{$type}->{__changed} = 1;
		$clist->remove($row);
		$dialog->destroy();
	} );
	$dialog->action_area->pack_start( $ok, 1, 1, 0 );
	$ok->show();

	$dialog->show();
}

sub save_phonebook_as_file {
	my $searchstr = shift || "";
	my $type = shift || $phonebooks{__active};

	$searchstr = "" if ref($searchstr);

 	my $file_dialog = new Gtk::FileSelection(&i18n("Phonebook") . ": " . &i18n("Save as File"));
	my $dir = "";
    if ($opendirs{'phonebook_save'}) {
        ($dir = $opendirs{'phonebook_save'}) =~ s/[^\/]+$//;
    }
	$file_dialog->set_filename($dir. "Phonebook_" . $type . ".csv");
	$file_dialog->set_modal(1);	
	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $file = $file_dialog->get_filename(); 
							$opendirs{'phonebook_save'} = $file;
							if (-e $file) {
								&check_if_file_exists($file);
								while ($tmpvals{overwritefile} == 0) {
									Gtk->main_iteration while (Gtk->events_pending);
									select(undef, undef, undef, 0.25);
								}
								if ($tmpvals{overwritefile} == 1) {
									&do_save_phonebook_as_file($file,$searchstr, $type);
									$file_dialog->destroy();
								}
								$tmpvals{overwritefile} = 0;
							} else {
								&do_save_phonebook_as_file($file,$searchstr, $type);
								$file_dialog->destroy();
							}

						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();

}

sub do_save_phonebook_as_file {
	my $file = shift;
	my $searchstr = shift;
	my $type = shift;
	print "Saving Phonebook $type to $file " if $DEBUG;

	return unless $file;
	my ($status, $pbook) = $scmxx->generate_phonebook($phonebooks{$type});
	print "Status: $status\n" if $DEBUG;
	if ($searchstr) {
		my $ucsearchstr = uc($searchstr);
		my @tmp = split (/\n/, $pbook);
		$pbook = "";
		foreach (@tmp) {
			$pbook .= $_ . "\n" if (uc($_) =~ /$ucsearchstr/);	
		}
	}
	$pbook ||= "";
	open (PBOOK, ">$file") || die "Can't write $file $!";
	print PBOOK $pbook;
	close (PBOOK);
}

sub show_pin2_dialog {
	my $error = shift;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 


	my $txt = new Gtk::Label(&i18n("Please enter PIN2"));
	$dialog->vbox->pack_start($txt, 0, 0, 2);
	$txt->show;

	if ($error) {
		my $errtxt = new Gtk::Label($error);
		$dialog->vbox->pack_start($errtxt, 0, 0, 2);
		$errtxt->show;
	}

	my $pin = new Gtk::Entry();
	$dialog->vbox->pack_start($pin, 0, 0, 2);
	$pin->show;

	my $ok = new Gtk::Button(&i18n("OK"));
	$ok->signal_connect( "clicked", sub { $pin2 = $pin->get_text(); $dialog->destroy(); } );
	$dialog->vbox->pack_start($ok, 0, 0, 2);
	$ok->show;

	$dialog->show;
}

sub save_phonebook {
	my $type = shift || $phonebooks{__active};
	return if $cmdactive;

	$pin2 = "";
	if ($type eq "FD") {
		my $shown = 1;
		&show_pin2_dialog;
		while ($shown) {
			if ($pin2) {
				if ($pin2 =~ /^\d+$/) {
					$shown = 0;
				} else {
					$pin2 = "";
					&show_pin2_dialog(&i18n("Only numbers allowed!"));
				}
			} 
			print "." if $DEBUG;
			Gtk->main_iteration while (Gtk->events_pending);
#			sleep(1);
		}	
	}

	&waitscreen(&i18n("Phonebook") . " ($type)", 'phonebook.xpm', 'save');

	$cmdactive = 1;
	my $result = $scmxx->save_phonebook($type, $phonebooks{$type}, $pin2);
	$cmdactive = 0;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 
	$dialog->set_modal(1);

	chomp $result;
	$result =~ s/^\s+//;
	$result =~ s/\s+$//;
	print "+++ $result +++" if $DEBUG;
	my $dialogtxt;
	if ($result =~ /^\d+$/) {
		# $dialogtxt = "$result " . &i18n("Phonebook entries have been saved!");
		$dialogtxt = &i18n("Phonebook entries have been saved!");
		delete $phonebooks{$type}->{__cachedate};
	} else {
		$dialogtxt = &i18n("ERROR") . "\n$result";
	}
	my $label = new Gtk::Label($dialogtxt);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $button = new Gtk::Button(&i18n("OK"));
    $button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();

	&do_save_phonebook_as_file("$ENV{HOME}/.gscmxx/pbooks/$type.pbook", '', $type);

	&list_phonebook('', $type);
}


sub uniq_phonebook {
	my $type = shift || $phonebooks{__active};
	return if $cmdactive;
	my %pb = %{$phonebooks{$type}};
	my %uniq = map { uc( ($pb{$_}->{NAME} || "") . ":" . ($pb{$_}->{NUMBER} || "") . ":" . ($pb{$_}->{GROUP} || "") ) => $_ } grep !/^__/, keys %pb;

	my $old = grep !/^__/, keys %pb;
	my $cnt = keys %uniq;
	my $removed = $old - $cnt;

	my $title = "";
	my $clist;
	if ($removed == 0) {
		$title = &i18n("There are no duplicate items!");
	} else {
		my %old = %pb;
		foreach (values %uniq) {
			delete $old{$_};
		}
		if ($removed == 1) {
			$title = &i18n("1 item has been removed.");
		} else {
			$title = &i18n("\$cnt items have been removed.");
			$title =~ s/\$cnt/$removed/;
		}
		$clist = new_with_titles Gtk::CList('', &i18n('Name'), &i18n('Number'));
		$clist->set_selection_mode( 'browse' ); 
		$clist->set_shadow_type( 'in' );
		$clist->set_column_width(0, 20);
		$clist->set_column_width(1, 150);
		$clist->set_column_width(2, 150);

		my $i = 0;
		foreach (keys %old) {
			next if ($_ =~ /^__/);
			my $group = $old{$_}->{GROUP} || "";
			my $row = $clist->append($group, $old{$_}->{NAME} || "", $old{$_}->{NUMBER} || "");
			&set_row_group_icon($clist, $i, $group);
			$i++;
		}
	}

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 

	my $label = new Gtk::Label($title);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	if ($clist) {
		$clist->show;
		$dialog->vbox->pack_start( $clist, 1, 1, 10 );
	}

	my $button = new Gtk::Button( "OK" );
   	$button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();

	my %new;
	foreach (grep /^__/, keys %pb) {
		$new{$_} = $pb{$_};
	}
	foreach (keys %uniq) {
		$new{$uniq{$_}} = $pb{$uniq{$_}};
	}
	$phonebooks{$type} = \%new;
	$phonebooks{$type}->{__changed} = 1;
	&list_phonebook('', $type);
}
##################################################
# ADDRESSBOOK
##################################################

sub list_addressbook {

	my $searchstr = shift || "";
	my $sortcol = shift || 1;
	my $sorttype = shift || "ascending";
	my $row = shift || 0;
	my $fromsms = shift;

	return if ($cmdactive);
	$currentscreen = sub { &list_addressbook($searchstr, $sortcol, $sorttype, $row, $fromsms); };

	if (ref ($searchstr)) {
		$searchstr = "";
	}

	&reset_main_menu;
	my @sensitive;
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Save on Phone") if ($prefs{phonetype} && $phonedefs{slots}->{vcf});
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Load from Phone") if ($prefs{phonetype} && $phonedefs{slots}->{vcf});
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Import File") . " (" . &i18n("append items") . ")";
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Restore from File") . " (" . &i18n("overwrite items") . ")";
 

	&clean_main_box;

	my $header = "Addressbook";
	my $menu;
	my $footer;

	unless ($addressbook{'__fetched'}) {
		%addressbook = ();
		%addressbook = &load_addressbook_from_file("$ENV{HOME}/.gscmxx/addressbook.cache");
	}

	$menu = new Gtk::HBox(0,0);
	my $content;


	my @slots = grep !/^\_\_/, keys %addressbook;

	if (!$addressbook{'__fetched'}) {
		$content = new Gtk::EventBox();
		$content->set_style($styles{default});
		my $vbox = new Gtk::VBox(0,0);

		my $txt = new Gtk::Label("\n\n" . &i18n("Addressbook is not available.") . ". " . &i18n("Please load it from phone first!") . "\n\n");
		$vbox->pack_start($txt,0,0,0);
		$txt->show;

		my $hbox = new Gtk::HBox(0,0);
		my $button = new Gtk::Button(&i18n("Load from Phone") . ": " . &i18n("Addressbook"));
		$button->signal_connect( "clicked", \&load_addressbook );
		$button->show;
		$hbox->pack_start($button,1,0,0);
		$hbox->show;
		$vbox->pack_start($hbox,0,0,0);

		$vbox->show;

		$content->add($vbox);

		$footer = "";
	} else {
		push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Save as File");

		my $search = new Gtk::Entry();
		$search->set_text($searchstr || "");
		$search->signal_connect( "activate", sub { &list_addressbook($search->get_text(), $sortcol, $sorttype, 0, $fromsms); } );
		$menu->pack_start($search, 0, 0, 2);
		$search->show;

		my $button = new Gtk::Button(&i18n("Search"));
		$button->signal_connect( "clicked", sub { &list_addressbook($search->get_text(), $sortcol, $sorttype, 0, $fromsms); } );
		$menu->pack_start($button, 0, 0, 2);
		$button->show;

		$button = new Gtk::Button(&i18n("Show all"));
		$button->signal_connect( "clicked", sub { &list_addressbook('', $sortcol, $sorttype, 0, $fromsms); } );
		$menu->pack_start($button, 0, 0, 2);
		$button->show if ($searchstr);


		$button = new Gtk::Button(&i18n("New item"));
		$button->signal_connect( "clicked", sub { &edit_address(undef, $searchstr,$sortcol, $sorttype, 0); });
		$menu->pack_end($button, 0, 0, 2);
		$button->show;
		$menu->show;

		my $ucsearchstr = uc($searchstr);
		my $clist = new_with_titles Gtk::CList('', &i18n('Lastname'), &i18n('Firstname'), &i18n("Tel, Home"), &i18n("Tel, Mobile"), &i18n("Tel, Work"));
		$clist->set_selection_mode( 'browse' ); 
		$clist->set_shadow_type( 'in' );
		$clist->set_column_width(0, 20);
		$clist->set_column_width(1, 100);

		my $i = 0;
		foreach my $slot(@slots) {
			next if ($slot =~ /^\_\_/);
			if ($ucsearchstr) {
				next unless (uc($addressbook{$slot}->{FN}) =~ /$ucsearchstr/);
			}
#			print "$slot => $addressbook{$slot}->{FN}\n";
			my $r = $clist->append(
					'',
					$addressbook{$slot}->{"N"} || "",
					$addressbook{$slot}->{"SN"} || "",
					$addressbook{$slot}->{"TEL;HOME"} || "",
					$addressbook{$slot}->{"TEL;CELL"} || "",
					$addressbook{$slot}->{"TEL;WORK"} || "",
			);
			$addressbook{$slot}->{CATEGORIES} ||= "";
			my $group = "!" if ($addressbook{$slot}->{CATEGORIES} eq "VIP");
			&set_row_group_icon($clist, $i, $group);
			$clist->set_row_data ($r, \$slot);
			$i++;
		}
		
		$clist->set_sort_column($sortcol);
		$clist->set_sort_type($sorttype);
		$clist->set_compare_func( \&list_compare_function );
#		$clist->set_compare_func(sub { return uc($_[1]) cmp uc($_[2]); } );
		$clist->sort();

		# sort on clumn header click
		$clist->signal_connect( "click_column", \&click_column_addressbook);
		# select on click, popup menu on right click
		$clist->signal_connect("button_press_event", \&select_row_addressbook, { searchstr => $searchstr, fromsms => $fromsms } );
		my $w = 170;
		foreach (1..5) {
			$clist->set_column_auto_resize($_, 1);
			$clist->set_column_resizeable($_, 1);
			$w += $clist->optimal_column_width($_) + 5
		}
#		$widgets->{window}->set_default_size($w,0);
#		print "Autosize nachher: " . $clist->columns_autosize() . "\n";
		$clist->columns_autosize();
		$clist->select_row($row,0);
#		$clist->set_focus_row($row);
#		print "Should move to ROW: $row\n";
		$clist->moveto($row, 0, 0, 0);
		$clist->show();

		$content = $clist;
	}
	$content->show;		

	if ($addressbook{__cachedate}) {
		$footer = new Gtk::HBox(0,5);
		my $ebox = new Gtk::EventBox();
		my $txt = "Cached Addressbook from " . $addressbook{__cachedate};
		my $label = new Gtk::Label($txt);
		$ebox->add($label);
		$label->show();
		my $tooltip = new Gtk::Tooltips();
		$tooltip->set_tip( $ebox, &i18n("Use the 'Reload'-Button to get the latest version from your phone"), "" );
		$tooltip->enable(); 
		$footer->pack_end($ebox, 0, 0, 0);
		$ebox->show;
	}

	&show_main_menu_items(@sensitive);

	&mainscreen(HEADER => $header,
			MENU	=> $menu,
			ICON	=> 'addressbook.xpm',
			CONTENT => $content,
			FOOTER	=> $footer);

#	($widgets->{content}->children)[0]->moveto($row, 0, 0, 0);
#	my $w =  ($widgets->{content}->children)[0];
#	print $w;
	#($widgets->{content}->children)[0]->draw_focus();
#	$widgets->{content}->draw_focus();
#	$widgets->{content}->draw_focus();
}

sub click_column_addressbook {
	my ($clist, $col) = @_;

	my $stype = $clist->sort_type;
	my $scol = $clist->sort_column;
	if ($scol == $col) {
		if ($stype eq "ascending") {
			$clist->set_sort_type('descending');
			$stype = "descending";
		} else {
			$clist->set_sort_type('ascending');
			$stype = "ascending";
		}
	} else {
		$clist->set_sort_type('ascending');
		$stype = "ascending";
	}

	$clist->set_sort_column($col);
	if ($col == 0) {
		&sort_addressbook_by_group($clist, $col, $stype);
	} else {
		$clist->sort;
	}
}

sub sort_addressbook_by_group {
	my ($clist, $col, $stype) = @_;

	my $rows = $clist->rows;
	my @tmp;
	foreach (0..$rows-1) {
		my $data = $clist->get_row_data($_);
		push @tmp, $$data;
	}

	my $sort;
	if ($stype eq 'ascending') {
		$sort =  sub { 
			$addressbook{$b}->{CATEGORIES} cmp $addressbook{$a}->{CATEGORIES} || 
			$addressbook{$a}->{N} cmp $addressbook{$b}->{N} 
		}; 
	} else {
		$sort =  sub { 
			$addressbook{$a}->{CATEGORIES} cmp $addressbook{$b}->{CATEGORIES} || 
			$addressbook{$a}->{N} cmp $addressbook{$b}->{N}
		}
	}
	my $i = 0;
	foreach (sort $sort @tmp) {
		$clist->set_text($i, 1, $addressbook{$_}->{N} || "");
		$clist->set_text($i, 2, $addressbook{$_}->{SN} || "");
		$clist->set_text($i, 3, $addressbook{$_}->{"TEL;HOME"} || "");
		$clist->set_text($i, 4, $addressbook{$_}->{"TEL;CELL"} || "");
		$clist->set_text($i, 5, $addressbook{$_}->{"TEL;WORK"} || "");

		$clist->set_row_data($i, \$_);
	
		my $group = "";	
		$group = "!" if ($addressbook{$_}->{CATEGORIES} && $addressbook{$_}->{CATEGORIES} eq "VIP");
		&set_row_group_icon($clist, $i, $group);
		$i++;
	}
}


sub select_row_addressbook {
	my ( $clist, $data, $event ) = @_;

	my $x = $event->{"x"};
	my $y = $event->{"y"};
	my ($r, $c) = $clist->get_selection_info($x, $y);

	my $rowdata = $clist->get_row_data($r);
	my $s = ${$rowdata}; # slot

    $clist->select_row($r, $c);

	if ($event->{type} eq "2button_press" && $event->{button} == 1) {
		if ($data->{fromsms}) {
			if ($addressbook{$s}->{"TEL;CELL"}) {
				&sendsms_form($addressbook{$s}->{"TEL;CELL"}, $addressbook{$s}->{FN}, '', '', '', '');
			}
		} else {
			print "Edit Addressbook Entry; Row: $r Slot: $s\n" if $DEBUG;
			&edit_address($s, $data->{searchstr}, $clist->sort_column, $clist->sort_type, $r);
		}
	} else {
		if ($event->{button} == 1) {
			# left button pressed
			print "Left button pressed: Row: $r Slot: $s\n" if $DEBUG;
		}
		if ($event->{button} == 2 || $event->{button} == 3 ) {
			# right or middle button pressed
			print "Right or middle button pressed: Row: $r Slot: $s\n" if $DEBUG;

			&show_addressbook_list_menu($clist, $data->{type}, $s, $r, $event->{'x_root'}, $event->{'y_root'}, $data->{searchstr});
		}
	}
	return 1;
}

sub show_addressbook_list_menu {
	my ($clist, $type, $slot, $row, $x, $y, $searchstr) = @_;

	my @items;
		
	push @items, { label => "Edit item", callback => sub { &edit_address($slot, $searchstr, $clist->sort_column, $clist->sort_type, $row); }, active => 1 },
		{ label => "Delete item", callback => sub { &delete_address($slot, $clist, $row); }, active => 1 };

	my $num = $clist->get_text($row, 4);
	if ($num) {
		my $name = $clist->get_text($row,2) . " " . $clist->get_text($row,1);
		push @items, { label => "Send SMS", callback => sub { &sendsms_form($num, $name, $searchstr, 'address', $type, ''); }, active => 1 };
	} else {
		push @items, { label => "Send SMS", active => 0 };
	}

	if (@items) {
		&popup_menu(\@items, $x, $y);
	}
}



sub load_addressbook {
	return if $cmdactive;

	&waitscreen('Addressbook', 'addressbook.xpm');
	print "Fetching Addressbook ... $prefs{abtimeout} $prefs{abtimeout}\n" if $DEBUG;
	$cmdactive = 1;
	my ($ok, $addressbook) = $scmxx->get_addressbook($prefs{abtimeout});
	$cmdactive = 0;
	print "Done ...\n" if $DEBUG;
	if (!$ok) {
		&errorscreen('Addressbook', $addressbook);
		return;
	} else {
		%addressbook = ();
		%addressbook = %{$addressbook};
		&do_save_addressbook_as_file("$ENV{HOME}/.gscmxx/addressbook.cache", '');
		&list_addressbook;
	}
}

sub load_addressbook_from_file_dialog {
	my $action = shift || "";	
	$action = "" if ref($action);
 	my $file_dialog = new Gtk::FileSelection("Addressbook: Load from File");
	if ($opendirs{'addressbook'}) {
		$file_dialog->set_filename($opendirs{'addressbook'});
	}
	$file_dialog->set_modal(1);	
	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $file = $file_dialog->get_filename(); 
							$opendirs{'addressbook'} = $file;
							my %abook = &load_addressbook_from_file($file);
							if ($action eq "append") {
								my @slots = reverse sort {$a <=> $b} grep !/^\_\_/, keys %addressbook;
								my $tmpslot;
								if (defined $slots[0]) {
									$tmpslot = $slots[0]+1 || 0;
								} else {
									$tmpslot = 0;
								}
								foreach (keys %abook) {
									if (/^__/) {
										$addressbook{$_} = $abook{$_};
									} else {
										$addressbook{$tmpslot} = $abook{$_};
										$tmpslot++;
									}
								}
							} else {
								%addressbook = ();
								%addressbook = %abook;
							}
							$addressbook{'__fetched'} = 1;
							$file_dialog->destroy(); 
							&list_addressbook();
						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();

}

sub load_addressbook_from_file {
	my $file = shift;

#	print "Loading addressbook from $file";
	return () unless -e $file;

	my @stat = stat($file);
	my $date = localtime($stat[9]);

	open (ABOOK, "$file") || warn "Can't open $file $!";
	my @tmp = (<ABOOK>);
	close (ABOOK);

	my $addressbook = $scmxx->create_addressbook_from_data(join("\n", @tmp));
	$addressbook->{__fetched} = 1;
	$addressbook->{__cachedate} = $date;
	return %{$addressbook};
}


sub reload_addressbook {
	return if $cmdactive;
	%addressbook = ();
	&load_addressbook;
}

# show one address (editable)
sub edit_address {
	my $slot = shift;
	my $searchstr = shift;
	my $sortcol = shift;
	my $sorttype = shift;
	my $row = shift;

	return if $cmdactive;
	$currentscreen = sub { &edit_address($slot, $searchstr, $sortcol, $sorttype, $row) };

	my %address = ();
	if (defined $slot) {
		%address = %{$addressbook{$slot}};
	}

	&reset_main_menu;
	my @sensitive;
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Load from Phone") if ($prefs{phonetype});
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Import File") . " (" . &i18n("append items") . ")";
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Restore from File") . " (" . &i18n("overwrite items") . ")";
	push @sensitive, "/" . &i18n("Addressbook") . "/" . &i18n("Save as File");
	&show_main_menu_items(@sensitive);
 
	&clean_main_box;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $table = new Gtk::Table( 15, 2, 0);	

	foreach (keys %addresslabels) {
		$address{$_} ||= "";
	}
	my %tmpaddress = %address;

	my $save = new Gtk::Button(&i18n("Save"));
	my $saveas = new Gtk::Button(&i18n("Save VCard as File"));
	if (!$tmpaddress{N} && !$tmpaddress{SN}) {
		$save->set_sensitive(0);
		$saveas->set_sensitive(0);
	} 
	my $i = 0;
#	foreach my $key (sort keys %values) {
	foreach my $key (sort { $addresslabels{$a} cmp $addresslabels{$b} } keys %addresslabels) {
		my (undef, $keyname) = split (/:/, $addresslabels{$key}, 2);
		my $k = new Gtk::Label(&i18n($keyname) . ":    ");
		$k->set_alignment( 0, 0 );
		$k->set_justify('left');
		$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
		$k->show;
		my $v = new Gtk::Entry($addresssizes{$key});
		#$v->set_text($values{$key} || "");
		$v->set_text($address{$key} || "");
		if ($key eq "N" || $key eq "SN") {
			$v->signal_connect("changed", sub { 
					my $tmp = $v->get_text();
					$tmpaddress{$key} = $tmp;
					if (!$tmpaddress{N} && !$tmpaddress{SN}) {
						$save->set_sensitive(0);
						$saveas->set_sensitive(0);
					} else {
						$save->set_sensitive(1);
						$saveas->set_sensitive(1);
					}
				} );
		} else {
			$v->signal_connect("changed", sub { $tmpaddress{$key} = $v->get_text(); } );
		}
		$table->attach( $v, 1, 2, $i, $i+1, 'shrink', 'shrink',0 ,0);
		$v->show;
		$i++;
	}

	my $k = new Gtk::Label(&i18n("Group") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
	$k->show;

	my $groupmenu = new Gtk::OptionMenu();
	my $grouppopup = new Gtk::Menu();
	$grouppopup->set_title("Group");
	my $num = 0; my $selgroup = 0;
	my %agroups = ('' => "No Group", "VIP" => "VIP");
    foreach my $gr ('', 'VIP') {
        my $item = new Gtk::MenuItem( &i18n($agroups{$gr}) );
        $item->signal_connect( 'activate', sub { $tmpaddress{CATEGORIES} = $gr });
        $grouppopup->append($item);
        $item->show();
        if ($tmpaddress{CATEGORIES} && $gr eq $tmpaddress{CATEGORIES} ) {
            $selgroup = $num;
        }
        $num++;
    }
    $groupmenu->set_menu($grouppopup);
    $groupmenu->set_history( $selgroup );
    $table->attach( $groupmenu, 1, 2, $i, $i+1, ['shrink','fill'], 'shrink', 0, 0);
    $groupmenu->show();

	$i++;

	$k = new Gtk::Label(&i18n("Last changed") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
	$k->show;
	my $date = readable_date($address{REV} || "");
	my $v = new Gtk::Label($date);
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, $i, $i+1, 'fill', 'shrink', 0, 0);
	$v->show;

	$table->show;
	$content->add($table);
	$content->show;
	
	my $footer = new Gtk::HBox(0,5);

	$save->signal_connect( "clicked", \&save_address, $slot, \%tmpaddress, $searchstr, $sortcol, $sorttype, $row );
	my $tooltip = new Gtk::Tooltips();
	$tooltip->set_tip( $save, &i18n("Save on Phone"), "" );
	$tooltip->enable(); 
	$footer->pack_start( $save, 0, 0, 0);
	$save->show();

	$saveas->signal_connect( "clicked", \&save_address_as_file, $slot, \%tmpaddress, $searchstr, $sortcol, $sorttype, $row );
	$tooltip = new Gtk::Tooltips();
	$tooltip->set_tip( $saveas, &i18n("Save VCard as File"), "" );
	$tooltip->enable(); 
	$footer->pack_start( $saveas, 0, 0, 0 );
	$saveas->show();
	
	my $next = new Gtk::Button(&i18n("Next") . " >>");
	$next->signal_connect( "clicked", sub { &show_prevnext_address($slot,1,$searchstr,$sortcol, $sorttype,$row); } );
	$footer->pack_end( $next, 0, 0, 0);
	$next->show();

	my $okbutton = new Gtk::Button(&i18n("Back to list"));
	$okbutton->signal_connect( "clicked", sub { &list_addressbook($searchstr, $sortcol, $sorttype, $row); } );
	$footer->pack_end( $okbutton, 0, 0, 0);
	$okbutton->show();

	my $prev = new Gtk::Button("<< " . &i18n("Prev"));
	$prev->signal_connect( "clicked", sub { &show_prevnext_address($slot,-1, $searchstr,$sortcol, $sorttype,$row); } );
	$footer->pack_end( $prev, 0, 0, 0);
	$prev->show();


	$footer->show();

	&show_main_menu_items(@sensitive);

	&mainscreen(HEADER => 'Addressbook',
			ICON => 'addressbook.xpm',
			CONTENT => $content,
			FOOTER => $footer);
}

sub new_addressbook_entry {
	return if $cmdactive;
	my $searchstr = shift;
	my $sort = shift;
	my @slots = reverse sort { $a <=> $b } grep /^\d+$/, keys %addressbook;
	my $slot = $slots[0]+1;
#	$addressbook{$slot} = {};
	&edit_address($slot,$searchstr,$sort);
}

# jump to next or previous address in list
sub show_prevnext_address {
	my $slot = shift;
	my $prevnext = shift;
	my $searchstr = shift;
	my $sortcol = shift;
	my $sorttype = shift;
	my $row = shift;

	# TODO implement sort
	my $sort = sub { uc($addressbook{$a}->{N}) cmp uc($addressbook{$b}->{N}) || uc($addressbook{$a}->{SN}) cmp uc($addressbook{$b}->{SN})};
	if ($sortcol == 1) {
		if ($sorttype eq "ascending") {
			$sort = sub { uc($addressbook{$a}->{N}) cmp uc($addressbook{$b}->{N}) || uc($addressbook{$a}->{SN}) cmp uc($addressbook{$b}->{SN}) };
		} else {
			$sort = sub { uc($addressbook{$b}->{N}) cmp uc($addressbook{$a}->{N}) || uc($addressbook{$a}->{SN}) cmp uc($addressbook{$b}->{SN}) };
		}
	} elsif ($sortcol == 2) {
		if ($sorttype eq "ascending") {
			$sort = sub { uc($addressbook{$a}->{SN}) cmp uc($addressbook{$b}->{SN}) || uc($addressbook{$a}->{N}) cmp uc($addressbook{$b}->{N}) };
		} else {
			$sort = sub { uc($addressbook{$b}->{SN}) cmp uc($addressbook{$a}->{SN}) || uc($addressbook{$a}->{N}) cmp uc($addressbook{$b}->{N}) };
		}
	} elsif ($sortcol == 3) {
		if ($sorttype eq "ascending") {
			$sort = sub { uc($addressbook{$a}->{'TEL;HOME'}) cmp uc($addressbook{$b}->{'TEL;HOME'}) };
		} else {
			$sort = sub { uc($addressbook{$b}->{'TEL;HOME'}) cmp uc($addressbook{$a}->{'TEL;HOME'}) };
		}
	}
	my @slots = sort $sort grep !/^__/, keys %addressbook; 
#	print (Dumper(\@slots)) if $DEBUG > 5;
	my $i=0;
	if ($searchstr) {
		my $ucsearchstr = uc($searchstr);
		my @tmp = @slots;
		@slots = ();
		foreach (@tmp) {
			push @slots, $_ if (uc($addressbook{$_}->{FN}) =~ /$ucsearchstr/);
		}
	}
	foreach my $s(@slots) {
		if ($s == $slot) {
			my $xslot;
			if ($i == $#slots && $prevnext == 1) {
				$xslot = $slots[0];
			} else {
				$xslot = $slots[$i+$prevnext];
			}
			&edit_address($xslot, $searchstr, $sortcol, $sorttype, $row);
			last;
		}
		$i++;
	}
}

sub save_address {
	my $pressedbutton = shift;
	my $slot = shift;
	my $address = shift;
	my $searchstr = shift;
	my $sortcol = shift;
	my $sorttype = shift;
	my $row = shift;

	return if $cmdactive;

#	unless ($slot) {
 		my @slots = reverse sort { $a <=> $b } grep /^\d+$/, keys %addressbook;
#		my $maxslot = $slots[0]+1;
#	}
	&waitscreen('Addressbook', 'addressbook.xpm', 'save');
#	print "New Slot? $slot\n";

	delete $addressbook{$slot} if $slot;
	my $result;
	$cmdactive = 1;
	($result, $slot, $address) = $scmxx->save_address($slot, $address, \@slots);
	$cmdactive = 0;
	$slot ||= "";
	print "gscmxx gets result: $result\n\n" if $DEBUG;
	print "Slot is now $slot\n" if $DEBUG;

#	print Dumper($address) if $DEBUG;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);

	my $dialogtxt;
	my $error;
	if ($result =~ /File transfer complete/ || $result =~ /VCard saved/) {
		$dialogtxt = &i18n("Address has been saved!");
	} else {
		if ($result =~ /nothing to get/) {
			$dialogtxt = &i18n("WARNING") . "\n" . "$result";
			$dialogtxt .= "\n\n" . &i18n("The address has probably been saved at another Slot.");
			$dialogtxt .= "\n" . &i18n("Please reload your Addressbook.");
		} else {
			$dialogtxt = &i18n("ERROR") . "\n" . "$result";
		}
		$error = 1;
	}

	my $label = new Gtk::Label($dialogtxt);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$dialog->set_style($styles{default});
	$dialog->set_modal( 1 ); 
	$dialog->border_width(10); 
	$label->show();

	my $button = new Gtk::Button( "OK" );
    $button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();

	$addressbook{__changed} = 1;
	$slot ||= $slots[0]+1;
	if (!$error && $address && ref($address)) {
		# change values in memory	
		$address->{FN} =~ s/^\s*,\s+//;
		$addressbook{$slot} = $address;
		&edit_address($slot,$searchstr,$sortcol, $sorttype, $row);
	} else {
		$error = "Something went wrong ..." unless ($error);
		warn $error;
		$addressbook{$slot} = $address unless $addressbook{$slot};
		&list_addressbook();
	}
}

sub save_address_as_file {
	my $pressedbutton = shift;
	my $slot = shift;
	my $address = shift;
	my $searchstr = shift;
	my $sort = shift;

	if (!$address || !ref($address)) {
		$address = $addressbook{$slot};
	}
 	my $file_dialog = new Gtk::FileSelection("Save VCard as file");
    if ($opendirs{'vcard_save'}) {
        $file_dialog->set_filename($opendirs{'vcard_save'});
    }
	$file_dialog->set_modal(1);	
	(my $fn = $address->{FN}) =~ s/\W+/_/g; 
	$fn ||= "unknown";
	$fn .= ".vcf";
	print "$fn\n" if $DEBUG;
	$file_dialog->set_filename( $fn );

#	$file_dialog->show_fileop_buttons(); 
# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $file = $file_dialog->get_filename(); 
							$opendirs{'vcard_save'} = $file;
							if (-e $file) {
								&check_if_file_exists($file);
								while ($tmpvals{overwritefile} == 0) {
									Gtk->main_iteration while (Gtk->events_pending);
									select(undef, undef, undef, 0.25);
								}
								if ($tmpvals{overwritefile} == 1) {
									&do_save_address_as_file($file,$slot,$address,$searchstr,$sort);
									$file_dialog->destroy();
								}
								$tmpvals{overwritefile} = 0;
							} else {
								&do_save_address_as_file($file,$slot,$address,$searchstr,$sort);
								$file_dialog->destroy();
							}
						} );


	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();

}

sub do_save_address_as_file {
	my $file = shift;
	my $slot = shift;
	my $address = shift;
	my $searchstr = shift;
	my $sort = shift;
	print "Saveing VCARD to $file " if $DEBUG;
	return unless $file;
	my $vcard;
	($address,$vcard) = $scmxx->generate_vcard($address, $slot);
	open (VCARD, ">$file") || warn "Can't write $file $!";
	print VCARD $vcard;
	close (VCARD);
}

sub save_addressbook_as_file {
	my $searchstr = shift || "";
	$searchstr = "" if (ref($searchstr));
 	my $file_dialog = new Gtk::FileSelection("Addressbook: Save as File");
    if ($opendirs{'addressbook_save'}) {
        $file_dialog->set_filename($opendirs{'addressbook_save'});
    } else {
		$file_dialog->set_filename( "addressbook.txt" );
	}
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $file = $file_dialog->get_filename(); 
							$opendirs{'addressbook_save'} = $file;
							if (-e $file) {
								&check_if_file_exists($file);
								while ($tmpvals{overwritefile} == 0) {
									Gtk->main_iteration while (Gtk->events_pending);
									select(undef, undef, undef, 0.25);
								}
								if ($tmpvals{overwritefile} == 1) {
									&do_save_addressbook_as_file($file,$searchstr);
									$file_dialog->destroy();
								}
								$tmpvals{overwritefile} = 0;
							} else {
								&do_save_addressbook_as_file($file,$searchstr);
								$file_dialog->destroy();
							}
						} );


	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();
}

sub do_save_addressbook_as_file {
	my $file = shift;
	my $searchstr = shift || "";
	my $abook = "";

	my $ucsearchstr = uc($searchstr);
	my @slots;
	if ($ucsearchstr) {
		foreach my $slot( keys %addressbook ) {
			next if $slot =~ /^__/;
			push @slots, $slot if (uc($addressbook{$slot}->{FN}) =~ /$ucsearchstr/);
		}
	} else {
		@slots = grep !/^__/, keys %addressbook;
	}

	foreach my $slot (sort { uc($addressbook{$a}->{FN}) cmp uc($addressbook{$b}->{FN}) } @slots) {
		my ($address,$vcard) = $scmxx->generate_vcard($addressbook{$slot},$slot);
		$abook .= $vcard . "\n";
	}

	open (ABOOK, ">$file") || warn "Can't write $file $!";
	print ABOOK $abook;
	close (ABOOK);
}


sub delete_address {
	my $slot = shift;
	my $clist = shift;
	my $row = shift;
	return if $cmdactive;

	my $address = $addressbook{$slot};

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 

	my $txt = &i18n("Do you really want to delete this VCard from your phone?");

	my $label = new Gtk::Label($txt);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $i = 0;
	my $table = new Gtk::Table( 15, 2, 0);	
	foreach my $key (sort { $addresslabels{$a} cmp $addresslabels{$b} } keys %addresslabels) {
		next unless $address->{$key};
		my (undef, $keyname) = split (/:/, $addresslabels{$key}, 2);
		my $k = new Gtk::Label(&i18n($keyname) . ":    ");
		$k->set_alignment( 0, 0 );
		$k->set_justify('left');
		$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
		$k->show;
		my $v = new Gtk::Label($address->{$key});
		$v->set_alignment( 0, 0 );
		$v->set_justify('left');
		$table->attach( $v, 1, 2, $i, $i+1, 'fill', 'shrink',0 ,0);
		$v->show;
		$i++;
	}

	my $k = new Gtk::Label(&i18n("Group") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
	$k->show;

	my %agroups = ('' => "No Group", "VIP" => "VIP");
   	my $v = new Gtk::Label(&i18n($agroups{$address->{CATEGORIES}}));
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, $i, $i+1, 'fill', 'shrink',0 ,0);
	$v->show;
	$i++;

	$k = new Gtk::Label(&i18n("Last changed") . ":    ");
	$k->set_alignment( 0, 0 );
	$k->set_justify('left');
	$table->attach( $k, 0, 1, $i, $i+1, 'fill', 'shrink', 0, 0);
	$k->show;
	my $date = readable_date($address->{REV} || "");
	$v = new Gtk::Label($date);
	$v->set_alignment( 0, 0 );
	$v->set_justify('left');
	$table->attach( $v, 1, 2, $i, $i+1, 'fill', 'shrink', 0, 0);
	$v->show;


	$dialog->vbox->pack_start( $table, 1, 1, 10 );
	$table->show();

	my $cancel = new Gtk::Button(&i18n("Cancel"));
   	$cancel->signal_connect( "clicked", sub { $dialog->destroy(); } );
	$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
	$cancel->show();

	my $ok = new Gtk::Button(&i18n("OK"));
	$ok->has_focus(1);
   	$ok->signal_connect( "clicked", sub {  
		my $result = $scmxx->delete_addressbook_entry($slot); 
		delete $addressbook{$slot}; 
		$addressbook{__changed} = 1;
		$clist->remove($row);
		$dialog->destroy();
	} );
	$dialog->action_area->pack_start( $ok, 1, 1, 0 );
	$ok->show();


#	$dialog->signal_connect( "key_press_event", sub { 
#		my $dialog = shift;
#		my $event = shift;
#		print "OK? " . $ok->has_focus() . "\n";
#		print "'" . $event->{keyval} . "'\n";
#		print "'" . Gtk::Gdk->keyval_name($event->{keyval}) . "'\n";
#		if (Gtk::Gdk->keyval_name($event->{keyval}) eq "Return" &&
#			$ok->has_focus()
#		) {
#			
#			print "delete $slot\n";
#			my $result = $scmxx->delete_addressbook_entry($slot); 
#			delete $addressbook{$slot}; 
#			$clist->remove($row);
#			$dialog->destroy();
#		}
#	});

	$dialog->show();
}


sub save_addressbook {
	return if $cmdactive;


	print "Really save whole addressbook?\n" if $DEBUG;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 

	my $txt = &i18n("Do you really want to save the current addressbook at your phone?");
	$txt .= "\n\n";
	$txt .= &i18n("All entries on your phone will be deleted!");
	$txt .= "\n\n";

	my $label = new Gtk::Label($txt);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $cancel = new Gtk::Button(&i18n("Cancel"));
   	$cancel->signal_connect( "clicked", sub { $dialog->destroy(); } );
	$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
	$cancel->show();

	my $ok = new Gtk::Button(&i18n("OK"));
	$ok->has_focus(1);
   	$ok->signal_connect( "clicked", sub { $dialog->destroy(); &do_save_addressbook($dialog); } );
	$dialog->action_area->pack_start( $ok, 1, 1, 0 );
	$ok->show();

	$dialog->show();
}

sub do_save_addressbook {

	print "Really save addressbook!!\n" if $DEBUG;

	print "Start: " . localtime() if $DEBUG;
	&waitscreen('Addressbook', 'addressbook.xpm', 'delete', 'minutes');

	$cmdactive = 1;
	# first delete all old entries
	# this is really slow!!
	my $result = $scmxx->delete_addressbook($prefs{abtimeout});
	print "DELETE ALL VCARDS: $result\n\n";

#=comment only delete full slots
#	# let's fetch the entries from the phone first and then delete them
#	my $tmp;
#
#	print "Fetched: $addressbook{__fetched} Cached: $addressbook{__cachedate}\n";
#	if ($addressbook{__fetched} && $addressbook{__cachedate}) {
#		print "Cached Addressbook => fetch tmp adressbook from phone\n";
#		my $ok;
#		($ok, $tmp) = $scmxx->get_addressbook($prefs{abtimeout});
#		$cmdactive = 0;
#	} else {
#		$tmp = \%addressbook;
#	}
#	use Data::Dumper;
#	print Dumper($tmp);
#	if ($tmp && ref($tmp) eq "HASH") {
#		foreach my $s (keys %{$tmp}) {
#			next if ($s =~ /^__/);
#			print "Delete Slot $s\n";
#			$cmdactive = 1;
#			$scmxx->delete_addressbook_entry($s);
#			$cmdactive = 0;
#		}
#	}
#=cut

	&waitscreen('Addressbook', 'addressbook.xpm', 'save', 'minutes');

	my @slots = (); # reverse sort { $a <=> $b } grep /^\d+$/, keys %addressbook;
	my %tmp = %addressbook;
	%addressbook = ();
	my $saved = 0;
	my $errors = 0;
	my $cnt = keys %tmp;
	print "\n\n---------------------\n\n" if $DEBUG;
	foreach my $tmpslot (sort { uc($tmp{$a}->{FN}) cmp uc($tmp{$b}->{FN}) } grep !/^__/, keys %tmp) {
		my $result;
		my $slot = ($slots[$#slots]) ? ($slots[$#slots]+1) : 0;
		print "TMP slot is: $slot\n" if $DEBUG;
		my $address = undef;
		$tmp{$tmpslot}->{SLOT} = $slot;
		($result, $slot, $address) = $scmxx->save_address($slot, $tmp{$tmpslot}, \@slots);
##		print "\n------\n$result\n------\n" if $DEBUG;
		if ($result =~ /File transfer complete/ || $result =~ /VCard saved/ || $result =~ /nothing to get/ ) {
			$saved++;
			print "Saved on Slot $slot\n" if $DEBUG;
			push @slots, $slot;
			@slots = sort { $a <=> $b } @slots;
			$addressbook{$slot} = $address;
		} else {
			$errors++;
		}
		print "\n\n---------------------\n\n" if $DEBUG;
#		sleep 2;
	}
	$cmdactive = 0;

	print "End: " . localtime() if $DEBUG;

	my $dialog = new Gtk::Dialog();
	$dialog->set_style($styles{default});
	$dialog->set_modal( 1 ); 
	$dialog->border_width(10); 

	my $label = new Gtk::Label(&i18n ("Addressbook has been saved."));
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	
	my $dialogtxt .= &i18n("\$cnt VCards have been saved on your phone.");
	$dialogtxt =~ s/\$cnt/$saved/;
	$dialogtxt .= "\n";
	if ($errors != 0) {
		$dialogtxt .= &i18n("\$cnt VCards could not be saved.");
		$dialogtxt =~ s/\$cnt/$errors/;
		$dialogtxt .= "\n";
	}

	$label = new Gtk::Label($dialogtxt);
	$label->set_justify('left');
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $button = new Gtk::Button( "OK" );
    $button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();

	$addressbook{__fetched} = 1;
	&list_addressbook();

}

##################################################
# BITMAPS
##################################################

sub list_bitmaps {

	return if $cmdactive;
	$currentscreen = sub { &list_bitmaps(@_) };

	if (!$bitmaps{__fetched}) {
		&waitscreen('Bitmaps', 'bitmap.xpm');
		print "Fetching Bitmaps ...\n" if $DEBUG;
		$cmdactive = 1;
		%bitmaps = $scmxx->get_bitmaps('all', "$ENV{HOME}/.gscmxx/bitmaps/");
		foreach my $slot(keys %bitmaps) {
			next if $slot =~ /^__/;
			my ($w, $h, $t) = imgsize("$ENV{HOME}/.gscmxx/bitmaps/$bitmaps{$slot}");
			my $bmp = $bitmaps{$slot};
			$bitmaps{$slot} = {
				"bitmap" => $bmp,
				"file"	=> &convert_to_xpm($bmp),
				"width"	=> $w,
				"height" => $h,
				"type"	=> $t
			}
		}
		$cmdactive = 0;
		$bitmaps{__fetched} = 1;
		print "Done ..." if $DEBUG;
	}

	my @slots = grep !/^__/, keys %bitmaps;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my %infos = (
		"0"	=>	{ "name" => "Logo of your provider", "editable" => 1 },
		"1"	=>	{ "name" => "Temporary Bitmap", "editable" => 1},
		"2"	=>	{ "name" => "Screensaver Image", "editable" => 1 }, 
		"3"	=>	{ "name" => "Unknown Image", "editable" => 1 },
	);
#		"1"	=>	"Temporary Bitmap",

	my $i = 0;
	
#	foreach my $slot (sort @slots) {
	my ($x,$y) = split(/-/, $phonedefs{slots}->{bmp});
	my $table = new Gtk::Table(($y*2), 7, 0);
	foreach my $slot ($x..$y) {
		next unless $infos{$slot};
#		(my $num = $bmp) =~ s/\.xpm//;
		my $n =  new Gtk::Label( " Slot $slot ");
        $n->set_alignment( 0, 0 );
        $table->attach( $n, 0, 1, $i, $i+1, 'shrink', 'fill', 0, 3 );
        $n->show;

		my $file;
		my $bmp;
		if ($bitmaps{$slot}) {
			$file = $bitmaps{$slot}->{file};
			$bmp = $bitmaps{$slot}->{bitmap};
			my $pixmapfile = "$ENV{HOME}/.gscmxx/bitmaps/$file";
		    my ($p,$m) = Gtk::Gdk::Pixmap->create_from_xpm($widgets->{window}->window,$widgets->{window}->style->bg('normal'),$pixmapfile);
		    my $pixmap = new Gtk::Pixmap($p,$m);
	        $table->attach( $pixmap, 1, 2, $i, $i+1, 'shrink', 'fill', 5, 3 );
			$pixmap->show;
		}
		my $info = &i18n($infos{$slot}->{name} || "Unknown Image") . "\n";

		if ($bitmaps{$slot}) {
			$info .= "(" . $bitmaps{$slot}->{width} ." x " . $bitmaps{$slot}->{height} . ", " . $bitmaps{$slot}->{type} . ")";
		}
		$n =  new Gtk::Label($info);
        $n->set_alignment( 0, 0 );
        $n->set_justify( 'left' );
        $table->attach( $n, 2, 3, $i, $i+1, 'fill', 'fill', 0, 10 );
        $n->show;

		if ($infos{$slot}->{editable}) {
			if ($bitmaps{$slot}) {
				my $save = create_pixmap_button('', sub { &save_bitmap($slot, "$ENV{HOME}/.gscmxx/bitmaps/$bmp", "Save Bitmap"); }, 'save.xpm', 'hor', &i18n('Bitmap') . ': ' . &i18n('Save on Phone'));
				$table->attach( $save, 3, 4, $i, $i+1, 'shrink', 'shrink', 5, 3 );
				$save->show;

				my $saveas = create_pixmap_button('', sub { &save_file("$ENV{HOME}/.gscmxx/bitmaps/$bmp", "Save Bitmap", 'bitmap'); }, 'saveas.xpm', 'hor', &i18n('Bitmap') . ': ' . &i18n('Save as File'));
				$table->attach( $saveas, 4, 5, $i, $i+1, 'shrink', 'shrink', 5, 3 );
				$saveas->show;

				my $del = create_pixmap_button('', sub { &delete_bitmap($slot); }, 'delete.xpm', 'hor', &i18n('Bitmap') . ': ' . &i18n('Delete'));
				$table->attach( $del, 5, 6, $i, $i+1, 'shrink', 'shrink', 5, 3 );
				$del->show;
			}

			my $open = create_pixmap_button('', sub { &open_bitmap_file($slot, &i18n("Bitmap") . ": " . &i18n("Open File")); }, 'open.xpm', 'hor', &i18n("Bitmap") . ": " . &i18n("Open File"));
			$table->attach( $open, 6, 7, $i, $i+1, 'shrink', 'shrink', 5, 3 );
			$open->show;
		}
		$i++;

		my $hsep = new Gtk::HSeparator();
        $table->attach( $hsep, 0, 7, $i, $i+1, ['expand','fill'], 'fill', 10, 3 );
		$hsep->show;
		
		$i++;
	}

	$content->add($table);
	$table->show;
	$content->show;

	my $footer = new Gtk::HBox(0,5);

	my $reload = new Gtk::Button(&i18n("Reload"));
	$reload->signal_connect( "clicked", \&reload_bitmaps );
	my $tooltip = new Gtk::Tooltips();
	$tooltip->set_tip( $reload, &i18n("Bitmaps") . ": " . &i18n("Load from Phone"), "" );
	$tooltip->enable(); 
	$footer->pack_end( $reload, 0, 0, 0 );
	$reload->show();

	$footer->show();
	
	&mainscreen(HEADER => 'Bitmaps',
			ICON 	=> 'bitmap.xpm',
			CONTENT => $content,
			FOOTER	=> $footer);
}

sub reload_bitmaps {
	%bitmaps = ();
	&list_bitmaps;
}

sub open_bitmap_file {
	my $slot = shift;

#	print "Slot: $slot";

 	my $file_dialog = new Gtk::FileSelection(&i18n('Bitmaps') . ": " . &i18n('Open File'));
	$file_dialog->set_modal(1);	
	if ($opendirs{'bitmaps'}) {
		$file_dialog->set_filename($opendirs{'bitmaps'});
	}
	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $dfile = $file_dialog->get_filename(); 
#							print "Should open $dfile\n";
							$opendirs{'bitmaps'} = $dfile;
							if (my $error = &handle_bitmap($slot, $dfile)) {
								print "ERROR: $error\n";
							} else {
								$file_dialog->destroy(); 
								&list_bitmaps;
							}
						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();
	
}

sub handle_bitmap {
	my $slot = shift;
	my $bitmap = shift;

	return &i18n("File does not exist") . ": $bitmap\n" if (!-e $bitmap);

	my ($w, $h, $t) = imgsize($bitmap);
	$t = lc($t);

	return &i18n("Unknown Image Format") unless ($t);
		
	#my $tmp = "$ENV{HOME}/.gscmxx/bitmaps/tmp_$slot.$t";
	my $bitmapdir = "$ENV{HOME}/.gscmxx/bitmaps";
	my $tmp = "tmp_$slot.$t";
#	print "Renaming to $bitmapdir/$tmp\n";
	my $cp = "cp -f $bitmap $bitmapdir/$tmp";
#	print "$cp\n";
	system($cp) == 0 || return &i18n("Could not open:") . " $bitmap.\n";

#	if ($t ne "bmp") {
		# we convert bmps also, because they may have more colors then bw
		$bitmap = &convert_to_bmp($tmp, $t);
		return &i18n("ERROR") . ": " . &i18n("Could not convert image to bitmap format.") unless $bitmap;
#	} else {
#		if ($w > 101 || $h > 64) {
#			$bitmap = &convert_to_bmp($tmp, $t);
#			return &i18n("ERROR") . ": " . &i18n("Could not convert image to bitmap format.") unless $bitmap;
#		} else {
#			$bitmap = $tmp;
#		}
#	}

	($w, $h, $t) = imgsize("$bitmapdir/$bitmap");
	my $xpm = convert_to_xpm($bitmap); 
	$bitmaps{$slot} = {
		"bitmap"=>	$bitmap,
		"file"	=>	$xpm,
		"width"	=>	$w,
		"height"=>	$h,
		"type"	=>	$t
	};
	return 0;
}

sub convert_to_xpm {
	my $img = shift;
	my $xpm = $img;
	$xpm =~ s/\.bmp/.xpm/;
	my $bitmapdir = "$ENV{HOME}/.gscmxx/bitmaps";
	my $cmd = "convert $bitmapdir/$img  -background black $bitmapdir/$xpm";
#	my $cmd = "bmptoppm $bitmapdir/$img 2>/dev/null | ppmtoxpm > $bitmapdir/$xpm 2>/dev/null";
#	print "convert to xpm: $cmd\n";
	system($cmd);
	return $xpm;
}

sub convert_to_bmp {
	my $img = shift;
	my $type = shift;
	my $size = shift || "101x64";
	$size .= ">";	
	my $bitmapdir = "$ENV{HOME}/.gscmxx/bitmaps";

	my $bmp;
	if ($type eq "bmp") {
		$bmp = $img;
		$img =~ s/\.$type$/_old.$type/;
		my $mv = "mv -f $bitmapdir/$bmp $bitmapdir/$img";
#		print "$mv\n";
		system($mv) == 0 || return 0;
	} else {
		($bmp = $img) =~ s/\.$type$//;
		$bmp .= ".bmp";
	}
	# use '+matte' to remove transparency
	my $cmd = "convert -geometry '$size' $bitmapdir/$img +matte -background white -monochrome BMP:$bitmapdir/$bmp";
#	print "convert to bmp: $cmd\n";
	system ($cmd) == 0 || return 0;
	unlink("$bitmapdir/$img");
	return $bmp;
}

sub save_bitmap {
	my $slot = shift;
	my $file = shift;
	return if $cmdactive;
	$cmdactive = 1;
	my $cmd = "--send --bitmap=$slot $file 2>&1";
	my $result = $scmxx->docmd($cmd);
	$cmdactive = 0;
}

sub delete_bitmap {
	my $slot = shift;
	my $cmd = "--remove --bitmap=$slot --file -  2>&1";
	return if $cmdactive;
	$cmdactive = 1;
	my $result = $scmxx->docmd($cmd);
	delete $bitmaps{$slot};
	$cmdactive = 0;
	&list_bitmaps;
}

sub save_file {
	my $file = shift;
	my $title = shift || "Save as File";
	my $type = shift || "";
 	my $file_dialog = new Gtk::FileSelection($title);
	$file_dialog->set_modal(1);	

	my $dir;
	if ($opendirs{$type . '_save'}) {
		($dir = $opendirs{$type . '_save'}) =~ s/[^\/]+$//;
    }

	(my $fn = $file) =~ s/^.*\///;
	$file_dialog->set_filename( "$dir$fn" );
	
	# Connect the ok_button 
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { my $dfile = $file_dialog->get_filename(); 
							$opendirs{$type . '_save'} = $dfile;
							if (-e $dfile) {
								&check_if_file_exists($dfile);
								while ($tmpvals{overwritefile} == 0) {
									Gtk->main_iteration while (Gtk->events_pending);
									select(undef, undef, undef, 0.25);
								}
								if ($tmpvals{overwritefile} == 1) {
									system("cp $file $dfile");
									$file_dialog->destroy();
								}
								$tmpvals{overwritefile} = 0;
							} else {
								system("cp $file $dfile");
								$file_dialog->destroy();
							}
						} );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();

}
##################################################
# SOUNDS
##################################################

sub list_sounds {

	return if $cmdactive;
	$currentscreen = sub { &list_sounds(@_) };

	if (!@sounds) {
		&waitscreen('Ringtones', 'sound.xpm');

		print "Fetching Ringtones ...\n" if $DEBUG;
		$cmdactive = 1;
		@sounds = $scmxx->get_sounds('all', "$ENV{HOME}/.gscmxx/midi", '');
		$cmdactive = 0;
		print "Done ..." if $DEBUG;
	}

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $table = new Gtk::Table($#sounds, 4, 0);	

	my $i = 0;
	foreach my $mid (@sounds) {
		(my $num = $mid) =~ s/\.mid//;
		my $label = new Gtk::Label(" $num  ");
		$label->set_alignment(0,0);
		$table->attach($label, 0, 1, $i, $i+1, 'shrink', 'shrink', 5, 3);
		$label->show;

		my $pixmap = &createpixmap('midi.xpm');
		$table->attach($pixmap, 1, 2, $i, $i+1, 'shrink', 'shrink', 5, 3);
		$pixmap->show;

		my $save = create_pixmap_button('', sub { &save_file("$ENV{HOME}/.gscmxx/midi/$num.mid", &i18n("Ringtones")  . ": " . &i18n("Save as File"), 'midi' ); }, 'saveas.xpm', 'hor', &i18n('Save as File') );
        $table->attach( $save, 3, 4, $i, $i+1, 'shrink', 'shrink', 10, 3 );
        $save->show;


		$i++;
	}

	$content->add($table);
	$table->show;
	&mainscreen(HEADER => 'Ringtones',
				ICON => 'sound.xpm',
				CONTENT => $content,
				FOOTER => '');
				
}

##################################################
# PREFERENCES
##################################################

sub show_preferences {
	my $menu = shift;

	return if $cmdactive;
	$currentscreen = sub { &show_preferences($menu) };

	&clean_main_box();

	my $prefs = new Gtk::VBox(0,0);
	$prefs->set_style($styles{default});

	if ($prefs{errortxt}) {
		my $ebox = new Gtk::EventBox();
		$ebox->set_style($styles{default});

		my $error = new Gtk::Label(&i18n("ERROR") . ":\n\n$prefs{errortxt}\n\n");
	    $error->set_alignment( 0, 0 );
		$error->set_justify('left');
		$error->set_style($styles{default});
	    $error->show();
		$ebox->add($error);
		$prefs->pack_start( $ebox, 0, 0, 0 );
	}

	my $ebox = new Gtk::EventBox();
	$ebox->set_style($styles{default});

	my $table = new Gtk::Table(7, 4, 0);
	$table->set_row_spacings( 3 ); 
	$table->set_col_spacings( 5 ); 

	my  $label = new Gtk::Label(&i18n("SCMxx binary") . ":");
   	$label->set_alignment( 0, 0.5 );
	$label->set_justify('left');
	$label->set_line_wrap(1);
	$table->attach( $label, 0, 1, 0, 1, ['shrink','fill'], 'fill', 0, 0);
	$label->show();

	my $scmxxentry = new Gtk::Entry();
	$scmxxentry->set_text($prefs{scmxx});
	$scmxxentry->signal_connect( "changed", sub { $prefs{scmxx} = $scmxxentry->get_text(); } );
	$scmxxentry->show;
	$table->attach( $scmxxentry, 1, 2, 0, 1, ['fill','shrink'], 'shrink', 0, 0);

	my $choose = new Gtk::Button(&i18n("Choose"));
	$choose->signal_connect( "clicked", \&choose_prefs_file, 'scmxx', $scmxxentry );
	$choose->show();
	$table->attach( $choose, 2, 3, 0, 1, ['fill','shrink'], 'fill', 0, 0);

#	my $tmp = new Gtk::Label("                      ");
#	$table->attach( $tmp, 3, 4, 0, 1, ['expand','fill'],'fill', 0, 0);
#	$tmp->show;

	# create a popup menu for devices
	$label = new Gtk::Label(&i18n("Device") . ":\n");
   	$label->set_alignment( 0, 0.5 );
   	$label->set_justify('left');
	$label->set_line_wrap(1);
	$table->attach( $label, 0, 1, 1, 2, ['shrink','fill'], 'fill', 0, 0);
	$label->show();
	my $devmenu = new Gtk::OptionMenu();
	my $devpopup = new Gtk::Menu();
	$devpopup->set_title("Device");


	# Other device
#=comment
#	my $deventry = new Gtk::Entry();
#	$deventry->set_text($prefs{device}) unless (grep /^$prefs{device}$/, @devices);
#	$deventry->signal_connect( "changed", sub { $prefs{device} = $deventry->get_text(); } );
##	$deventry->show;
#	$table->attach( $deventry, 2, 4, 1, 2, ['fill','shrink'], 'shrink', 0, 0);
#=cut

	my $num = 0;
	my $selportnum = 0;
#	my $item = new Gtk::MenuItem( "- " . &i18n("Other device") . " --->" );
#	$item->signal_connect( 'activate', sub { $deventry->show; });
#	$devpopup->append($item);
#	$item->show();
#	if (! grep /^$prefs{device}$/, @devices) {
#		$selportnum = $num;
#		$deventry->show;
#	}
#	$num++;
#=comment sorted
#	foreach my $i (sort {
#		my ($x1, $x2, $y1, $y2);
#		if ($a =~ /(\D+)(\d+)/) {
#			($x1, $x2) = ($1, $2);
#		} else {
#			$x1 = $a; $x2 = 0;
#		}
#		if ($b =~ /(\D+)(\d+)/) {
#			($y1, $y2) = ($1, $2);
#		} else {
#			$y1 = $b; $y2 = 0;
#		}
#		$x1 cmp $y1 || $x2 <=> $y2;
#	} @devices) {
#=cut
	foreach my $i (@devices) {
		chomp $i;
		my $item = new Gtk::MenuItem( "$i" );
		# $item->signal_connect( 'activate', sub { $deventry->hide; $prefs{device} = $i });
		$item->signal_connect( 'activate', sub { $prefs{device} = $i });
		$devpopup->append($item);
		$item->show();
		if ($i eq $prefs{device}) {
			$selportnum = $num;
		}
		$num++;
	}
	$devmenu->set_menu($devpopup);	
	$devmenu->set_history( $selportnum );
	$table->attach( $devmenu, 1, 2, 1, 2, ['fill','shrink'], 'shrink', 0, 0);
	$devmenu->show();

	my $choose2 = new Gtk::Button(&i18n("Choose other"));
	$choose2->signal_connect( "clicked", \&choose_prefs_file, 'Device', undef );
	$choose2->show();
	$table->attach( $choose2, 2, 3, 1, 2, ['fill','shrink'], 'fill', 0, 0);


	# create a popup menu for baudrate
	$label = new Gtk::Label(&i18n("Baudrate") . ":\n");
  	$label->set_alignment( 0, 0.5 );
   	$label->set_justify('left');
	$label->set_line_wrap(1);
	
	$table->attach( $label, 0, 1, 2, 3, ['shrink','fill'], 'fill', 0, 0);
	$label->show();
	my $baudmenu = new Gtk::OptionMenu();
	my $baudpopup = new Gtk::Menu();
	$baudpopup->set_title("Baudrate");
	$num = 0;
	$selportnum = 0;
	foreach my $i (9600, 19200, 38400, 57600, 115200) {
		my $item = new Gtk::MenuItem( "$i" );
		$item->signal_connect( 'activate', sub { $prefs{baudrate} = $i });
		$baudpopup->append($item);
		$item->show();
		if ($i eq $prefs{baudrate}) {
			$selportnum = $num;
		}
		$num++;
	}
	$baudmenu->set_menu($baudpopup);	
	$baudmenu->set_history( $selportnum );
	$table->attach( $baudmenu, 1, 2, 2, 3, ['fill','shrink'], 'shrink', 0, 0);
	$baudmenu->show();

	my $info = new Gtk::Label(&i18n("The baudrate MUST match the rate of your phone") . "\n\n");
   	$info->set_alignment( 0, 0 );
   	$info->set_justify( 'left' );
	$info->set_line_wrap( 1 );
	$table->attach( $info, 1, 4, 3, 4, 'fill', 'shrink', 0, 0);
	$info->show;

	my ($tomenu, $topopup, $sel);

	$label = new Gtk::Label(&i18n("Timeout") . ":");
  	$label->set_alignment( 0, 0.5 );
   	$label->set_justify('left');
	$label->set_line_wrap(1);
	
	$table->attach( $label, 0, 1, 5, 6, ['fill','shrink'], 'expand', 0, 0);
	$label->show();
	$tomenu = new Gtk::OptionMenu();
	$topopup = new Gtk::Menu();
	$topopup->set_title("Timeout");
	$num = 0;
	$sel = 0;
	foreach (1..24) {
		my $i = $_ * 10;
		my $item = new Gtk::MenuItem( "$i s" );
		$item->signal_connect( 'activate', sub { $prefs{timeout} = $i; });
		$topopup->append($item);
		$item->show();
		if ($i == $prefs{timeout}) {
			$sel = $num;
		}
		$num++;
	}
	$tomenu->set_menu($topopup);	
	$tomenu->set_history( $sel );
	$table->attach( $tomenu, 1, 2, 5, 6, ['fill','shrink'], 'shrink', 0, 0);
	$tomenu->show();


	$label = new Gtk::Label(&i18n("Phonebook Timeout") . ":");
  	$label->set_alignment( 0, 0.5 );
   	$label->set_justify('left');
	$label->set_line_wrap(1);
	
	$table->attach( $label, 0, 1, 6, 7, ['shrink','fill'], 'fill', 0, 0);
	$label->show();
	$tomenu = new Gtk::OptionMenu();
	$topopup = new Gtk::Menu();
	$topopup->set_title("Phonebook Timeout");
	$num = 0;
	$sel = 0;
	foreach (1..24) {
		my $i = $_ * 10;
		my $item = new Gtk::MenuItem( "$i s" );
		$item->signal_connect( 'activate', sub { $prefs{pbtimeout} = $i; });
		$topopup->append($item);
		$item->show();
		if ($i == $prefs{pbtimeout}) {
			$sel = $num;
		}
		$num++;
	}
	$tomenu->set_menu($topopup);	
	$tomenu->set_history( $sel );
	$table->attach( $tomenu, 1, 2, 6, 7, ['fill','shrink'], 'shrink', 0, 0);
	$tomenu->show();

	$label = new Gtk::Label(&i18n("Addressbook Timeout") . " : ");
	$label->set_line_wrap(1);
  	$label->set_alignment( 0, 0.5 );
  	$label->set_justify('fill');
	
	$table->attach( $label, 0, 1, 7, 8, ['fill','shrink'], 'expand', 0, 0);
	$label->show();
	$tomenu = new Gtk::OptionMenu();
	$topopup = new Gtk::Menu();
	$topopup->set_title("Addessbook Timeout");
	$num = 0;
	$sel = 0;
	foreach (1..24) {
		my $i = $_ * 10;
		my $item = new Gtk::MenuItem( "$i s" );
		$item->signal_connect( 'activate', sub { $prefs{abtimeout} = $i; });
		$topopup->append($item);
		$item->show();
		if ($i == $prefs{abtimeout}) {
			$sel = $num;
		}
		$num++;
	}
	$tomenu->set_menu($topopup);	
	$tomenu->set_history( $sel );
	$table->attach( $tomenu, 1, 2, 7, 8, ['fill','shrink'], 'expand', 0, 0);
	$tomenu->show();

	$table->show();

	$ebox->add($table);
	$ebox->show;
	$prefs->pack_start( $ebox, 0, 0, 0 );

	$ebox = new Gtk::EventBox();
	$ebox->set_style($styles{default});
	$ebox->show;
	$prefs->pack_start( $ebox, 1, 1, 0 );
	
	$prefs->show;

	# save and cancel button
	my $bbox = new Gtk::HBox(0,5);

	my $savebutton = new Gtk::Button(&i18n("Save"));
	$savebutton->signal_connect( "clicked", \&save_preferences );
	$bbox->pack_start( $savebutton, 0, 0, 0 );
	$savebutton->show();

#	my $cancelbutton = new Gtk::Button("Cancel");
#	$cancelbutton->signal_connect( "clicked", \&splashscreen );
#	$bbox->pack_start( $cancelbutton, 0, 0, 0 );
#	$cancelbutton->show();

	my $reset = new Gtk::Button(&i18n("Reset Phone"));
	$reset->signal_connect( "clicked", \&reset_phone );
	$bbox->pack_end( $reset, 0, 0, 0 );
	$reset->show();

	$bbox->show();
	
	&mainscreen(HEADER => 'Preferences',
			ICON => 'preferences.xpm',
			CONTENT => $prefs,
			SCROLLEDWIN => 0,
			FOOTER => $bbox);
}

sub save_preferences {

	$prefs{saved} = 1;
	return if $cmdactive;

	&write_preferences;
	$cmdactive = 1;
	$scmxx->set_preferences(\%prefs);
	$cmdactive = 0;
	&reset_data;
	&redisplay;
}

sub write_preferences {
	my $file = $ENV{HOME} . "/.gscmxx/gscmxxrc";
	open (PREFS, ">$file") || die "Can't open $file $!";
	print PREFS "#" x 50 . "\n";
	print PREFS "### preferences for gscmxx\n";
	print PREFS "### do not edit! will be overwritten\n";
	print PREFS "#" x 50 . "\n";
	my @prefs = qw(device baudrate scmxx abtimeout pbtimeout language);
	foreach (@prefs) {
		print "$_ : $prefs{$_} : $prefs{$_}\n" if $DEBUG > 5;
#		$prefs{$_} = $prefs{$_};
		print PREFS "$_\t$prefs{$_}\n";
	} 
	close(PREFS);
}

sub reset_data {
	@mobileinfo = ();
	%addressbook = ();
	%phonebooks = ();

	$prefs{phonetype} = &detect_phone;

	$i18n = &read_lang_file($prefs{language});
}

sub redisplay {
	&mainwindow();
	&show_preferences;
}

sub set_language {
	my $lang = shift;
	return unless $lang;
	return if $cmdactive;
	return if ($prefs{language} eq $lang);
	$prefs{language} = $lang;
	&write_preferences;	
	$i18n = &read_lang_file($prefs{language});
	&mainwindow();
	&{$currentscreen};
}
sub read_preferences {

	print "Reading preferences ...\n" if $DEBUG;
	my $scmxx = `which scmxx 2>/dev/null`;
	chomp $scmxx;
	if (!$scmxx) {
		print "\nERROR:\nscmxx not found\nplease get it from http://www.hendrik-sattler.de/scmxx/ and try again\n\n";
#		exit(0);
	}
	my %defaultprefs = (
		"device" => $SCMxx::Config->{DEVICE},
		"baudrate" => $SCMxx::Config->{BAUDRATE},
		"saved" => 0,
		"scmxx" => $SCMxx::Config->{SCMXX},
		"timeout" => $SCMxx::Config->{TIMEOUT},
		"pbtimeout" => $SCMxx::Config->{PBTIMEOUT},
		"abtimeout" => $SCMxx::Config->{ABTIMEOUT},
		"language"	=> 'english'
	);
	my $file = $ENV{HOME} . "/.gscmxx/gscmxxrc";	
	if (-e $file) {
		#print "Prefs found!";
		my %prefs;
		open (PREFS, "$file") || die "Can't open $file $!";
		while (<PREFS>) {
			my $l = $_;
			chomp $l;
			next if ($l =~ /\s*#/);
			my ($k, $v) = split (/\s+/, $l, 2);
			$prefs{$k} = $v;
		}
		close (PREFS);
		if ($prefs{device} && $prefs{scmxx}) {
			$prefs{saved} = 1;
		}
		foreach (keys %defaultprefs) {
			$prefs{$_} ||= $defaultprefs{$_};
		}
#		print Dumper(%prefs) if $DEBUG > 5;
		return (0, \%prefs);
	} else {
		return (1, \%defaultprefs);
	}
}

# try to detect usable devices 
sub get_devices {

	# check for usable ttyS* devices 
	# see http://www.ibiblio.org/mdw/HOWTO/Serial-HOWTO-10.html#ss10.1
	# this will only work with linux!
	print "Checking for tty-serial ports .......... " if $DEBUG;
	my @ttyS;
	my $procfile = "/proc/tty/driver/serial";
	if (-e $procfile) {
		open (PROC, "$procfile") || die "Can't open $procfile $!";
		while (<PROC>) {
			chomp;
			if ($_ !~ /unknown port/ && $_ !~ /serinfo/ ) {
				my ($num, undef) = split (/:/, $_, 2);
				push @ttyS, "/dev/ttyS$num";
			}
		} 
		close (PROC);
		if (@ttyS) {
			print "available\n" if $DEBUG;
			print "    found: " . join(", ", @ttyS) if $DEBUG;
			print "\n" if $DEBUG;
		}
	} else {
		print "$procfile not available\n" if $DEBUG;
	}
	
	#TODO
	# check for useable ircomm devices
	# for now just list all of them	
	my @ircoms = `ls -1 /dev/ircomm*`;

	# check if usb is present
	my @usbtty;
	print "Checking for usb support ............... " if $DEBUG;
	if (-e "/proc/bus/usb/drivers") {
		print "OK\n" if $DEBUG;
		# check if usbserial is present
		print "Checking for usbserial support ......... " if $DEBUG;
		my $usbser = `grep serial /proc/bus/usb/drivers`;
		if ($usbser =~ /serial/) {
			print "available\n" if $DEBUG;
			print "Checking for usbserial device .......... " if $DEBUG;
			$usbser = `grep -c serial /proc/bus/usb/devices`; 
			chomp $usbser;
			$usbser =~ s/\s+//g;
			if ($usbser > 0) {
				print "available\n" if $DEBUG;
				print "     $usbser device(s) found\n" if $DEBUG;
				print "     assuming devices " if $DEBUG;
				my $devpath;
				if (-d "/dev/usb/tts") {
					$devpath = "/dev/usb/tts";
				} else {
					$devpath = "/dev/usb/ttyUSB";
				}
				foreach (1..$usbser) {
					push @usbtty, "$devpath" . ($_-1);
				}
				print join (", ", @usbtty) . "\n" if $DEBUG;
			} else {
				print "NOT available\n" if $DEBUG;
			}
		} else {
			print "NOT available\n" if $DEBUG;
		}
	} else {
		print "NOT available\n" if $DEBUG;
	}

	print "\n\n" if $DEBUG;
	return (@ttyS, @usbtty, @ircoms);
}

sub choose_prefs_file {
	my $button = shift;
	my $what = shift;
	my $entry = shift;

	print "WHAT: $what\n" if $DEBUG;
 	my $file_dialog = new Gtk::FileSelection(&i18n("Choose") . ": " . &i18n($what));
	$file_dialog->set_modal(1);	
	if ($what eq "Device" && !$opendirs{$what}) { $opendirs{$what} = "/dev/"; }
	if ($opendirs{$what}) {
        $file_dialog->set_filename($opendirs{$what});
    }


	# Connect the ok_button to file_ok_sel function
	$file_dialog->ok_button->signal_connect( "clicked",
					 sub { $prefs{lc($what)} = $file_dialog->get_filename(); 
							$opendirs{$what} = $prefs{lc($what)};
							if ($what eq "Device") {
								@devices = ($prefs{lc($what)}, @devices);
							}
							$file_dialog->destroy(); 
							&show_preferences; } );

	# Connect the cancel_button to destroy the widgets
	$file_dialog->cancel_button->signal_connect( "clicked",
					     sub { $file_dialog->destroy; } );
	$file_dialog->show();

}

##################################################
# MAIN LAYOUT FUNCTIONS
##################################################

# the main window 
#  +-------------+
#  | txt menu    |
#  +-------------+
#  | p |         |
#  | i |  main   |
#  | c |         |
#  +-------------+

sub mainwindow {

	my @childs = $widgets->{window}->children;
	foreach (@childs) {
		$_->destroy();
	}

	# vertical box (txt-menu & hbox)
	my $vbox = new Gtk::VBox( 0, 0 );
	$vbox->show;
	$vbox->set_style($styles{default});
	$vbox->set_sensitive(1);
	$widgets->{window}->add( $vbox );

	# Create the txt menu bar
	my $menubar = create_main_menu();
	$vbox->pack_start( $menubar, 0, 1, 0 );
	$vbox->set_spacing(0);
	$menubar->show();

	&reset_main_menu;
	# horizontal box (pics u. menu)
	my $hbox = new Gtk::HBox( 0, 0);
	$hbox->set_spacing(0);
	$hbox->set_style($styles{default});
	$hbox->set_sensitive(1);
	$hbox->show();

	# pic menu
	my $picmenu = &create_pic_menu($widgets->{window});
	$hbox->pack_start($picmenu, 0, 1, 0);


	#my $sepbox = new Gtk::EventBox();
	#$sepbox->set_style($styles{picnavig});
	#my $sep = new Gtk::VSeparator();
	#$sepbox->add($sep);
	#$hbox->pack_start($sepbox, 0, 1, 0);
	#$sep->show;
	#$sepbox->show;

	# new vertical box for content (main)
	$widgets->{mainbox} = new Gtk::VBox( 0, 0 );
	$widgets->{mainbox}->border_width( 5 );
	$widgets->{mainbox}->set_style($styles{default});
	$widgets->{mainbox}->set_sensitive(1);
	$widgets->{mainbox}->show();

	$hbox->pack_start($widgets->{mainbox}, 1, 1, 0);

	$vbox->pack_start($hbox, 1, 1, 0);

	$widgets->{window}->set_sensitive(1);
	# set window attributes and show it
	$widgets->{window}->show();
}

# this is the mainscreen
#
#  +----------------------+
#  | HEADER               |
#  +----------------------+
#  | optional menu/func   |
#  +--------------------+-+
#  | CONTENT            |^|
#  | with automatic     | |
#  | scrollbars         | |
#  |                    |v|
#  +--------------------+-+
#  | FOOTER (Buttons)     |
#  +----------------------+

sub mainscreen {
	my %args = (HEADER	=> '',
				MENU	=> '',
				ICON	=> '',
				CONTENT	=> '',
				SCROLLEDWIN => 1,
				FOOTER	=> '',
				@_);

	&clean_main_box;


	# new box
	my $box = new Gtk::VBox(0,0);
	$box->border_width( 0 );
	$box->set_spacing(5);
#	$box->set_style($styles{default});

	my $header;
	if (!$args{HEADER}) {
		# do nothing
	} elsif (ref ($args{HEADER}) && $args{HEADER}->get_name =~ /Gtk/) {
        	$box->pack_start( $args{HEADER}, 0, 0, 0 );
	} else {
		# create a hbox
		$header = &header($args{HEADER}, $args{ICON}, $args{MENU});
		$box->pack_start($header, 0, 0, 0);
	}

	if ($args{SCROLLEDWIN}) {
		# create a new scrolled window.
		$widgets->{content} = new Gtk::ScrolledWindow( "", "" );
		$widgets->{content}->set_policy( "automatic", "automatic" );
		if (ref($args{CONTENT}) =~ /CList/) {
			$widgets->{content}->add( $args{CONTENT} );
		} else {
			$widgets->{content}->add_with_viewport( $args{CONTENT} );
		}
	#	$widgets->{content}->viewport->set_shadow_type('none');
		$widgets->{content}->set_style($styles{default});
	} else {
		$widgets->{content} = $args{CONTENT};
	}
	$args{CONTENT}->set_style($styles{default});
	$args{CONTENT}->show;
	$box->pack_start( $widgets->{content}, 1, 1, 0 );
	$widgets->{content}->show();

	# footer
	if (!$args{FOOTER}) {
		# do nothing
	} elsif (ref ($args{FOOTER}) && $args{FOOTER}->get_name =~ /Gtk/) {
		$box->pack_start( $args{FOOTER}, 0, 0, 0 );
		$args{FOOTER}->show;
	} else {
		# Create a label
		my $label = new Gtk::Label($args{FOOTER});
		# Align the label to the left side. 
	   	$label->set_alignment( 0, 0 );
		# Pack the label into the box and show it
		$box->pack_start( $label, 0, 0, 0 );
		$box->set_style($styles{default});
		$label->show();
	}

	$widgets->{mainbox}->pack_start($box, 1, 1, 0);
	$box->show;
}

sub header {
	my $title = shift;
	my $pixmap = shift;
	my $menu = shift;

	my $hstyle = $styles{default}->copy();
	$hstyle->font($fonts{header});
	foreach (@states) {
		$hstyle->fg($_, $colors{header});
	}

	# create a hbox
	my $header = new Gtk::HBox(0,0);
	$header->set_style($hstyle);

	# create a vbox
	my $vbox = new Gtk::VBox(0,0);

	my $label = new Gtk::Label(&i18n($title));
#	$label->set_shadow_type('none');
	$label->set_style($hstyle);
	$label->set_alignment( 0, 0 );
	$label->set_justify('left');
#	$frame->set_label($title);
	my $texth = ($menu) ? 20 : 48;
	$label->set_usize( 0, $texth ); 

	# Create a textbox		
#	my $text = new Gtk::Text(undef,undef);
#	$text->set_editable( 0 );
#	my $texth = ($menu) ? 20 : 48;
#	$text->set_usize( 0, $texth ); 
#	$text->set_sensitive(0);
#	$text->insert( $fonts{header}, $colors{header}, $colors{headerbg}, $title ); 	
#	$text->set_relief('none');
#	$text->set_style($styles{default});
#	$text->show;

#	$frame->add($text);
	$vbox->pack_start($label, 1, 1, 0);
	$label->show;
	$vbox->show;

	# optional bar with menu / functions
	if ($menu) {
		if (ref ($menu) && $menu->get_name =~ /Gtk/) {
			$menu->set_style($styles{default});
			$vbox->pack_start( $menu, 0, 0, 0);
			$menu->show;
		} else {
			print "Warning: Menu $menu is not a Gtk Widget\n";
		}
	}


	$header->pack_start($vbox, 1, 1, 0);

	if ($pixmap) {
		# my $pix = &createpixmap($widgets->{window}, $pixmap);
		my $pix = &createpixmap($pixmap);
		if ($pix) {
			$header->pack_end($pix, 0, 0, 5);
			$pix->show;
		}
	}
	$header->show;

	return $header;
}



sub popup_menu {
	my ($items, $x, $y) = @_;

#	print "Should show a menu now! at $x $y";

	my $menu = new Gtk::Menu();

	foreach (@{$items}) {
		# Create the menu items
		my $item = new Gtk::MenuItem( &i18n($_->{label}) );
		# Add them to the menu
		$menu->append( $item );

		if ($_->{callback}) {
			# Attach the callback functions to the activate signal
			$item->signal_connect( 'activate', $_->{callback});
		}

		if ($_->{active} == 0) {
			$item->set_sensitive(0);
		}
		# We do not need the show the menu, but we do need to show the menu items
		$item->show();
	}

	$menu->show();
	
	my $func = sub { print "$x $y\n" if $DEBUG; return ("$x,$y"); };
	$menu->popup(undef, undef, 0, 0, $func);

}


### Create main menu bar
sub create_main_menu {
#	my $widgets->{window} = shift;

	my @tools = (
		{ path		=> "/" . &i18n("Phonebooks"),
		  type		=> '<Branch>' },
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("List Phonebooks"),
		  	  callback	=> \&list_phonebook,
			  accelerator => '<control>P' },
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Load from Phone"),
		  	  callback	=> sub { &load_phonebook(''); },  
			},
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Save on Phone"),
		  	  callback	=> sub { &save_phonebook(''); } 
			},  
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Remove Duplicates"),
		  	  callback	=> sub { &uniq_phonebook(''); },  
			},
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Save as File"),
		  	  callback	=> sub { &save_phonebook_as_file('',''); }, 
			},
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Open File"),
			  callback	=> sub { &load_phonebook_from_file_dialog(''); },  
			},
			{ path		=> "/" . &i18n("Phonebooks") . "/" . &i18n("Load all from Phone"),
			  callback	=> sub { &load_all_phonebooks(''); } 
			},
	);

	my $searchstr = shift || "";
	my $type = shift || "SM";
	my $sortcol = shift || 0;
	my $sorttype = shift || 'ascending';
	my $fromsms = shift;
	my $listtype = shift;


	%available_phonebooks = $scmxx->available_phonebooks() if $prefs{phonetype}; #  unless %available_phonebooks;
	if (%available_phonebooks) {
		my @recordtypes = qw( MC MS LD DC MD SD RC CD ON OW BD BL MB);
		push @tools,	{ path		=> "/" . &i18n("Records"),
			  type		=> '<Branch>' };
		foreach my $i (@recordtypes) {
			next unless $available_phonebooks{$i};
			push @tools,	
			{ path		=> "/" . &i18n("Records") . "/" . &i18n("pb_$i"),
			  callback	=> sub { &list_phonebook('', $i, 0, '', '', 'Records'); } };
		}
	}

	if ($phonedefs{'SMS storages'}) {
		push @tools, 
		{ path		=> "/" . &i18n("SMS"),
		  type		=> '<Branch>' },
			{ path		=> "/" . &i18n("SMS") . "/" . &i18n("List SMS"),
		  	  callback	=> \&list_sms,
			  accelerator => '<control>S' },
			{ path		=>  "/" . &i18n("SMS") . "/" . &i18n("Send SMS"),
		  	  callback	=> sub { &sendsms_form(); } };
	}	
	if ($phonedefs{slots}->{vcf} || -e "$ENV{HOME}/.gscmxx/addressbook.cache") {
		push @tools, 
		{ path      => "/" . &i18n("Addressbook"),
		  type		=> '<Branch>' },
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("List Addressbook"),
              callback  => \&list_addressbook,
			  accelerator => '<control>A' 
			},
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("Load from Phone"),
			  callback  => \&load_addressbook,
			},
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("Save on Phone"),
		  	  callback	=> \&save_addressbook 
			},
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("Save as File"),
			  callback  => \&save_addressbook_as_file,
			},
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("Import File") . " (" . &i18n("append items") . ")",
			  callback  => sub { &load_addressbook_from_file_dialog('append'); },
			},
			{ path		=> "/" . &i18n("Addressbook") . "/" . &i18n("Restore from File") . " (" . &i18n("overwrite items") . ")",
			  callback  => sub { &load_addressbook_from_file_dialog(''); },
			}
		
	}
	if ($phonedefs{slots}->{bmp} || $phonedefs{slots}->{mid}) {
		push @tools, 
		{ path      => "/" . &i18n("Multimedia"),
		  type		=> '<Branch>' };
		if ($phonedefs{slots}->{bmp}) {
			push @tools, 
			{ path		=> "/" . &i18n("Multimedia") . "/" . &i18n("Bitmaps"),
              callback  => \&list_bitmaps,
			  accelerator => '<control>B' 
			};
		}
		if ($phonedefs{slots}->{mid}) {
			push @tools, 
			{ path		=> "/" . &i18n("Multimedia") . "/" . &i18n("Ringtones"),
              callback  => \&list_sounds,
			  accelerator => '<control>R' 
			};
		}
	}
#
#	push @tools, { path		=> '_Bitmaps',
#		  	  callback	=> \&list_bitmaps,
#			  accelerator => '<control>B' },
#			{ path		=> '/Tools/_Ringtones',
#		  	  callback	=> \&list_sounds,
#			  accelerator => '<control>M' };

	my @menu_items = ( 
		{ path	=> "/" . &i18n("File"),
		  type	=> '<Branch>' },
			{ path		=> "/" . &i18n("File") . "/" . &i18n("About your Phone"),
			  callback	=> \&show_information ,
			  accelerator => '<control>I' },
			{ path		=> "/" . &i18n("File") . "/" . &i18n("Reset Phone"),
			  callback	=> \&reset_phone },
			{ path		=> "/" . &i18n("File") . "/" . &i18n("Quit"),
			  callback	=> \&CloseAppWindow,
			  accelerator => '<control>Q' 
			},

			@tools,

		{ path	=> "/" . &i18n("Settings"),
		  type	=> '<Branch>' },
			{ path		=> "/" . &i18n("Settings") . "/" . &i18n("Edit Preferences"),
			  callback	=> \&show_preferences },
			{ path		=> "/" . &i18n("Settings") . "/" . &i18n("Language"),
			  type		=> '<Branch>'},
		{ path	=> "/" . &i18n("Help"),
		  type	=> '<LastBranch>' },
			{ path		=> "/" . &i18n("Help") . "/" . &i18n("About"),
			  callback	=> \&aboutgscmxx },
	);

#			{ path		=> "/" . &i18n("Help") . "/" . &i18n("Use DEBUG"),
#			  callback	=> sub { $scmxx->setdebug(1); } }
	my $accel_group = new Gtk::AccelGroup();

	# This function initializes the item factory.
	# Param 1: The type of menu - can be 'Gtk::MenuBar', 'Gtk::Menu',
	#          or 'Gtk::OptionMenu'.
	# Param 2: The path of the menu.
	# Param 3: The accelerator group.  The item factory sets up
	#          the accelerator table while generating menus.
	$widgets->{mainmenu} = new Gtk::ItemFactory('Gtk::MenuBar',
											'<main>',
											$accel_group );

	# This function generates the menu items. Pass the item factory,
	# the number of items in the array, the array itself, and any
	# callback data for the the menu items.
	$widgets->{mainmenu}->create_items( @menu_items );

	# Attach the new accelerator group to the window.
	$widgets->{window}->add_accel_group( $accel_group );

	my $langmenu = $widgets->{mainmenu}->get_widget("/" . &i18n("Settings") . "/" . &i18n("Language"));

	## create radio menu items for languages (didn't work with itmefactory ???)
	@languages = &find_lang_files() unless @languages;
	my $ln = 0;
	my $group;
	my %langitems;
	foreach my $l(@languages) {
		# Construct a GtkRadioMenuItem
		my $item;
		if ($ln == 0) {
			$item = new Gtk::RadioMenuItem(&i18n($l) || $l);
			$group = $item;
		} else {
			$item = new Gtk::RadioMenuItem( ( &i18n($l) || $l ), $group);
		}
		my $state = ($l eq $prefs{language}) ? 1 : 0;
		$item->set_state( $state );
		$item->set_show_toggle( 1 );
		$langmenu->append($item);
		$item->show;
		$langitems{$l} = $item;
		$ln++;
	}
	foreach my $l (keys %langitems) {
		$langitems{$l}->signal_connect('activate', sub { &set_language($l); });
	}

	# Finally, return the actual menu bar created by the item factory.
	#*menubar = gtk_item_factory_get_widget (item_factory, "&lt;main>");
	return ( $widgets->{mainmenu}->get_widget( '<main>' ) );
}

sub reset_main_menu {
	my @insensitive = (
		"/" . &i18n("Phonebooks") . "/" . &i18n("Save on Phone"),
		"/" . &i18n("Phonebooks") . "/" . &i18n("Load from Phone"),
		"/" . &i18n("Phonebooks") . "/" . &i18n("Remove Duplicates"),
		"/" . &i18n("Phonebooks") . "/" . &i18n("Save as File"),
		"/" . &i18n("Phonebooks") . "/" . &i18n("Open File"),
		"/" . &i18n("Phonebooks") . "/" . &i18n("Load all from Phone"),
		"/" . &i18n("Addressbook") . "/" . &i18n("Save on Phone"),
		"/" . &i18n("Addressbook") . "/" . &i18n("Save as File"),
		"/" . &i18n("Addressbook") . "/" . &i18n("Import File") . " (" . &i18n("append items") . ")",
		"/" . &i18n("Addressbook") . "/" . &i18n("Restore from File") . " (" . &i18n("overwrite items") . ")"
	);
#		"/" . &i18n("Addressbook") . "/" . &i18n("Load from Phone"),
	my $ab = &i18n("Addressbook");
	@insensitive = grep !/$ab/, @insensitive unless ($phonedefs{slots}->{vcf} || -e "$ENV{HOME}/.gscmxx/addressbook.cache");
	foreach (@insensitive) {
		my $menuitem = $widgets->{mainmenu}->get_widget($_);
		$menuitem->set_sensitive( 0 ) if ($menuitem); 
	}
}

sub show_main_menu_items {
	foreach (@_) {
		print "Show Menu Item: $_\n" if $DEBUG > 1;
		my $menuitem = $widgets->{mainmenu}->get_widget($_);
		$menuitem->set_sensitive( 1 ) if ($menuitem); 
	}
}
sub create_pic_menu {

	my $ebox = new Gtk::EventBox();
	$ebox->set_style($styles{picnavig});
	$ebox->set_usize(100,0);
	my $box = new Gtk::VBox(0,0);
#	$box->set_style($styles{picnavig});

	my @buttons;
	push @buttons, ['Phonebooks', \&list_phonebook, 'phonebook.xpm', 'vert', 'List Phonebooks'];
	push @buttons, ['Addressbook', \&list_addressbook, 'addressbook.xpm', 'vert', 'List Addressbook'] if ($phonedefs{slots}->{vcf} || -e "$ENV{HOME}/.gscmxx/addressbook.cache");
	push @buttons, ['SMS', \&list_sms, 'sms.xpm', 'vert', 'List SMS'] if ($phonedefs{'SMS storages'});
	push @buttons, ['Bitmaps', \&list_bitmaps, 'bitmap.xpm', 'vert', 'Show Bitmaps'] if ($phonedefs{slots}->{bmp});
	push @buttons, ['Ringtones', \&list_sounds, 'sound.xpm', 'vert', 'List Ringtones'] if ($phonedefs{slots}->{mid});
	push @buttons, ['Preferences', \&show_preferences, 'preferences.xpm', 'vert', 'Edit Preferences'];
	foreach (@buttons) {
		my $button = create_pixmap_button(@{$_}, $styles{picnavig});
		$box->pack_start( $button, 0, 0, 0 );
	}

	if (!$prefs{phonetype}) {
		my $label = new Gtk::Label(&i18n("Sorry\\nno phone\\navailable!") . "\n");
		$label->set_justify('center');
		$box->pack_end( $label, 0, 0, 0);
		$label->show;
	}
	$box->show;
	$ebox->add($box);
	$ebox->show;
	
	return $ebox
}

# 'Please wait while ... '
sub waitscreen {
	my $title = shift;
	my $pixmap = shift;
	my $save = shift || "";
	my $duration = shift || "seconds";

	&clean_main_box;
	my $infobox = new Gtk::VBox(0,5);
#	$infobox->border_width( 5 );

	my $header = &header($title, $pixmap);

	$infobox->pack_start( $header, 0, 0, 0 );

#	my $label = new Gtk::Label($title);
#	$label->set_alignment( 0, 0 );
#	$infobox->pack_start( $label, 0, 0, 0 );
#	$label->show();

	# Create a centering alignment object
	my $align = new Gtk::Alignment( 0.5, 0.5, 0, 0 );
	$infobox->pack_start( $align, 0, 0, 10 );
	$align->show();

	# Create a Adjusment object to hold the range of the progress bar
	my $adj = new Gtk::Adjustment( 0, 1, 100, 0, 0, 0 );

	# Create the GtkProgressBar using the adjustment
	$widgets->{pbar} = new_with_adjustment Gtk::ProgressBar( $adj );

	# Set the format of the string that can be displayed in the
	# trough of the progress bar:
	#   %p - percentage
	#   %v - value
	#   %l - lower range value
	#   %u - upper range value
	#$widgets->{pbar}->set_format_string( "%v from [%l-%u] (=%p%%)" );
	$widgets->{pbar}->set_activity_mode(1);
	$align->add( $widgets->{pbar} );
	$widgets->{pbar}->show();

	# Add a timer callback to update the value of the progress bar
	my $timer = Gtk->timeout_add( 150, \&progress_timeout );

	my $text;
	if ($save eq "save") {
		$text = new Gtk::Label("\n" . &i18n("Please wait while saving") . " " . &i18n($title) . " " . &i18n("Please_wait_while_saving2") . "...\n\n" . &i18n("This may take some $duration..."));
	} elsif ($save eq "delete") {
		$text = new Gtk::Label("\n" . &i18n("Please wait while deleting") . " " . &i18n($title) . " " . &i18n("Please_wait_while_deleting2") . "...\n\n" . &i18n("This may take some $duration..."));
	} else {
		$text = new Gtk::Label("\n" . &i18n("Please wait while fetching") . " " . &i18n($title) . " " . &i18n("Please_wait_while_fetching2") . "...\n\n" . &i18n("This may take some $duration..."));
	}
	$text->set_line_wrap(1);
#	$text->set_alignment( 0, 0 );
#	$text->set_justify( 'left' );

	$infobox->pack_start( $text, 1, 1, 0 );
	$text->show();

	$widgets->{mainbox}->pack_start( $infobox,0,0,0 );
	$infobox->show();
	$widgets->{window}->show();
   	while (Gtk->events_pending) {
   	    Gtk->main_iteration
   	}

}


# Timer callback to update the progress bar.

sub progress_timeout {

	my $new_val;
	my $adj;

	# Calculate the value of the progress bar using the
	# value range set in the adjustment object

	$new_val = $widgets->{pbar}->get_value() + 1;
	$adj = $widgets->{pbar}->adjustment;
	$new_val = $adj->lower if ( $new_val > $adj->upper );

	# Set the new value
	$widgets->{pbar}->set_value( $new_val );

	# As this is a timeout function, return TRUE so that it
	# continues to get called
	return ( 1 );
}


sub warndialog {
	my $text = shift;

 	my $dialog = new Gtk::Dialog(); 
	$dialog->set_modal(1);
	$dialog->set_style($styles{default});
	$dialog->border_width(10); 
	my $label = new Gtk::Label($text);
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $button = new Gtk::Button( "OK" );
   	$button->signal_connect( "clicked", sub { $dialog->destroy(); } );

	$dialog->action_area->pack_start( $button, 1, 1, 0 );
	$button->show();
	$dialog->show();
}

sub errorscreen {

	my $title = shift;
	my $error = shift;

	$currentscreen = sub { &errorscreen($title, $error); };

	&clean_main_box;

	my $content = new Gtk::EventBox();
	$content->set_style($styles{default});

	my $hbox = new Gtk::HBox();

	my $text = new Gtk::Text;
	$text->insert(undef,undef,undef,$error);
#	$text->set_alignment( 0, 0 );
#	$text->set_justify( 'left' );
#	$text->set_sensitive( 1 ); 
#	$text->can_focus(1 );
#	$text->set_selectable( 1 );
	
	$text->show();
	$hbox->pack_start( $text, 1, 1, 0 );

	my $vscrollbar = new Gtk::VScrollbar( $text->vadj );
	$vscrollbar->show();
	$hbox->pack_start( $vscrollbar, 0, 0, 0 );

	$hbox->show();	
	$content->add($hbox);

	# buttons
	my $footer = new Gtk::HBox(0,5);
	my $prefs = new Gtk::Button(&i18n("Edit Preferences"));
	$prefs->signal_connect( "clicked", \&show_preferences );
	$footer->pack_start( $prefs, 0, 0, 0 );
	$prefs->show();


	&mainscreen(HEADER => $title . " - ERROR",
			ICON => 'error.xpm',
			CONTENT => $content,
			SCROLLEDWIN => 0,
			FOOTER => $footer);
}



# splashscreen with logo 
sub splashscreen {
#	my $txt = shift || "";

	return if $cmdactive;
	$currentscreen = sub { splashscreen(@_); };

	&clean_main_box;

	my $pixmap = &gscmxxpixmap($widgets->{window});
	if ($pixmap->get_name() eq "GtkText") {
		$widgets->{mainbox}->pack_start($pixmap, 0, 0, 10);
	} else {
		$widgets->{mainbox}->pack_start($pixmap, 1, 1, 10);
	}

    while (Gtk->events_pending) {
        Gtk->main_iteration
    }

	my $txt;

#	$prefs{phonetype} = &detect_phone;

	if ($prefs{phonetype}) {
		$txt = &i18n("Detected a") . " $prefs{phonetype}.\n";
	} else {
		$txt = &i18n("Sorry, no phone detected.") . "\n" . &i18n("Please check the preferences.") . "\n";
	}
	if ($txt && !ref ($txt)) {
		my $text = new Gtk::Label($txt);
		$widgets->{mainbox}->pack_start( $text, 0, 0, 0 );
		$text->show;
	}
}

# about screen 
sub aboutgscmxx {

	return if $cmdactive;
	$currentscreen = sub { &aboutgscmxx(@_) };

	&clean_main_box;
	my $about = new Gtk::VBox(0,0);

	my $pixmap = &gscmxxpixmap($widgets->{window});
	$about->pack_start($pixmap, 1,0,0);

	my $abouttxt = qq|gscmxx is a gtk-frontend for SIEMENS mobile phones  

it is written in perl and uses gtk.

more information and downloads are available at http://gscmxx.sourceforge.net

you will need scmxx (a commandline tool)! you can find it at http://www.hendrik-sattler.de/scmxx/

CAUTION - NO WARRANTY AT ALL!!!
(everything is tested only with a S45)
|;
	my $box = new Gtk::EventBox();
	$box->set_style($styles{default});

	my $text = new Gtk::Label($abouttxt);
#	$text->set_alignment( 0, 0 );
#	$text->set_justify( 'center' );
	$text->set_line_wrap(1);
	$box->add($text);
	$about->pack_start( $box, 1, 1, 0 );
	$text->show();
	$box->show;
	$about->show();

	$widgets->{mainbox}->add($about);	
#	&mainscreen(HEADER => 'About gscmxx',
#			ICON => 'gscmxx.xpm',
#			CONTENT => $about,
#			FOOTER => '');

#	my $button = new Gtk::Button("http://weirdoz.net/gscmxx/");
#	$button->signal_connect( "clicked", \&goto_gscmxxweb );
#	$widgets->{mainbox}->pack_start( $button, 0, 0, 0 );
#	$button->show();


}

# get pixmap for splash and about screen
sub gscmxxpixmap {
	my $window = shift;
	my $pixmapfile = &findpixmap("gscmxx.xpm"); 
	my $pixmap;
	if (-e $pixmapfile) {
	    my ($p,$m) = Gtk::Gdk::Pixmap->create_from_xpm($window->window,$window->style->bg('normal'),$pixmapfile);
	    $pixmap = new Gtk::Pixmap($p,$m);
	} else {
		# no pixmap -> use ascii art
		my $logo = qq|
         M"""M M""" M""""" M"""M"""M "o o" "o o"
         M   M """M M      M   M   M  o"o   o"o
         """"M """" """""" "   "   " "   " "   "
             M            a frontend for siemens
          """"                     mobile phones 


             (c) 2002 koppi\@weirdoz.net
|;

		# Get the system color map and allocate the color red
		my $cmap = Gtk::Gdk::Colormap->get_system();
		my $color;
		$color->{'red'} = 0xeeee;
		$color->{'green'} = 0;
		$color->{'blue'} = 0;
		my $text = new Gtk::Text(undef,undef);
		$text->set_editable( 0 );
		my $name = "-misc-fixed-medium-r-normal-*-*-120-*-*-c-*-koi8-r";
		my $fixed_font = Gtk::Gdk::Font->load( $name );


		$text->insert( $fixed_font, $color, undef, $logo ); 	
		$pixmap = $text;
	}
	$pixmap->show();
	return $pixmap;
}

##################################################
# HELP FUNCTIONS
##################################################

# send a cmd to scmxx and receive result
sub docmd {

	print "***  No used anymore PLEASE use SCMxx.pm!!! ****\n";
	return;
}

# try to reset the phone
sub reset_phone {
	my $from = shift;
	return if $cmdactive;
	$cmdactive = 1;
	my $result = $scmxx->reset();
	$cmdactive = 0;

	$SCMxx::infotxt = "";
	@mobileinfo = ();
	%phonebooks = ();
	%addressbook = ();
	%sms = ();

#	$prefs{phonetype} = &detect_phone;
	&mainwindow();
	&{$currentscreen};
}

sub detect_phone {
	return if $cmdactive;
	print "Trying to detect phone ...\n" if $DEBUG;
	undef %phonedefs;
	my ($error, $phonedefs) = $scmxx->phonedefs;
	return "" if ($error);
	%phonedefs = %{$phonedefs};
	if ($phonedefs{Vendor} || $phonedefs{Model}) {
		print "Found: $phonedefs{Vendor} $phonedefs{Model}\n" if $DEBUG;
		$phonedefs{Vendor} ||= "SIEMENS";
		return ("$phonedefs{Vendor} $phonedefs{Model}");
	} else {
		return "";
	}
}

# format vcard date to be human readable  (german version)
sub readable_date {
	my $date = shift;
	return "" unless $date;
	my @d = split (//, $date);
	return sprintf("%d%d.%d%d.%d%d%d%d %d%d:%d%d", @d[6,7,4,5,0,1,2,3,9,10,11,12]);	
}

# destroy all childs (expet the main menu) of the main vbox
sub clean_main_box {
	my @childs = $widgets->{mainbox}->children();
	foreach (0..$#childs) {
		my $w = $childs[$_]->widget();
		$w->destroy();
#		$w->hide();
	}
}

# try to find a pixmap
sub findpixmap {
	my $pix = shift;
	my @pathes = (
		$ENV{HOME} . "/.gscmxx",
		$ENV{HOME} . "/share/pixmaps/gscmxx",
		"/usr/share/pixmaps/gscmxx",
		"/usr/local/share/pixmaps/gscmxx",
		"/usr/share/pixmaps",
		"/usr/local/share/pixmaps",
		$FindBin::Bin . "/pixmaps",
		$FindBin::Bin . "/../share/pixmaps/gscmxx",
		"PREFIX/share/pixmaps",
		"../pixmaps", 
		"./pixmaps"
	);
	foreach (@pathes) {
		if (-d $_ && -e "$_/$pix") {
			return "$_/$pix";
		}
	}
	return 0;
}

sub createpixmap {
#	my $widgets->{window} = shift;
#	print "Window: $widgets->{window}\n" if $DEBUG;
	my $pix = shift;
	return unless $pix;
#	if ($pixmaps{$pix}) {
#		print "Have pixmap $pix : $pixmaps{$pix}\n";;
#		return $pixmaps{$pix};
#	} else {
		my $file = &findpixmap($pix);
		return unless $file;
		return unless -e $file;
#		print "Found file: $file\n" if $DEBUG;
	    my ($p,$m) = Gtk::Gdk::Pixmap->create_from_xpm($widgets->{window}->window,$widgets->{window}->style->bg('normal'),$file);
	    my $pixmap = new Gtk::Pixmap($p,$m);
		$pixmaps{$pix} = $pixmap;
		return $pixmap;
#	}
}

sub create_pixmap_button {
	my ($labeltext, $signal, $pixmapfile, $orientation, $tooltip, $butstyle) = @_;
	$orientation ||= "vert";
	$butstyle ||= $styles{default};
	my $button = new Gtk::Button();
	if ($signal) {
		$button->signal_connect( "clicked", $signal );
	}
	my $buttonbox;
	if ($orientation eq "vert") {
		$buttonbox = new Gtk::VBox(0,0);
	} else {
		$buttonbox = new Gtk::HBox(0,0);
	}
	if ($pixmapfile) {
		#my $pixmap = &createpixmap($widgets->{window}, $pixmapfile); 
		my $pixmap = &createpixmap($pixmapfile); 
		if ($pixmap) {
			$buttonbox->pack_start($pixmap, 1, 1, 0);
			$pixmap->set_style($butstyle);
			$pixmap->show;
		}
	}
	if ($labeltext) {
		my $label = new Gtk::Label(&i18n($labeltext));
		$buttonbox->pack_start($label, 1, 1, 0);
		$label->show;
		$label->set_style($butstyle);
	}
	$button->add($buttonbox);
	$buttonbox->show;
	$buttonbox->set_style($butstyle);
	$button->set_relief('none');
	$button->set_style($butstyle);
	if ($tooltip) {
		my $tip = new Gtk::Tooltips();
		$tip->set_tip( $button, &i18n($tooltip), "" );
		$tip->enable(); 
	}
	$button->show;

	return $button;
}

sub setstyles {
	# layout specific parameters
	$fontnames{header} = "-adobe-helvetica-bold-r-normal-*-*-140-*-*-p-*-iso8859-1";

	$colordefinitions{background} = [65000, 65000, 65000];
	$colordefinitions{header} = [0, 0, 0];
	$colordefinitions{headerbg} = [65000,65000,65000];
	$colordefinitions{row0} = [60000,60000,60000];
	$colordefinitions{picnavig} = [40000,40000,40000];


	# fonts
	# "-misc-fixed-bold-r-normal-*-*-140-*-*-c-*-iso8859-19";
	foreach (keys %fontnames) {
		if (my $font =  Gtk::Gdk::Font->load( $fontnames{$_} ) ) {
			$fonts{$_} = $font;
		} else {
			# foundry - family - weight - slant - set_width - add_style - pxl - pt - resX - rexY - spacing - avg.w. - charset
			my @fp = split (/-/, $fontnames{$_}, 13);
#			print Dumper(\@fp) if $DEBUG > 5;
			my $fontname = "-misc-fixed-$fp[3]-r-normal-*-*-$fp[8]-*-*-c-*-iso8859-1";
			print "Font $fontnames{$_} not found. Using Font: $fontname\n" if $DEBUG;
			$fonts{$_} = Gtk::Gdk::Font->load( $fontname ); 
		}
	}

	# colors
	# Get the system color map and allocate the color red
	my $cmap = Gtk::Gdk::Colormap->get_system();
	foreach (keys %colordefinitions) {
		my $color;
		$color->{'red'} = $colordefinitions{$_}->[0];
		$color->{'green'} = $colordefinitions{$_}->[1];;
		$color->{'blue'} = $colordefinitions{$_}->[2];;
		$colors{$_} = $color;
	}


	@states = qw(normal insensitive active prelight);
	$styles{default} = new Gtk::Style;
	foreach (@states) {
		$styles{default}->base($_, $colors{background});
		$styles{default}->bg($_, $colors{background});
		$styles{default}->text($_, $colors{background});
		$styles{default}->light($_, $colors{background});
		$styles{default}->mid($_, $colors{background});
		$styles{default}->dark($_, $colors{background});
	};

	# style of alternate rows
	$styles{row0} = new Gtk::Style;
	foreach (@states) {
		$styles{row0}->base($_, $colors{row0});
		$styles{row0}->bg($_, $colors{row0});
		$styles{row0}->text($_, $colors{row0});
		$styles{row0}->light($_, $colors{row0});
		$styles{row0}->mid($_, $colors{row0});
		$styles{row0}->dark($_, $colors{row0});
	};

	$styles{picnavig} = new Gtk::Style;
	foreach (@states) {
		$styles{picnavig}->base($_, $colors{picnavig});
		$styles{picnavig}->bg($_, $colors{picnavig});
		$styles{picnavig}->text($_, $colors{picnavig});
		$styles{picnavig}->light($_, $colors{picnavig});
		$styles{picnavig}->mid($_, $colors{picnavig});
		$styles{picnavig}->dark($_, $colors{picnavig});
	};


	#$style->font($fonts{header});

	#$style->depth(0);
}

sub check_if_file_exists {
	my $file = shift;

	my $dialog = new Gtk::Dialog(); 
#	$dialog->set_style($styles{default});
	$dialog->set_modal(1);
	$dialog->border_width(10); 

	my $labeltxt = &i18n("File \$file exists");
	$labeltxt =~ s/\$file/$file\n/;
	$labeltxt .= " ";
	$labeltxt .= &i18n("Do you want to overwrite it?");

	my $label = new Gtk::Label($labeltxt);
#	$label->set_line_wrap( 1 );
	$dialog->vbox->pack_start( $label, 1, 1, 10 );
	$label->show();

	my $ok = new Gtk::Button( &i18n("OK") );
	$ok->signal_connect( "clicked", sub { $tmpvals{overwritefile} = 1; $dialog->destroy();  } );
	$dialog->action_area->pack_start( $ok, 1, 1, 0 );
	$ok->show();

	my $cancel = new Gtk::Button( &i18n("Cancel") );
	$cancel->signal_connect( "clicked", sub { $tmpvals{overwritefile} = -1; $dialog->destroy(); } );
	$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
	$cancel->show();

	$dialog->show();
}


sub i18n {
	my $en = shift;

	unless ($i18n) {
		$en =~ s/\\n/\n/g;
		return $en;
		print STDERR "\$i18n is not defined ...\n" if $DEBUG; 
	}
	if (defined $i18n->{$en}) {
		if ($i18n->{$en} eq "''") {
			return "";
		} else {
			return $i18n->{$en};
		}
	} else {
		if ($DEBUG) {
			my ($package, $filename, $line) = caller;
			print STDERR "String '$en' is not translated in lang '$prefs{language}' (called from line $line) ...\n";
		}
		return "$en";
	}
}

# try to find language files
sub find_lang_files {
	my @pathes = (
		$ENV{HOME} . "/.gscmxx/i18n",
		$ENV{HOME} . "/share/gscmxx/i18n",
		"/usr/share/gscmxx/i18n",
		"/usr/local/share/gscmxx/i18n",
		$FindBin::Bin . "../share/gscmxx/i18n",
		$FindBin::Bin . "../share/i18n",
		"PREFIX/share/gscmxx/i18n",
		"../share/i18n", 
		"./share/i18n"
	);
	my %langs;
	foreach my $p(@pathes) {
		if (-d $p ) {
			opendir(DIR, "$p") || warn "Can't open dir $p $!";
			$langs{$_} = 1 foreach grep /^[a-z]+$/, readdir (DIR);
			close (DIR);
		}
	}
	return keys %langs;
}

# find a specific language file
sub find_lang_file {
	my $lang = shift;
	my @pathes = (
		$ENV{HOME} . "/.gscmxx/i18n",
		$ENV{HOME} . "/share/gscmxx/i18n",
		"/usr/share/gscmxx/i18n",
		"/usr/local/share/gscmxx/i18n",
		$FindBin::Bin . "../share/gscmxx/i18n",
		$FindBin::Bin . "../share/i18n",
		"PREFIX/share/gscmxx/i18n",
		"../share/i18n", 
		"./share/i18n"
	);
	foreach (@pathes) {
		if (-d $_ && -e "$_/$lang") {
			return "$_/$lang";
		}
	}
	return 0;
}

sub read_lang_file {
	my $lang = shift;

	my $langfile = &find_lang_file($lang);

#	print "Lang found : $langfile\n";
	return unless $langfile;

	my %i18n;
	open (LANG, "$langfile") || die "Can't open $langfile";
	while (<LANG>) {
		chomp;
		next if (/^\s*#/);
		next if (/^\s*$/);
		s/\t+\#.*$//;
		my ($en, $trans) = split (/\s*\t+\s*/, $_);
		if (!$trans && $DEBUG) {
			print STDERR "String '$en' is not translated in lang '$prefs{language}' ...\n";
		}
		$trans ||= $en;
		$trans =~ s/\\n/\n/g;
		$i18n{$en} = $trans;
	}
	close (LANG);
	return \%i18n;
}

### Callback function to close the window
sub CloseAppWindow {
	return if ($cmdactive);	

	# save all phonebooks
#	%available_phonebooks = $scmxx->available_phonebooks() if (!%available_phonebooks && $prefs{phonetype});
	foreach (keys %available_phonebooks) {
		if ($phonebooks{$_} && $phonebooks{$_}->{__fetched} && $phonebooks{$_}->{__changed}) { # do not save empty phonebooks
			&do_save_phonebook_as_file("$ENV{HOME}/.gscmxx/pbooks/$_.pbook", '', $_);
		}
	}
	# save addressbook
	if ($addressbook{__fetched} && $addressbook{__changed}) {
		&do_save_addressbook_as_file("$ENV{HOME}/.gscmxx/addressbook.cache", '');
	}

	my $rm = "rm -f $ENV{HOME}/.gscmxx/bitmaps/tmp*";
	system($rm);

	Gtk->exit( 0 );
	return 0;
}

__END__
# Below is stub documentation for your module. You better edit it!

=head1 NAME

gscmxx - a  GTK Application for Siemens mobile phones

=head1 SYNOPSIS

gscmxx

=head1 DESCRIPTION

gscmxx is a application to access Siemens mobile phones from your linux desktop

=head1 OPTIONS

No options.

=head1 Known Bugs

On S45 with firmware revision vcards may be saved twice ..

=head1 AUTHOR

koppi <koppi@weirdoz.net>

=cut
