///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using EMAPILib;
using JetBrains.DataStructures;
using JetBrains.Omea.AsyncProcessing;
using JetBrains.Omea.Base;
using JetBrains.Omea.Diagnostics;
using JetBrains.Omea.OpenAPI;
using JetBrains.Omea.ResourceTools;
namespace JetBrains.Omea.OutlookPlugin
{
public class OutlookProcessor : AsyncProcessor
{
private Exception _lastException;
private ChangeWatchers _changeWatchers = new ChangeWatchers();
private bool _scheduleDeliver = true;
private static int _syncVersion;
private IUIManager _UIManager = null;
public const int CURRENT_VERSION = 11;
private static bool _inited = false;
private bool _aborted = false;
public OutlookProcessor() : base( null, false )
{
_tracer = new Tracer( "OutlookProcessor" );
try
{
OutlookSession.Init( this );
OnSettingsChanged( null, null );
IdlePeriod = Settings.IdlePeriod * 60000;
ThreadName = "Outlook AsyncProcessor";
ThreadPriority = ThreadPriority.Normal;
ThreadStarted += new EventHandler( _outlookProcessor_ThreadStarted );
ThreadFinished += new EventHandler( _outlookProcessor_ThreadFinished );
ProcessMessages = true;
ExceptionHandler = new AsyncExceptionHandler( HandleException );
_UIManager = Core.UIManager;
_UIManager.RegisterIndicatorLight( "Outlook", this, 10,
OutlookPlugin.LoadIconFromAssembly( "OutlookPlugin.Icons.outlook_idle.ico" ),
OutlookPlugin.LoadIconFromAssembly( "OutlookPlugin.Icons.outlook_busy.ico" ),
OutlookPlugin.LoadIconFromAssembly( "OutlookPlugin.Icons.outlook_stuck.ico" ) );
_UIManager.MainWindowClosing += new System.ComponentModel.CancelEventHandler( _UIManager_MainWindowClosing );
StartThread();
_inited = true;
}
catch ( Exception exception )
{
SetLastException( exception );
}
}
public static bool Inited { get { return _inited; } }
public void AbortThread()
{
if ( _aborted )
{
return;
}
_finished = _aborted = true;
this.Thread.Abort();
MessageBox.Show( "Outlook plugin has encountered fatal error. " + Core.ProductFullName + " will shutdown.",
"Error" , MessageBoxButtons.OK, MessageBoxIcon.Error );
Core.UIManager.CloseMainWindow();
}
public static void CheckState()
{
if ( !OutlookProcessor.Inited )
{
throw new ApplicationException( "Outlook processor is not executed yet" );
}
}
public override void DoJobs()
{
if ( !_aborted )
{
base.DoJobs();
}
else
{
_finished = true;
}
}
public void ProcessJobs()
{
if ( Core.State == CoreState.Running )
{
if ( OutstandingJobs > 0 )
{
DoJobs();
}
else
{
Application.DoEvents();
}
}
}
public bool ShuttingDown { get { return ( Core.State == CoreState.ShuttingDown ) || Finished; } }
public bool IsStarted { get { return ( _lastException == null ); } }
public Exception LastException { get { return _lastException; } }
public static int SyncVersion
{
get
{
LoadSyncVersion();
return _syncVersion;
}
}
public bool ScheduleDeliver { get { return _scheduleDeliver; } }
private void OnSettingsChanged( object obj, EventArgs args )
{
Settings.LoadSettings();
if ( Core.State == CoreState.Running )
{
QueueJob( JobPriority.AboveNormal, "Synchronization for address books",
new MethodInvoker( SynchronizeOutlookAddressBooksImpl ) );
QueueJob( JobPriority.AboveNormal, "Synchronization for contacts", new MethodInvoker( SynchronizeContactsImpl ) );
}
_scheduleDeliver = Settings.ScheduleDeliver;
}
public void SynchronizeOutlookAddressBooks()
{
if ( Settings.SyncContacts )
{
if ( IsInitialStart() )
{
QueueJob( "Synchronization of address books", new MethodInvoker( SynchronizeOutlookAddressBooksImpl ) );
}
}
}
public void RunSynchronizeFolderAndAddressBooks()
{
RunJob( new MethodInvoker( SynchronizeFolderStructureImpl ) );
if ( Settings.SyncContacts )
{
if ( IsInitialStart() )
{
RunJob( "Synchronization of address books", new MethodInvoker( SynchronizeOutlookAddressBooksImpl ) );
}
}
}
public void SynchronizeFolderStructure()
{
QueueJob( "Synchronization of folder structure", new MethodInvoker( SynchronizeFolderStructureImpl ) );
}
public void SynchronizeMAPIInfoStores()
{
MethodInvoker synchronizeMAPIInfoStoresMethod = new MethodInvoker( SynchronizeMAPIInfoStoresImpl );
if ( IsInitialStart() )
{
RunJob( "Synchronization of MAPI info stores", synchronizeMAPIInfoStoresMethod );
}
else
{
QueueJob( JobPriority.Immediate, "Synchronization of MAPI info stores", synchronizeMAPIInfoStoresMethod );
}
}
public void InitialIndexing()
{
if ( Settings.SyncContacts )
{
_tracer.Trace( "prepare SynchronizeContacts" );
SynchronizeContacts();
}
_tracer.Trace( "prepare EnumerateMails" );
EnumerateMails();
}
private void ExportTasksImpl()
{
IResourceList tasksToExport = Core.ResourceStore.GetAllResources( STR.Task );
IResourceList tasksWithEntry = Core.ResourceStore.FindResourcesWithProp( null, PROP.EntryID );
tasksToExport = tasksToExport.Minus( tasksWithEntry );
foreach ( IResource task in tasksToExport.ValidResources )
{
if ( Finished )
{
break;
}
new ExportTaskDescriptor( task ).QueueJob( JobPriority.AboveNormal );
}
}
public void ExportTasks()
{
QueueJob( JobPriority.Immediate, new MethodInvoker( ExportTasksImpl ) );
}
private static void LoadSyncVersion()
{
if ( _syncVersion == 0 )
{
IResource resSyncVersion = GetSyncVersionResource();
_syncVersion = resSyncVersion.GetIntProp( PROP.SyncVersion );
}
}
private static IResource GetSyncVersionResource()
{
IResourceList syncVersions = Core.ResourceStore.GetAllResources( STR.SyncVersion );
if ( syncVersions.Count > 0 )
{
return syncVersions[ 0 ];
}
return Core.ResourceStore.NewResource( STR.SyncVersion );
}
public bool IsSyncComplete()
{
IResourceList syncVersions = Core.ResourceStore.GetAllResources( STR.SyncVersion );
if ( syncVersions.Count == 0 )
{
return false;
}
return syncVersions[ 0 ].HasProp( PROP.SyncComplete );
}
public void SetSyncComplete()
{
IResource resource = GetSyncVersionResource();
ResourceProxy proxy = new ResourceProxy( resource );
proxy.SetPropAsync( PROP.SyncComplete, true );
}
internal static void SetSyncVersion( int syncVersion )
{
_syncVersion = syncVersion;
Tracer._Trace( "OutlookProcessor: Forced syncVersion was set = " + _syncVersion );
}
private void SetSyncVersion()
{
_syncVersion = CURRENT_VERSION;
IResource resource = GetSyncVersionResource();
resource.SetProp( PROP.SyncVersion, _syncVersion );
_tracer.Trace( "syncVersion was set = " + _syncVersion );
}
internal void StopMailIndexing()
{
SetSyncVersion();
if ( Settings.IdleIndexing )
{
QueueIdleJob( new MailSyncDescriptor( false, DateTime.MinValue, true ) );
}
_changeWatchers.Watch();
Core.UIManager.AddOptionsChangesListener( "MS Outlook", STR.OUTLOOK_GENERAL, new EventHandler( OnSettingsChanged ) );
Core.UIManager.AddOptionsChangesListener( "MS Outlook", STR.OUTLOOK_FOLDERS, new EventHandler( OnSettingsChanged ) );
Core.UIManager.AddOptionsChangesListener( "MS Outlook", STR.OUTLOOK_ADDRESS_BOOKS, new EventHandler( OnSettingsChanged ) );
new PostManRepeatable();
}
public void SynchronizeContacts()
{
if ( IsInitialStart())
{
QueueJob( "Synchronization for contacts", new MethodInvoker( SynchronizeContactsImpl ) );
}
}
public void EnumerateMails()
{
QueueJob( "Start for mail enumerating", new MethodInvoker( EnumerateMailsImpl ) );
}
private void SynchronizeMAPIInfoStoresImpl()
{
bool isInitialStart = IsInitialStart();
HashMap infoStores = new HashMap();
foreach ( IResource infoStore in Core.ResourceStore.GetAllResources( STR.MAPIInfoStore ).ValidResources )
{
string storeId = infoStore.GetStringProp( PROP.EntryID );
if ( storeId != null )
{
if ( !OutlookSession.WereProblemWithOpeningStorage( storeId ) )
{
infoStores.Add( storeId, infoStore );
}
}
else
{
new ResourceProxy( infoStore ).DeleteAsync();
}
}
foreach ( IEMsgStore msgStore in OutlookSession.GetMsgStores() )
{
if ( msgStore == null )
{
continue;
}
string storeID = msgStore.GetBinProp( MAPIConst.PR_ENTRYID );
infoStores.Remove( storeID );
MAPIInfoStoreDescriptor infoStoreJob = new MAPIInfoStoreDescriptor( msgStore );
if( isInitialStart )
{
Core.ResourceAP.RunJob( infoStoreJob );
}
else
{
Core.ResourceAP.QueueJob( JobPriority.Immediate, infoStoreJob );
}
}
foreach ( HashMap.Entry entry in infoStores )
{
IResource infoStore = (IResource)entry.Value;
new ResourceProxy( infoStore ).Delete();
}
}
internal static bool IsIgnoredInfoStore( IEMsgStore msgStore )
{
Trace.WriteLine( "IsIgnoredInfoStore -- checking infostore: " );
string entryId = msgStore.GetBinProp( MAPIConst.PR_ENTRYID );
if ( entryId != null )
{
IResource infoStore = Core.ResourceStore.FindUniqueResource( STR.MAPIInfoStore, PROP.EntryID, entryId );
if ( infoStore != null )
{
if( infoStore.HasProp( Core.Props.Name ))
Trace.WriteLine( " IsIgnoredInfoStore -- with name [" + infoStore.GetStringProp( Core.Props.Name ) + "]" );
int prop = infoStore.GetIntProp( PROP.IgnoredFolder );
if( prop != 0 )
Trace.WriteLine( " IsIgnoredInfoStore -- FLAG IgnoredFolder is set!" );
return infoStore.GetIntProp( PROP.IgnoredFolder ) != 0;
}
else
{
Trace.WriteLine( " IsIgnoredInfoStore -- No InfoStore resource found." );
}
}
Trace.WriteLine( "IsIgnoredInfoStore -- It has no PR_ENTRYID, trying DeletedItemsEntryID" );
string deletedItemsEntryId = msgStore.GetBinProp( MAPIConst.PR_IPM_WASTEBASKET_ENTRYID );
if ( deletedItemsEntryId != null )
{
IResource infoStore = Core.ResourceStore.FindUniqueResource( STR.MAPIInfoStore,
PROP.DeletedItemsEntryID, deletedItemsEntryId );
if ( infoStore != null )
{
if( infoStore.HasProp( Core.Props.Name ))
Trace.WriteLine( "IsIgnoredInfoStore -- with name [" + infoStore.GetStringProp( Core.Props.Name ) + "]" );
int prop = infoStore.GetIntProp( PROP.IgnoredFolder );
if( prop != 0 )
Trace.WriteLine( "IsIgnoredInfoStore -- FLAG IgnoredFolder is set!" );
return infoStore.GetIntProp( PROP.IgnoredFolder ) != 0;
}
else
{
Trace.WriteLine( " IsIgnoredInfoStore -- No InfoStore resource found." );
}
}
Trace.WriteLine( "IsIgnoredInfoStore -- It has no PR_IPM_WASTEBASKET_ENTRYID" );
return false;
}
private void SynchronizeFolderRecursive( IEFolder folder, string name, string storeID, FolderDescriptor parentDescriptor )
{
if ( folder == null )
{
return;
}
using ( folder )
{
FolderDescriptor folderDescriptor = FolderDescriptor.Get( folder );
if ( name != null )
{
folderDescriptor.Name = name;
_tracer.Trace( "Folder name = " + name );
}
else
{
_tracer.Trace( "Folder name is unknown" );
}
_folders.Remove( folderDescriptor.FolderIDs.EntryId );
FolderStructureDescriptor folderStruct =
new FolderStructureDescriptor( parentDescriptor, folderDescriptor );
Core.ResourceAP.QueueJob( folderStruct );
IEFolders folders = OutlookSession.GetFolders( folder, folderDescriptor );
if ( folders == null )
{
return;
}
using ( folders )
{
for ( int i = 0; i < folders.GetCount(); ++i )
{
try
{
SynchronizeFolderRecursive( folders.OpenFolder( i ), null, storeID, folderDescriptor );
}
catch ( COMException exception )
{
_tracer.TraceException( exception );
OutlookSession.ProblemWithOpeningFolder( folderDescriptor.FolderIDs.EntryId );
break;
}
}
}
}
}
private HashSet _folders = new HashSet();
private void SynchronizeFolderStructureImpl()
{
_tracer.Trace( "Start SynchronizeFolderStructureImpl" );
IResourceList folders = Core.ResourceStore.GetAllResources( STR.MAPIFolder );
foreach ( IResource folder in folders.ValidResources )
{
string entryID = folder.GetStringProp( PROP.EntryID );
if ( entryID != null )
{
_folders.Add( entryID );
}
else
{
new ResourceProxy( folder ).DeleteAsync();
}
}
_tracer.Trace( "Start enumeration for info stores" );
foreach ( IEMsgStore msgStore in OutlookSession.GetMsgStores() )
{
if ( msgStore == null )
{
continue;
}
_tracer.Trace( "GetRootFolder" );
IEFolder rootFolder = msgStore.GetRootFolder();
string storeID = msgStore.GetBinProp( MAPIConst.PR_STORE_ENTRYID );
if ( IsIgnoredInfoStore( msgStore ) )
{
_tracer.Trace( "MsgStore is ignored" );
if ( rootFolder == null )
{
continue;
}
using ( rootFolder )
{
string entryID = OutlookSession.GetFolderID( rootFolder );
IResource rootMAPIFolder = Folder.Find( entryID );
if ( rootMAPIFolder != null )
{
_tracer.Trace( "Delete folder recursive for " + rootMAPIFolder.DisplayName );
Core.ResourceAP.QueueJob( "Delete folder recursive", new ResourceDelegate( Folder.DeleteFolderRecursive ),
rootMAPIFolder );
}
}
}
else
{
string name = msgStore.GetStringProp( MAPIConst.PR_DISPLAY_NAME );
_tracer.Trace( "MsgStore name = " + name );
SynchronizeFolderRecursive( rootFolder, name, storeID, null );
}
}
_tracer.Trace( "Delete folders recursively if necessary" );
foreach ( HashSet.Entry entry in _folders )
{
IResource folderToDelete =
Core.ResourceStore.FindUniqueResource( STR.MAPIFolder, PROP.EntryID, (string)entry.Key );
if ( folderToDelete != null )
{
PairIDs folderIDs = PairIDs.Get( folderToDelete );
if ( folderIDs != null )
{
if ( OutlookSession.WereProblemWithOpeningStorage( folderIDs.StoreId ) )
{
continue;
}
if ( OutlookSession.WereProblemWithOpeningFolder( folderIDs.EntryId ) )
{
continue;
}
}
Core.ResourceAP.QueueJob( new ResourceDelegate( Folder.DeleteFolderRecursive ),
folderToDelete );
}
}
_folders.Clear();
_tracer.Trace( "Finish SynchronizeFolderStructureImpl" );
}
private void SynchronizeOutlookAddressBooksImpl()
{
_tracer.Trace( "Start SynchronizeOutlookAddressBooksImpl" );
IEAddrBook addrBook = OutlookSession.GetAddrBook();
if ( addrBook != null )
{
int count = addrBook.GetCount();
for ( int i = 0; i < count; i++ )
{
if ( ShuttingDown )
{
return;
}
OutlookSession.ProcessJobs();
IEABContainer abCont = addrBook.OpenAB( i );
if ( abCont == null )
{
continue;
}
using ( abCont )
{
int displayType = abCont.GetLongProp( MAPIConst.PR_DISPLAY_TYPE );
if ( displayType != ABType.DT_GLOBAL )
{
continue;
}
string entryID = abCont.GetBinProp( MAPIConst.PR_ENTRYID );
Core.ResourceAP.RunJob( new OutlookABDescriptor( abCont.GetStringProp( MAPIConst.PR_DISPLAY_NAME ), entryID ) );
}
}
}
_tracer.Trace( "Start SynchronizeOutlookAddressBooksImpl" );
}
private void SynchronizeContactsImpl()
{
_tracer.Trace( "Start SynchronizeContactsImpl" );
Settings.UpdateProgress( 0, "Computing Address Books count...", "" );
int totalABs = Folder.GetFolders( FolderType.Contact ).Count;
int processedABs = 0;
IEAddrBook addrBook = OutlookSession.GetAddrBook();
if ( addrBook != null )
{
int count = addrBook.GetCount();
totalABs += count;
for ( int i = 0; i < count; ++i )
{
if ( ShuttingDown )
{
return;
}
OutlookSession.ProcessJobs();
++processedABs;
int percentage = ( processedABs * 100 ) / totalABs;
Settings.UpdateProgress( percentage, "Synchronizing Address Books", processedABs.ToString() );
IEABContainer abContainer = addrBook.OpenAB( i );
if ( abContainer == null )
{
continue;
}
using ( abContainer )
{
ProcessGlobalAddressBook( abContainer );
}
}
}
ProcessContactFolders( processedABs, totalABs );
_tracer.Trace( "Finish SynchronizeContactsImpl" );
Settings.UpdateProgress( 100, "Synchronizing Address Books", totalABs.ToString() );
}
private void ProcessGlobalAddressBook( IEABContainer abContainer )
{
IERowSet rowSet = abContainer.GetRowSet();
if ( rowSet == null )
{
return;
}
using ( rowSet )
{
string entryID = abContainer.GetBinProp( MAPIConst.PR_ENTRYID );
IResource outlookAB = Core.ResourceStore.FindUniqueResource( STR.OutlookABDescriptor, PROP.EntryID, entryID );
if ( outlookAB == null )
{
return;
}
if ( !Folder.IsIgnoreImport( outlookAB ) )
{
string curName = abContainer.GetStringProp( MAPIConst.PR_DISPLAY_NAME );
string abName = OutlookAddressBook.GetProposedName( curName, entryID );
OutlookAddressBook AB = new OutlookAddressBook( abName, entryID, false );
AB.RunAB();
int count = rowSet.GetRowCount();
for ( int i = 0; i < count; i++ )
{
if ( ShuttingDown )
{
return;
}
OutlookSession.ProcessJobs();
string ABentryID = rowSet.GetBinProp( 0, i /*MAPIConst.PR_ENTRYID*/ );
if ( ABentryID == null )
{
continue;
}
Core.ResourceAP.QueueJob( new ContactDescriptor( rowSet, i, ABentryID, AB ) );
}
}
else
{
IResource AB = Core.ResourceStore.FindUniqueResource( STR.AddressBook, PROP.EntryID, entryID );
if ( AB != null )
{
new ResourceProxy( AB ).DeleteAsync();
}
}
}
}
private void ProcessContactFolder( PairIDs folderIDs, string abName )
{
IEFolder folder = null;
try
{
folder = OutlookSession.OpenFolder( folderIDs.EntryId, folderIDs.StoreId );
}
catch( System.Threading.ThreadAbortException )
{
}
catch ( Exception exception )
{
if ( exception is COMException &&
( (COMException)exception ).ErrorCode != ( unchecked( (int)0x80040111 ) ) ) //ClassFactory cannot supply requested class
{
return;
}
Core.ReportException( exception, ExceptionReportFlags.AttachLog );
return;
}
if ( folder == null )
{
return;
}
using ( folder )
{
OutlookAddressBook AB = new OutlookAddressBook( abName, folderIDs, true );
AB.RunAB();
IEMessages messages = folder.GetMessages();
if ( messages == null )
{
return;
}
using ( messages )
{
int mesCount = messages.GetCount();
for ( int i = 0; i < mesCount; i++ )
{
if( ShuttingDown )
{
break;
}
OutlookSession.ProcessJobs();
IEMessage message = messages.OpenMessage( i );
if ( message == null )
{
continue;
}
using ( message )
{
string mesEntryID = OutlookSession.GetMessageID( message );
Core.ResourceAP.QueueJob( new ContactDescriptor( message, mesEntryID, mesEntryID, AB ) );
}
}
}
}
}
private void ProcessContactFolders( int processedABs, int totalABs )
{
ArrayList toDeleteFolders = new ArrayList();
foreach ( IResource contactFolder in Folder.GetFolders( FolderType.Contact ).ValidResources )
{
if( ShuttingDown )
{
break;
}
OutlookSession.ProcessJobs();
processedABs++;
int percentage = ( processedABs * 100 ) / totalABs;
Settings.UpdateProgress( percentage, "Indexing Address Books", processedABs.ToString() );
PairIDs folderIDs = PairIDs.Get( contactFolder );
if ( folderIDs == null )
{
toDeleteFolders.Add( contactFolder );
continue;
}
string abName = OutlookAddressBook.GetProposedName( contactFolder.GetPropText( Core.Props.Name ), folderIDs.EntryId );
Core.ResourceAP.QueueJob( new OutlookAddressBookReName( folderIDs.EntryId, abName ) );
if ( !Folder.IsIgnoreImport( contactFolder ) )
{
ProcessContactFolder( folderIDs, abName );
}
else
{
IResource AB = Core.ResourceStore.FindUniqueResource( STR.AddressBook, PROP.EntryID, folderIDs.EntryId );
if ( AB != null )
{
new ResourceProxy( AB ).DeleteAsync();
}
}
}
foreach ( IResource contactFolder in toDeleteFolders ) // delete corrupted 'MAPIFolder' resources
{
new ResourceProxy( contactFolder ).DeleteAsync();
}
}
private void OnCoreStateChanged( object sender, EventArgs e )
{
if ( Core.State == CoreState.Running )
{
QueueBackgroundWork();
Core.StateChanged -= new EventHandler( OnCoreStateChanged );
new PostManRepeatable();
}
}
private void PrepareBackgroundWork()
{
if ( Core.State == CoreState.Running )
{
QueueBackgroundWork();
}
Core.StateChanged += new EventHandler( OnCoreStateChanged );
}
private void QueueBackgroundWork()
{
if ( Settings.UseBackgroundMailSync )
{
_tracer.Trace( "Heavy enumeration is started in background" );
QueueJobAt( DateTime.Now.AddMinutes( 1 ), "Address Books Synchronization", new MethodInvoker( SynchronizeOutlookAddressBooksImpl ) );
QueueJobAt( DateTime.Now.AddMinutes( 1.5 ), "Contacts Synchronization", new MethodInvoker( SynchronizeContactsImpl ) );
QueueJobAt( DateTime.Now.AddMinutes( 2 ), new MailSyncBackground( Settings.IndexStartDate ) );
}
}
private void UpdateProgress( int processed, int total )
{
if ( Core.ProgressWindow == null )
{
return;
}
int percentage = ( total == 0 )
? 100
: processed * 100 / total;
string statusText = "Updating attachments...";
Settings.UpdateProgress( percentage, statusText, string.Empty );
}
private void UpdateAttachments()
{
_tracer.Trace( "prepare UpdateAttachments" );
IResourceList attachments = Core.ResourceStore.FindResourcesWithProp( null, PROP.AttachmentIndex );
int count = attachments.Count;
int processed = 0;
UpdateProgress( processed, count );
int ticks = System.Environment.TickCount;
foreach ( IResource attach in attachments.ValidResources )
{
try
{
IEAttach attachment = new OutlookAttachment( attach ).OpenAttach();
if ( attachment == null )
{
continue;
}
using ( attachment )
{
string contentID = attachment.GetStringProp( MAPIConst.PR_ATTACH_CONTENT_ID );
int attachNum = attachment.GetLongProp( MAPIConst.PR_ATTACH_NUM );
int attachMethod = attachment.GetLongProp( MAPIConst.PR_ATTACH_METHOD );
ResourceProxy resAttach = new ResourceProxy( attach );
resAttach.BeginUpdate();
resAttach.SetProp( CommonProps.ContentId, contentID );
resAttach.SetProp( PROP.PR_ATTACH_NUM, attachNum );
resAttach.SetProp( PROP.AttachMethod, attachMethod );
resAttach.EndUpdateAsync();
}
}
catch
{}
++processed;
if ( System.Environment.TickCount - ticks > 250 )
{
ticks = System.Environment.TickCount;
UpdateProgress( processed, count );
}
}
}
private void UpdateAnnotation()
{
_tracer.Trace( "prepare UpdateAnnotation" );
IResourceList list = Core.ResourceStore.FindResourcesWithProp( STR.Email, PROP.MessageFlag );
foreach ( IResource resource in list.ValidResources )
{
ResourceProxy mail = new ResourceProxy( resource );
mail.BeginUpdate();
string messageFlag = resource.GetStringProp( PROP.MessageFlag );
string annotation = resource.GetStringProp( Core.Props.Annotation );
if ( annotation != messageFlag )
{
if ( annotation == null || annotation.Length == 0 )
{
mail.SetProp( Core.Props.Annotation, messageFlag );
}
else
{
AnnotationMailChangeWatcher.ExportAnnotation( resource );
}
}
mail.DeleteProp( PROP.MessageFlag );
mail.EndUpdate();
}
}
private void EnumerateMailsImpl()
{
_tracer.Trace( "prepare EnumerateMailsImpl" );
try
{
if ( SyncVersion < 10 )
{
UpdateAttachments();
}
if ( SyncVersion < 9 && Settings.CreateAnnotationFromFollowup )
{
UpdateAnnotation();
}
DateTime dtRestriction = Settings.IndexStartDate;
if ( !IsInitialStart() )
{
_tracer.Trace( "Light enumeration is started" );
if ( Settings.SyncMode == MailSyncMode.None )
{
PrepareBackgroundWork();
}
else if ( Settings.SyncMode == MailSyncMode.All )
{
new MailSyncDescriptor( true, dtRestriction, false ).NextMethod();
}
else
{
new FreshMailEnumerator().NextMethod();
PrepareBackgroundWork();
}
}
else
{
ResourceProxy.BeginNewResource( STR.InitialEmailEnum ).EndUpdateAsync();
_tracer.Trace( "Heavy enumeration is started" );
new MailSyncDescriptor( true, dtRestriction, false ).NextMethod();
if ( dtRestriction == DateTime.MinValue )
{
SetSyncComplete();
}
}
}
finally
{
_tracer.Trace( "fire FinishInitialIndexingJob" );
Core.ResourceAP.QueueJob( new MethodInvoker( OutlookPlugin.FinishInitialIndexingJob ) );
}
}
private void _outlookProcessor_ThreadStarted( object sender, EventArgs e )
{
try
{
OutlookSession.Initialize();
}
catch ( Exception exception )
{
_tracer.TraceException( exception );
SetLastException( exception );
}
}
private void _outlookProcessor_ThreadFinished( object sender, EventArgs e )
{
Settings.LastExecutionTime.Save( DateTime.Now );
OutlookSession.OutlookProcessor.ProcessJobs();
try
{
OutlookSession.Uninitialize();
}
catch ( Exception exception )
{
_tracer.TraceException( exception );
SetLastException( exception );
}
if ( _aborted )
{
_finished = true;
}
}
public bool HandleException( COMException comException )
{
_tracer.TraceException( comException );
if ( comException.ErrorCode == ( unchecked( (int)0x80040600 ) ) )
{
StandartJobs.MessageBox( "MAPI reports internal error that your message storage is corrupted", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error );
return true;
}
else if ( comException.ErrorCode == ( unchecked( (int)0x8004011C ) ) )
{
StandartJobs.MessageBox( "MAPI reports internal error that your message storage is not configured", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error );
return true;
}
else if ( comException.ErrorCode == ( unchecked( (int)0x80040116 ) ) ) //MAPI_E_DISK_ERROR
{
StandartJobs.MessageBox( "MAPI reports internal error that there is hard disk error while reading from message store.", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error );
return true;
}
else if ( comException.ErrorCode == ( unchecked( (int)0x8004060C ) ) ) //
{
StandartJobs.MessageBox( "Outlook reports that your message store exceeded the available space.", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error );
return true;
}
return false;
}
private void HandleException( Exception exception )
{
if ( exception is System.Threading.ThreadAbortException )
{
return;
}
bool trapped = false;
Exception mostInnerException = Utils.GetMostInnerException( exception );
if ( mostInnerException is COMException )
{
trapped = HandleException( (COMException)mostInnerException );
}
if ( !trapped )
{
Core.ReportException( exception, ExceptionReportFlags.AttachLog );
}
SetLastException( exception );
}
private void SetLastException( Exception exception )
{
_lastException = exception;
}
public override void Dispose()
{
Core.UIManager.DeRegisterIndicatorLight( "Outlook" );
base.Dispose();
}
private void _UIManager_MainWindowClosing( object sender, System.ComponentModel.CancelEventArgs e )
{
if ( OutlookSession.LibManagerBase.FormCount() > 0 && !OutlookSession.EMAPISession.CanClose() )
{
DialogResult result =
MessageBox.Show( "You have open Outlook message windows.\nYou should save, send or close the messages before closing Omea,\notherwise the messages will be lost. Continue closing?",
"Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2 );
if ( result == DialogResult.No )
{
e.Cancel = true;
}
}
}
private static bool IsInitialStart()
{
return Core.ResourceStore.GetAllResources( STR.InitialEmailEnum ).Count == 0;
}
}
internal delegate MailBodyDescriptor PairIDsDelegate( PairIDs pairIDs );
internal delegate void StringDelegate( string str );
internal delegate MailBodyDescriptor MailBodyDescriptorDelegate( IResource resource );
internal delegate void ActionContextDelegate( IActionContext context );
internal delegate Stream Resource2StreamDelegate( IResource resource, int threadId );
internal delegate void ResourceList_ResourceDelegate( IResourceList resourceList, IResource resource );
internal delegate void Resource_StringDelegate( IResource resource, string str );
internal delegate void CreateEmailDelegate( string subject, string body, EmailBodyFormat bodyFormat, IResourceList recipients,
string[] attachments, bool useTemplatesInBody );
internal delegate void CreateEmailWithRecipDelegate( string subject, string body, EmailBodyFormat bodyFormat, EmailRecipient[] recipients,
string[] attachments, bool useTemplatesInBody );
internal class OutlookThreadTimeoutException : Exception
{
internal OutlookThreadTimeoutException()
: base( "Timeout when calling Outlook thread" )
{}
}
internal class StandartJobs
{
static public void MessageBox( string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon )
{
Core.UIManager.QueueUIJob( new DelegateShowMessageBox( ShowMessageBox ), message, caption, buttons, icon );
}
delegate void DelegateShowMessageBox( string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon );
static private void ShowMessageBox( string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon )
{
System.Windows.Forms.MessageBox.Show( message, caption, buttons, icon );
}
}
internal class EmptyJob : AbstractNamedJob
{
protected override void Execute()
{
Tracer._Trace( "Empty job was executed." );
}
///
/// Gets or sets the name of the job.
///
/// The name of the last executing job is displayed in the tooltip for
/// the async processor status indicator in the status bar.
public override string Name { get { return "Empty job to start async processor"; }
}
}
}