#!/usr/bin/perl
#
# run iphonenote --help for usage
#
# Source http://www.perlmonks.org/?node_id=851322
# This version at http://daniel-lange.com/archives/64-Creating-iPhoneiPodiPad-notes-from-the-shell.html
# DL120201 changed for local use :)
# DL120204 added --list, utf8 handling
#
# $Id: iphonenote.pl 32 2011-02-22 04:26:00Z hossman $
#

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;

use Data::UUID;

use Mail::Message;
use Mail::Box::Manager;

use constant SUBJ_HEADER => 'Subject';
use constant UUID_HEADER => 'X-Universally-Unique-Identifier';
use constant TYPE_HEADER => 'X-Uniform-Type-Identifier';
use constant TYPE_VALUE  => 'com.apple.mail-note';

my %folder_opts = ('access'=>'rw');
my $foldername = "Notes";
my $msg = undef;
my $uuid = undef;
my $help = 0;
my $gmail = 0;
my $hosteurope = 0;
my $create = 0;
my $modify = 0;
my $delete = 0;
my $list = 0;

#binmode STDIN, ":utf8";
#binmode STDOUT, ":utf8";

sub trim($)
{
	my $string = shift;
	$string =~ s/^\s+//;
	$string =~ s/\s+$//;
	$string =~ s/\t/ /g;
	utf8::decode($string);
	return $string;
}

sub numformat($)
{
        my $string = shift;
	$string =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1\./g;
	return $string;
}

GetOptions('help|usage|?' => \$help, 
	   'folder|f=s'   => \$foldername,
	   'opt|opts=s%'  => \%folder_opts,
	   'uuid|u=s'     => \$uuid,
	   'create|c'     => \$create,
	   'modify|m'     => \$modify,
	   'delete|d'     => \$delete,
	   'list|l'	  => \$list,
	   'gmail|g'      => \$gmail,
	   'hosteurope|he' => \$hosteurope,
    ) or pod2usage(2);

pod2usage(1) if $help;

if ($gmail) {
    $foldername = 'Notes';
    $folder_opts{'server_name'} = 'imap.gmail.com';
    $folder_opts{'type'} = 'imaps';
}

if ($hosteurope) {
    $foldername = 'Notes';
    $folder_opts{'server_name'} = 'yourserver.hosteurope.de';
    $folder_opts{'type'} = 'imaps';
    $folder_opts{'username'} = 'the_username_goes_here' unless defined $folder_opts{'username'};
    $folder_opts{'password'} = 's3cr3t' unless defined $folder_opts{'password'};
}

pod2usage("Can not use more then one of --list, --create, --modify, --delete")
    if (1 < $list + $create + $modify + $delete);
pod2usage("Must specify one of --list, --create, --modify, --delete")
    if (0 == $list + $create + $modify + $delete);
pod2usage("must specify a --uuid to use --modify or --delete")
    unless (($create or $list) or defined $uuid);

my $mgr = Mail::Box::Manager->new;

# really wish Mail::Box impls registered themselves by default
if (exists $folder_opts{'type'} and $folder_opts{'type'} eq 'imaps') {
    $mgr->registerType('imaps' => 'Mail::Box::IMAP4::SSL');
}

my $folder = $mgr->open($foldername, %folder_opts)
    or die "Can't open folder: $foldername\n";

if ($list) {
foreach $msg ($folder->messages) { # all messages
    printf "%-40s %-36s %-40s [%11s bytes]\n", $msg->head->get(UUID_HEADER()), $msg->head->get('Date'), trim($msg->subject), numformat($msg->size());
    }
}

if ($modify or $delete) {
    # find the existing message

    # Ugh, gmail doesn't seem to support whatever Mail::Box::Search::Grep
    # tries to do to find messages with a specific header name=val
    my @matches = 
	grep { $_->head->get(UUID_HEADER()) eq $uuid } $folder->messages();

    my $num = scalar @matches;
    if (1 < $num) {
	die "Found too many messages: $num";
    } elsif ($num < 1) {
	die "Didn't find any matches";
    } 
    
    # delete now, add a new one later
    $matches[0]->delete();
}


if ($create or $modify) {
    # create the "new" message

    $uuid = Data::UUID->new()->create_str()
	unless defined $uuid;
    my @lines = <STDIN>;
# depending on your local utf8 brokenness you may want to uncomment the following lines if you work with non-English characters
#    foreach (@lines) {
#	utf8::encode($_);
#    }
    my $subject = $lines[0];
    chomp $subject;
    utf8::encode($subject);

    my $msg = Mail::Message->build
	( UUID_HEADER() => $uuid,
	  TYPE_HEADER() => TYPE_VALUE,
	  SUBJ_HEADER() => $subject,
	  'data' => \@lines,
	);
    $mgr->appendMessage($folder, $msg);
    $folder->close();
    $mgr->close();
}

__END__

=head1 NAME

iphonenote - Manipulate iPhone notes in a mail folder

=head1 SYNOPSIS

 iphonenote -c [-u uid] < somefile.txt
 iphonenote -m -u uid   < somefile.txt
 iphonenote -d -u uid
 iphonenote --gmail --opts username=foo@gmail.com --opts password=s3cr3t ...

 Options:
  -h  or --help          Print this help documentation
  -f  or --folder        The Mail::Box::Manager compliant foldername to manipulate
  -u  or --uuid          The UUID of the specific note to manipulate in that folder
  -l  or --list          To list existing notes
  -c  or --create        To create a new note
  -m  or --modify        To modify an existing note (requires --uuid)
  -d  or --delete        To delete an existing note (requires --uuid)
         --opts          key=val pairs of Mail::Box options
  -g  or --gmail         sets default --opts for using gmail
  -he or --hosteurope    sets default --opts for using hosteurope mailer
