summaryrefslogtreecommitdiffstats
path: root/plugins/kmail
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/kmail')
-rw-r--r--plugins/kmail/bodypartformatter/attendeeselector.cpp12
-rw-r--r--plugins/kmail/bodypartformatter/text_calendar.cpp379
-rw-r--r--plugins/kmail/bodypartformatter/text_calendar.desktop2
-rw-r--r--plugins/kmail/bodypartformatter/text_vcard.cpp157
-rw-r--r--plugins/kmail/bodypartformatter/text_vcard.desktop2
-rw-r--r--plugins/kmail/bodypartformatter/text_xdiff.cpp2
-rw-r--r--plugins/kmail/bodypartformatter/text_xdiff.desktop2
7 files changed, 465 insertions, 91 deletions
diff --git a/plugins/kmail/bodypartformatter/attendeeselector.cpp b/plugins/kmail/bodypartformatter/attendeeselector.cpp
index 0ea917bed..8fa677705 100644
--- a/plugins/kmail/bodypartformatter/attendeeselector.cpp
+++ b/plugins/kmail/bodypartformatter/attendeeselector.cpp
@@ -21,6 +21,7 @@
#include "ui_attendeeselector.h"
#include <libkdepim/addresseelineedit.h>
+#include <libemailfunctions/email.h>
#include <klocale.h>
#include <kpushbutton.h>
@@ -51,8 +52,15 @@ AttendeeSelector::AttendeeSelector(TQWidget * parent)
TQStringList AttendeeSelector::attendees() const
{
TQStringList rv;
- for ( uint i = 0; i < ui->attendeeList->count(); ++i )
- rv << ui->attendeeList->item( i )->text();
+ for ( uint i = 0; i < ui->attendeeList->count(); ++i ) {
+ TQString addr = ui->attendeeList->item( i )->text();
+
+ // Build a nice address for this attendee including the CN.
+ TQString tname, temail;
+ KPIM::getNameAndMail( addr, tname, temail ); // ignore return value
+ // which is always false
+ rv << temail;
+ }
return rv;
}
diff --git a/plugins/kmail/bodypartformatter/text_calendar.cpp b/plugins/kmail/bodypartformatter/text_calendar.cpp
index 2ea1cfd52..49b60f5ff 100644
--- a/plugins/kmail/bodypartformatter/text_calendar.cpp
+++ b/plugins/kmail/bodypartformatter/text_calendar.cpp
@@ -38,10 +38,14 @@
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>
+#include <libkdepim/kfileio.h>
+
#include <libkcal/calendarlocal.h>
#include <libkcal/calendarresources.h>
+#include <libkcal/calhelper.h>
#include <libkcal/icalformat.h>
#include <libkcal/attendee.h>
+#include <libkcal/attachmenthandler.h>
#include <libkcal/incidence.h>
#include <libkcal/incidenceformatter.h>
@@ -54,6 +58,7 @@
#include <email.h>
#include <kglobal.h>
+#include <kfiledialog.h>
#include <kinputdialog.h>
#include <klocale.h>
#include <kstringhandler.h>
@@ -65,6 +70,11 @@
#include <kstandarddirs.h>
#include <kapplication.h>
#include <ktempfile.h>
+#include <kmdcodec.h>
+#include <kmimetype.h>
+#include <kpopupmenu.h>
+#include <krun.h>
+#include <kio/netaccess.h>
#include <tqurl.h>
#include <tqdir.h>
@@ -86,10 +96,10 @@ class CalendarManager
public:
CalendarManager();
~CalendarManager();
- static KCal::Calendar* calendar();
+ static Calendar* calendar();
private:
- KCal::CalendarResources* mCalendar;
+ CalendarResources* mCalendar;
static CalendarManager* mSelf;
};
@@ -130,7 +140,7 @@ CalendarManager::~CalendarManager()
mSelf = 0;
}
-KCal::Calendar* CalendarManager::calendar()
+Calendar* CalendarManager::calendar()
{
if ( !mSelf ) {
sCalendarDeleter.setObject( mSelf, new CalendarManager() );
@@ -139,12 +149,12 @@ KCal::Calendar* CalendarManager::calendar()
}
-class KMInvitationFormatterHelper : public KCal::InvitationFormatterHelper
+class KMInvitationFormatterHelper : public InvitationFormatterHelper
{
public:
KMInvitationFormatterHelper( KMail::Interface::BodyPart *bodyPart ) : mBodyPart( bodyPart ) {}
virtual TQString generateLinkURL( const TQString &id ) { return mBodyPart->makeLink( id ); }
- KCal::Calendar* calendar() const { return CalendarManager::calendar(); }
+ Calendar* calendar() const { return CalendarManager::calendar(); }
private:
KMail::Interface::BodyPart *mBodyPart;
};
@@ -153,7 +163,7 @@ class Formatter : public KMail::Interface::BodyPartFormatter
{
public:
Result format( KMail::Interface::BodyPart *bodyPart,
- KMail::HtmlWriter *writer ) const
+ KMail::HtmlWriter *writer, KMail::Callback &callback ) const
{
if ( !writer )
// Guard against crashes in createReply()
@@ -163,14 +173,15 @@ class Formatter : public KMail::Interface::BodyPartFormatter
TQString source;
/* If the bodypart does not have a charset specified, we need to fall back to
utf8, not the KMail fallback encoding, so get the contents as binary and decode
- explicitely. */
+ explicitly. */
if ( bodyPart->contentTypeParameter( "charset").isEmpty() ) {
const TQByteArray &ba = bodyPart->asBinary();
source = TQString::fromUtf8(ba);
} else {
source = bodyPart->asText();
}
- TQString html = IncidenceFormatter::formatICalInvitation( source, &cl, &helper );
+ TQString html =
+ IncidenceFormatter::formatICalInvitationNoHtml( source, &cl, &helper, callback.sender() );
if ( html.isEmpty() ) return AsIcon;
writer->queue( html );
@@ -201,6 +212,25 @@ static TQString directoryForStatus( Attendee::PartStat status )
return dir;
}
+static Incidence *icalToString( const TQString &iCal )
+{
+ CalendarLocal calendar( KPimPrefs::timezone() ) ;
+ ICalFormat format;
+ ScheduleMessage *message =
+ format.parseScheduleMessage( &calendar, iCal );
+ if ( !message )
+ //TODO: Error message?
+ return 0;
+ return dynamic_cast<Incidence*>( message->event() );
+}
+
+static ScheduleMessage *icalToMessage( const TQString &iCal )
+{
+ CalendarLocal calendar( KPimPrefs::timezone() ) ;
+ ICalFormat format;
+ return format.parseScheduleMessage( &calendar, iCal );
+}
+
class UrlHandler : public KMail::Interface::BodyPartURLHandler
{
public:
@@ -209,19 +239,6 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
kdDebug() << "UrlHandler() (iCalendar)" << endl;
}
- Incidence* icalToString( const TQString& iCal ) const
- {
- CalendarLocal calendar( KPimPrefs::timezone() ) ;
- ICalFormat format;
- ScheduleMessage *message =
- format.parseScheduleMessage( &calendar, iCal );
- if ( !message )
- //TODO: Error message?
- return 0;
- return dynamic_cast<Incidence*>( message->event() );
- }
-
-
Attendee *findMyself( Incidence* incidence, const TQString& receiver ) const
{
Attendee::List attendees = incidence->attendees();
@@ -340,6 +357,13 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
break;
}
+ // Set the organizer to the sender, if the ORGANIZER hasn't been set.
+ if ( incidence->organizer().isEmpty() ) {
+ TQString tname, temail;
+ KPIM::getNameAndMail( callback.sender(), tname, temail );
+ incidence->setOrganizer( Person( tname, temail ) );
+ }
+
TQString recv = to;
if ( recv.isEmpty() )
recv = incidence->organizer().fullName();
@@ -347,7 +371,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
return callback.mailICal( recv, msg, subject, statusString, type != Forward );
}
- void ensureKorganizerRunning() const
+ void ensureKorganizerRunning( bool switchTo ) const
{
TQString error;
TQCString dcopService;
@@ -359,6 +383,10 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
TQCString dummy;
if ( !kapp->dcopClient()->findObject( dcopService, dcopObjectId, "", TQByteArray(), dummy, dummy ) ) {
DCOPRef ref( dcopService, dcopService ); // talk to the KUniqueApplication or its kontact wrapper
+ if ( switchTo ) {
+ ref.call( "newInstance()" ); // activate korganizer window
+ }
+
DCOPReply reply = ref.call( "load()" );
if ( reply.isValid() && (bool)reply ) {
kdDebug() << "Loaded " << dcopService << " successfully" << endl;
@@ -390,11 +418,126 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
// Now ensure that korganizer is running; otherwise start it, to prevent surprises
// (https://intevation.de/roundup/kolab/issue758)
- ensureKorganizerRunning();
+ ensureKorganizerRunning( false );
return true;
}
+ bool cancelPastInvites( Incidence *incidence, const TQString &path ) const
+ {
+ TQString warnStr;
+ TQDateTime now = TQDateTime::currentDateTime();
+ TQDate today = now.date();
+ Event * const event = dynamic_cast<Event *>( incidence );
+ Todo * const todo = dynamic_cast<Todo *>( incidence );
+ if ( incidence->type() == "Event" ) {
+ Q_ASSERT( event );
+ if ( !event->doesFloat() ) {
+ if ( event->dtEnd() < now ) {
+ warnStr = i18n( "\"%1\" occurred already." ).arg( event->summary() );
+ } else if ( event->dtStart() <= now && now <= event->dtEnd() ) {
+ warnStr = i18n( "\"%1\" is currently in-progress." ).arg( event->summary() );
+ }
+ } else {
+ if ( event->dtEnd().date() < today ) {
+ warnStr = i18n( "\"%1\" occurred already." ).arg( event->summary() );
+ } else if ( event->dtStart().date() <= today && today <= event->dtEnd().date() ) {
+ warnStr = i18n( "\"%1\", happening all day today, is currently in-progress." ).
+ arg( event->summary() );
+ }
+ }
+ } else if ( incidence->type() == "Todo" ) {
+ Q_ASSERT( todo );
+ if ( !todo->doesFloat() ) {
+ if ( todo->hasDueDate() ) {
+ if ( todo->dtDue() < now ) {
+ warnStr = i18n( "\"%1\" is past due." ).arg( todo->summary() );
+ } else if ( todo->hasStartDate() && todo->dtStart() <= now && now <= todo->dtDue() ) {
+ warnStr = i18n( "\"%1\" is currently in-progress." ).arg( todo->summary() );
+ }
+ } else if ( todo->hasStartDate() ) {
+ if ( todo->dtStart() < now ) {
+ warnStr = i18n( "\"%1\" has already started." ).arg( todo->summary() );
+ }
+ }
+ } else {
+ if ( todo->hasDueDate() ) {
+ if ( todo->dtDue().date() < today) {
+ warnStr = i18n( "\"%1\" is past due." ).arg( todo->summary() );
+ } else if ( todo->hasStartDate() &&
+ todo->dtStart().date() <= today && today <= todo->dtDue().date() ) {
+ warnStr = i18n( "\"%1\", happening all-day today, is currently in-progress." ).
+ arg( todo->summary() );
+ }
+ } else if ( todo->hasStartDate() ) {
+ if ( todo->dtStart().date() < today ) {
+ warnStr = i18n( "\"%1\", happening all day, has already started." ).
+ arg( todo->summary() );
+ }
+ }
+ }
+ }
+
+ if ( !warnStr.isEmpty() ) {
+ TQString queryStr;
+ Q_ASSERT( event || todo );
+ if ( path == "accept" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to accept the invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to accept the task?" );
+ }
+ } else if ( path == "accept_conditionally" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to send conditional acceptance of the invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to send conditional acceptance of the task?" );
+ }
+ } else if ( path == "accept_counter" ) {
+ queryStr = i18n( "Do you still want to accept the counter proposal?" );
+ } else if ( path == "counter" ) {
+ queryStr = i18n( "Do you still want to send a counter proposal?" );
+ } else if ( path == "decline" ) {
+ queryStr = i18n( "Do you still want to send a decline response?" );
+ } else if ( path == "decline_counter" ) {
+ queryStr = i18n( "Do you still want to decline the counter proposal?" );
+ } else if ( path == "reply" ) {
+ queryStr = i18n( "Do you still want to record this reponse in your calendar?" );
+ } else if ( path == "delegate" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to delegate this invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to delegate this task?" );
+ }
+ } else if ( path == "forward" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to forward this invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to forward this task?" );
+ }
+ } else if ( path == "check_calendar" ) {
+ queryStr = i18n( "Do you still want to check your calendar?" );
+ } else if ( path == "record" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to record this invitation in your calendar?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to record this task in your calendar?" );
+ }
+ } else if ( path.startsWith( "ATTACH:" ) ) {
+ return false;
+ } else {
+ queryStr = i18n( "%1?" ).arg( path );
+ }
+
+ if ( KMessageBox::warningYesNo(
+ 0,
+ i18n( "%1\n%2" ).arg( warnStr ).arg( queryStr ) ) == KMessageBox::No ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool handleInvitation( const TQString& iCal, Attendee::PartStat status,
KMail::Callback &callback ) const
{
@@ -405,17 +548,22 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
// Must be some error. Still return true though, since we did handle it
return true;
- // get comment for tentative acceptance
- Incidence* incidence = icalToString( iCal );
+ Incidence *incidence = icalToString( iCal );
+ // get comment for tentative acceptance
if ( callback.askForComment( status ) ) {
bool ok = false;
TQString comment = KInputDialog::getMultiLineText( i18n("Reaction to Invitation"),
i18n("Comment:"), TQString(), &ok );
if ( !ok )
return true;
- if ( !comment.isEmpty() )
- incidence->addComment( comment );
+ if ( !comment.isEmpty() ) {
+ if ( callback.outlookCompatibleInvitationReplyComments() ) {
+ incidence->setDescription( comment );
+ } else {
+ incidence->addComment( comment );
+ }
+ }
}
// First, save it for KOrganizer to handle
@@ -521,7 +669,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
void showCalendar( const TQDate &date ) const
{
- ensureKorganizerRunning();
+ ensureKorganizerRunning( true );
// raise korganizer part in kontact or the korganizer app
kapp->dcopClient()->send( "korganizer", "korganizer", "newInstance()", TQByteArray() );
TQByteArray arg;
@@ -550,13 +698,17 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
Incidence* incidence = icalToString( iCal );
if ( callback.askForComment( Attendee::Declined ) ) {
bool ok = false;
- // ### string freeze
- TQString comment = KInputDialog::getMultiLineText( i18n("Reaction to Invitation") /* i18n("Decline Counter Proposal") */,
+ TQString comment = KInputDialog::getMultiLineText( i18n("Decline Counter Proposal"),
i18n("Comment:"), TQString(), &ok );
if ( !ok )
return true;
- if ( !comment.isEmpty() )
- incidence->addComment( comment );
+ if ( !comment.isEmpty() ) {
+ if ( callback.outlookCompatibleInvitationReplyComments() ) {
+ incidence->setDescription( comment );
+ } else {
+ incidence->addComment( comment );
+ }
+ }
}
return mail( incidence, callback, Attendee::NeedsAction, Scheduler::Declinecounter,
callback.sender(), DeclineCounter );
@@ -576,17 +728,39 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
bool handleClick( KMail::Interface::BodyPart *part,
const TQString &path, KMail::Callback& c ) const
{
+ if ( !CalHelper::hasMyWritableEventsFolders( "calendar" ) ) {
+ KMessageBox::error(
+ 0,
+ i18n( "You have no writable calendar folders for invitations, "
+ "so storing or saving a response will not be possible.\n"
+ "Please create at least 1 writable events calendar and re-sync." ) );
+ return false;
+ }
+
+
+ // If the bodypart does not have a charset specified, we need to fall back to utf8,
+ // not the KMail fallback encoding, so get the contents as binary and decode explicitly.
TQString iCal;
- /* If the bodypart does not have a charset specified, we need to fall back to
- utf8, not the KMail fallback encoding, so get the contents as binary and decode
- explicitely. */
if ( part->contentTypeParameter( "charset").isEmpty() ) {
const TQByteArray &ba = part->asBinary();
iCal = TQString::fromUtf8(ba);
} else {
iCal = part->asText();
}
+ Incidence *incidence = icalToString( iCal );
+ if ( !incidence ) {
+ KMessageBox::sorry(
+ 0,
+ i18n( "The calendar invitation stored in this email message is broken in some way. "
+ "Unable to continue." ) );
+ return false;
+ }
+
bool result = false;
+ if ( cancelPastInvites( incidence, path ) ) {
+ return result;
+ }
+
if ( path == "accept" )
result = handleInvitation( iCal, Attendee::Accepted, c );
if ( path == "accept_conditionally" )
@@ -603,7 +777,6 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
if ( path == "delegate" )
result = handleInvitation( iCal, Attendee::Delegated, c );
if ( path == "forward" ) {
- Incidence* incidence = icalToString( iCal );
AttendeeSelector dlg;
if ( dlg.exec() == TQDialog::Rejected )
return true;
@@ -614,7 +787,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
Scheduler::Request, fwdTo, Forward );
}
if ( path == "check_calendar" ) {
- Incidence* incidence = icalToString( iCal );
+ incidence = icalToString( iCal );
showCalendar( incidence->dtStart().date() );
}
if ( path == "reply" || path == "cancel" || path == "accept_counter" ) {
@@ -626,16 +799,98 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
result = true;
}
}
- if ( result )
- c.closeIfSecondaryWindow();
+ if ( path == "record" ) {
+ incidence = icalToString( iCal );
+
+ int response =
+ KMessageBox::questionYesNoCancel(
+ 0,
+ i18n( "The organizer is not expecting a reply to this invitation "
+ "but you can send them an email message if you desire.\n\n"
+ "Would you like to send the organizer a message regarding this invitation?\n"
+ "Press the [Cancel] button to cancel the recording operation." ),
+ i18n( "Send Email to Organizer" ),
+ KGuiItem( i18n( "Do Not Send" ) ),
+ KGuiItem( i18n( "Send EMail" ) ) );
+
+ TQString summary;
+ switch( response ) {
+ case KMessageBox::Cancel:
+ break;
+ case KMessageBox::No: // means "send email"
+ summary = incidence->summary();
+ if ( !summary.isEmpty() ) {
+ summary = i18n( "Re: %1" ).arg( summary );
+ }
+
+ KApplication::kApplication()->invokeMailer( incidence->organizer().email(), summary );
+ //fall through
+ case KMessageBox::Yes: // means "do not send"
+ if ( saveFile( "Receiver Not Searched", iCal, TQString( "reply" ) ) ) {
+ if ( c.deleteInvitationAfterReply() ) {
+ ( new KMDeleteMsgCommand( c.getMsg()->getMsgSerNum() ) )->start();
+ result = true;
+ }
+ }
+ showCalendar( incidence->dtStart().date() );
+ break;
+ }
+ }
+
+ if ( path == "delete" ) {
+ ( new KMDeleteMsgCommand( c.getMsg()->getMsgSerNum() ) )->start();
+ result = true;
+ }
+
+ if ( path.startsWith( "ATTACH:" ) ) {
+ TQString name = path;
+ name.remove( TQRegExp( "^ATTACH:" ) );
+ result = AttachmentHandler::view( 0, name, icalToMessage( iCal ) );
+ }
+
+ if ( result ) {
+ // do not close the secondary window if an attachment was opened (kolab/issue4317)
+ if ( !path.startsWith( "ATTACH:" ) ) {
+ c.closeIfSecondaryWindow();
+ }
+ }
return result;
}
- bool handleContextMenuRequest( KMail::Interface::BodyPart *,
- const TQString &,
- const TQPoint & ) const
+ bool handleContextMenuRequest( KMail::Interface::BodyPart *part,
+ const TQString &path,
+ const TQPoint &point ) const
{
- return false;
+ TQString name = path;
+ if ( path.startsWith( "ATTACH:" ) ) {
+ name.remove( TQRegExp( "^ATTACH:" ) );
+ } else {
+ return false; //because it isn't an attachment inviation
+ }
+
+ TQString iCal;
+ if ( part->contentTypeParameter( "charset").isEmpty() ) {
+ const TQByteArray &ba = part->asBinary();
+ iCal = TQString::fromUtf8( ba );
+ } else {
+ iCal = part->asText();
+ }
+
+ KPopupMenu *menu = new KPopupMenu();
+ menu->insertItem( i18n( "Open Attachment" ), 0 );
+ menu->insertItem( i18n( "Save Attachment As..." ), 1 );
+
+ switch( menu->exec( point, 0 ) ) {
+ case 0: // open
+ AttachmentHandler::view( 0, name, icalToMessage( iCal ) );
+ break;
+ case 1: // save as
+ AttachmentHandler::saveAs( 0, name, icalToMessage( iCal ) );
+ break;
+ default:
+ break;
+ }
+ return true;
}
TQString statusBarMessage( KMail::Interface::BodyPart *,
@@ -643,31 +898,38 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
{
if ( !path.isEmpty() ) {
if ( path == "accept" )
- return i18n("Accept incidence");
+ return i18n("Accept invitation");
if ( path == "accept_conditionally" )
- return i18n( "Accept incidence conditionally" );
-// ### string freeze
-// if ( path == "accept_counter" )
-// return i18n( "Accept counter proposal" );
+ return i18n( "Accept invitation conditionally" );
+ if ( path == "accept_counter" )
+ return i18n( "Accept counter proposal" );
if ( path == "counter" )
return i18n( "Create a counter proposal..." );
if ( path == "ignore" )
return i18n( "Throw mail away" );
if ( path == "decline" )
- return i18n( "Decline incidence" );
-// ### string freeze
-// if ( path == "decline_counter" )
-// return i18n( "Decline counter proposal" );
+ return i18n( "Decline invitation" );
+ if ( path == "decline_counter" )
+ return i18n( "Decline counter proposal" );
if ( path == "check_calendar" )
return i18n("Check my calendar..." );
if ( path == "reply" )
- return i18n( "Enter incidence into my calendar" );
+ return i18n( "Record response into my calendar" );
+ if ( path == "record" )
+ return i18n( "Record invitation into my calendar" );
+ if ( path == "delete" )
+ return i18n( "Move this invitation to my trash folder" );
if ( path == "delegate" )
- return i18n( "Delegate incidence" );
+ return i18n( "Delegate invitation" );
if ( path == "forward" )
- return i18n( "Forward incidence" );
+ return i18n( "Forward invitation" );
if ( path == "cancel" )
- return i18n( "Remove incidence from my calendar" );
+ return i18n( "Remove invitation from my calendar" );
+ if ( path.startsWith( "ATTACH:" ) ) {
+ TQString name = path;
+ return i18n( "Open attachment \"%1\"" ).
+ arg( name.remove( TQRegExp( "^ATTACH:" ) ) );
+ }
}
return TQString::null;
@@ -679,19 +941,20 @@ class Plugin : public KMail::Interface::BodyPartFormatterPlugin
public:
const KMail::Interface::BodyPartFormatter *bodyPartFormatter( int idx ) const
{
- if ( idx == 0 ) return new Formatter();
+ if ( idx == 0 || idx == 1 ) return new Formatter();
else return 0;
}
const char *type( int idx ) const
{
- if ( idx == 0 ) return "text";
+ if ( idx == 0 || idx == 1 ) return "text";
else return 0;
}
const char *subtype( int idx ) const
{
if ( idx == 0 ) return "calendar";
+ if ( idx == 1 ) return "x-vcalendar";
else return 0;
}
diff --git a/plugins/kmail/bodypartformatter/text_calendar.desktop b/plugins/kmail/bodypartformatter/text_calendar.desktop
index cf2443d30..1321d5835 100644
--- a/plugins/kmail/bodypartformatter/text_calendar.desktop
+++ b/plugins/kmail/bodypartformatter/text_calendar.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -55,7 +54,6 @@ Comment[hu]=Formázómodul text/calendar adatfolyamok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/calendar
Comment[it]=Un plugin per formattare il corpo di text/calendar
Comment[ja]=text/calendar 用の Bodypart フォーマッタ プラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/calendar
Comment[kk]=Text/calendar бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/ប្រតិទិន
Comment[lt]=text/calendar formatavimo priedas
diff --git a/plugins/kmail/bodypartformatter/text_vcard.cpp b/plugins/kmail/bodypartformatter/text_vcard.cpp
index 347371d16..39a4ab28d 100644
--- a/plugins/kmail/bodypartformatter/text_vcard.cpp
+++ b/plugins/kmail/bodypartformatter/text_vcard.cpp
@@ -37,9 +37,15 @@
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
+#include <kfiledialog.h>
#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
-#include <kaddrbook.h>
+
+#include <libkdepim/addresseeview.h>
+#include <libkdepim/kaddrbook.h>
#include "interfaces/bodypartformatter.h"
#include "interfaces/bodypart.h"
@@ -47,6 +53,7 @@ using KMail::Interface::BodyPart;
#include "interfaces/bodyparturlhandler.h"
#include "khtmlparthtmlwriter.h"
#include <kimproxy.h>
+#include <kpopupmenu.h>
#include <kabc/vcardconverter.h>
#include <kabc/addressee.h>
@@ -67,14 +74,18 @@ namespace {
//mKIMProxy = ::KIMProxy::instance( kapp->dcopClient() );
}
- Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {
+ Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer, KMail::Callback & ) const {
if ( !writer ) return AsIcon;
VCardConverter vcc;
const TQString vCard = bodyPart->asText();
if ( vCard.isEmpty() ) return AsIcon;
- Addressee::List al = vcc.parseVCards( vCard );
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
if ( al.empty() ) return AsIcon;
writer->queue (
@@ -111,28 +122,126 @@ namespace {
class UrlHandler : public KMail::Interface::BodyPartURLHandler {
public:
- bool handleClick( BodyPart * bodyPart, const TQString & path,
- KMail::Callback& ) const {
+ bool handleClick( BodyPart * bodyPart, const TQString & path,
+ KMail::Callback& ) const {
- const TQString vCard = bodyPart->asText();
- if ( vCard.isEmpty() ) return true;
- VCardConverter vcc;
- Addressee::List al = vcc.parseVCards( vCard );
- int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
- if ( index == -1 ) return true;
- KABC::Addressee a = al[index];
- if ( a.isEmpty() ) return true;
- KAddrBookExternal::addVCard( a, 0 );
- return true;
- }
-
- bool handleContextMenuRequest( BodyPart *, const TQString &, const TQPoint & ) const {
- return false;
- }
-
- TQString statusBarMessage( BodyPart *, const TQString & ) const {
- return i18n("Add this contact to the address book.");
- }
+ const TQString vCard = bodyPart->asText();
+ if ( vCard.isEmpty() ) return true;
+ VCardConverter vcc;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
+ int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
+ if ( index == -1 ) return true;
+ KABC::Addressee a = al[index];
+ if ( a.isEmpty() ) return true;
+ KAddrBookExternal::addVCard( a, 0 );
+ return true;
+ }
+
+ static KABC::Addressee findAddressee( BodyPart *part, const TQString &path )
+ {
+ const TQString vCard = part->asText();
+ if ( !vCard.isEmpty() ) {
+ VCardConverter vcc;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
+ int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
+ if ( index >= 0 ) {
+ return al[index];
+ }
+ }
+ return KABC::Addressee();
+ }
+
+ bool handleContextMenuRequest( KMail::Interface::BodyPart *part,
+ const TQString &path,
+ const TQPoint &point ) const
+ {
+ const TQString vCard = part->asText();
+ if ( vCard.isEmpty() ) {
+ return true;
+ }
+ KABC::Addressee a = findAddressee( part, path );
+ if ( a.isEmpty() ) {
+ return true;
+ }
+
+ KPopupMenu *menu = new KPopupMenu();
+ menu->insertItem( i18n( "View Business Card" ), 0 );
+ menu->insertItem( i18n( "Save Business Card As..." ), 1 );
+
+ switch( menu->exec( point, 0 ) ) {
+ case 0: // open
+ openVCard( a, vCard );
+ break;
+ case 1: // save as
+ saveAsVCard( a, vCard );
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ TQString statusBarMessage( BodyPart *part, const TQString &path ) const
+ {
+ KABC::Addressee a = findAddressee( part, path );
+ if ( a.realName().isEmpty() ) {
+ return i18n( "Add this contact to the address book." );
+ } else {
+ return i18n( "Add \"%1\" to the address book." ).arg( a.realName() );
+ }
+ }
+
+ bool openVCard( const KABC::Addressee &a, const TQString &vCard ) const
+ {
+ Q_UNUSED( vCard );
+ AddresseeView *view = new AddresseeView( 0 );
+ view->setVScrollBarMode( TQScrollView::Auto );
+ if ( a.isEmpty() ) {
+ view->setText( i18n( "Failed to parse the business card." ) );
+ } else {
+ view->setAddressee( a );
+ }
+ view->setMinimumSize( 300, 400 );
+ view->show();
+ return true;
+ }
+
+ bool saveAsVCard( const KABC::Addressee &a, const TQString &vCard ) const
+ {
+ TQString fileName = a.givenName() + '_' + a.familyName() + ".vcf";
+
+ // get the saveas file name
+ KURL saveAsUrl =
+ KFileDialog::getSaveURL( fileName,
+ TQString::null, 0,
+ i18n( "Save Business Card" ) );
+ if ( saveAsUrl.isEmpty() ||
+ ( TQFileInfo( saveAsUrl.path() ).exists() &&
+ ( KMessageBox::warningYesNo(
+ 0,
+ i18n( "%1 already exists. Do you want to overwrite it?").
+ arg( saveAsUrl.path() ) ) == KMessageBox::No ) ) ) {
+ return false;
+ }
+
+ // put the attachment in a temporary file and save it
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete( true );
+
+ TQByteArray data = vCard.utf8();
+ tmpFile.file()->writeBlock( data.data(), data.size() );
+ tmpFile.close();
+
+ return KIO::NetAccess::upload( tmpFile.name(), saveAsUrl, 0 );
+ }
};
class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
diff --git a/plugins/kmail/bodypartformatter/text_vcard.desktop b/plugins/kmail/bodypartformatter/text_vcard.desktop
index 206d8462a..87cbf490e 100644
--- a/plugins/kmail/bodypartformatter/text_vcard.desktop
+++ b/plugins/kmail/bodypartformatter/text_vcard.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -56,7 +55,6 @@ Comment[hu]=Formázómodul text/vcard adatfolyamok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/vcard
Comment[it]=Un plugin per formattare il corpo di text/vcard
Comment[ja]=text/vcard 用の Bodypart フォーマッタ プラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/vcard
Comment[kk]=Text/vcard бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/vcard
Comment[lt]= Teksto/vcard formatavimo priedas
diff --git a/plugins/kmail/bodypartformatter/text_xdiff.cpp b/plugins/kmail/bodypartformatter/text_xdiff.cpp
index 87988840f..53bb0016f 100644
--- a/plugins/kmail/bodypartformatter/text_xdiff.cpp
+++ b/plugins/kmail/bodypartformatter/text_xdiff.cpp
@@ -59,7 +59,7 @@ namespace {
class Formatter : public KMail::Interface::BodyPartFormatter {
public:
- Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {
+ Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer, KMail::Callback & ) const {
if ( !writer ) return Ok;
diff --git a/plugins/kmail/bodypartformatter/text_xdiff.desktop b/plugins/kmail/bodypartformatter/text_xdiff.desktop
index a2c05f9cc..e04220538 100644
--- a/plugins/kmail/bodypartformatter/text_xdiff.desktop
+++ b/plugins/kmail/bodypartformatter/text_xdiff.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -54,7 +53,6 @@ Comment[hu]=Formázómodul text/x-diff adatok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/x-diff
Comment[it]=Un plugin per formattare il corpo di text/x-diff
Comment[ja]=text/x-diff 用の bodypart フォーマッタプラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/x-diff
Comment[kk]=Text/x-diff бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/x-diff
Comment[lt]=text/x-diff formatavimo priedas