예제 #1
0
 private void SyncStalled(ZPushAccount account)
 {
     ThisAddIn.Instance.InUI(() =>
     {
         if (MessageBox.Show(ThisAddIn.Instance.Window,
                             string.Format(Properties.Resources.SyncState_Stalled_Body, account.DisplayName),
                             string.Format(Properties.Resources.SyncState_Stalled_Caption, account.DisplayName),
                             MessageBoxButtons.YesNo,
                             MessageBoxIcon.Error
                             ) == DialogResult.Yes)
         {
             IRestarter restarter = ThisAddIn.Instance.Restarter();
             restarter.ResyncAccounts(account);
             restarter.Restart();
         }
     });
 }
        public SharedFoldersDialog(FeatureSharedFolders feature, ZPushAccount account, SyncId initial = null)
        {
            // If this is a shared store, open the account it's a share for, with the request account as the initial
            if (account.ShareFor != null)
            {
                _initialAccount = account;
                account         = account.ShareForAccount;
            }
            this._account       = account;
            this._feature       = feature;
            this._featureSendAs = ThisAddIn.Instance.GetFeature <FeatureSendAs>();
            this._folders       = feature.Manage(account);
            this._initialSyncId = initial;

            InitializeComponent();

            // TODO: make a specialised class out of this
            this.kTreeFolders.Images = new OutlookImageList(
                "NewFolder",              // Other
                "JunkEmailMarkAsNotJunk", // Inbox
                "GoDrafts",               // Drafts
                "RecycleBin",             // WasteBasket
                "ReceiveMenu",            // SentMail
                "NewFolder",              // Outbox
                "ShowTaskPage",           // Task
                "ShowAppointmentPage",    // Appointment
                "ShowContactPage",        // Contact
                "NewNote",                // Note
                "ShowJournalPage",        // Journal
                "LastModifiedBy"          // Store

                ).Images;

            // Set the check manager
            kTreeFolders.CheckManager = new ShareCheckManager();

            // Add the email address to the title
            Text = string.Format(Text, account.Account.SmtpAddress);

            // Set up options
            ShowOptions(new KTreeNode[0]);

            // Set up user selector
            gabLookup.GAB = FeatureGAB.FindGABForAccount(account);
        }
        /// <summary>
        /// Invoked by AccountWatcher on start-up to notify of the oof status.
        /// </summary>
        public void OnOOFSettings(ZPushAccount account, ActiveSync.SettingsOOF oof)
        {
            // Store them for later use
            StoreOOFSettings(account, oof);

            // Show a message if OOF is enabled
            if (IsOOFEnabled(oof))
            {
                if (MessageBox.Show(
                        string.Format(Properties.Resources.OOFStartup_Message, account.Account.SmtpAddress),
                        Properties.Resources.OOFStartup_Title,
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question
                        ) == DialogResult.Yes)
                {
                    ShowOOFDialog(account, oof);
                }
            }
        }
예제 #4
0
        private void ZPushChannelAvailable(IFolder folder)
        {
            using (IStore store = folder.GetStore())
            {
                Logger.Instance.Debug(this, "Z-Push channel available: {0} on {1}", folder, store.DisplayName);

                ZPushAccount account = Watcher.Accounts.GetAccount(folder);
                if (account != null)
                {
                    account.LinkedGABFolder(folder);
                    RegisterGABAccount(account, folder);
                }
                else
                {
                    Logger.Instance.Warning(this, "Z-Push channel account not found: {0} on {1}", folder, store.DisplayName);
                }
                Logger.Instance.Debug(this, "Z-Push channel available done");
            }
        }
예제 #5
0
        private void AccountDiscovered(ZPushAccount zpush)
        {
            Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName);
            _domains.Add(zpush.Account.DomainName);

            zpush.ConfirmedChanged += (z) =>
            {
                Logger.Instance.Debug(this, "Account discovered and confirmed: {0} -> {1}: {2}", zpush.DisplayName, zpush.Confirmed, zpush.GABFolder);
                if (zpush.Confirmed == ZPushAccount.ConfirmationType.IsZPush &&
                    !string.IsNullOrEmpty(zpush.GABFolder))
                {
                    Logger.Instance.Debug(this, "Account discovered, listening for folder: {0} -> {1}: {2}", zpush.DisplayName, zpush.Confirmed, zpush.GABFolder);
                    // Set up the Z-Push channel listener
                    ZPushChannel channel = ZPushChannels.Get(this, zpush, zpush.GABFolder);
                    channel.Available += ZPushChannelAvailable;
                    channel.Start();
                }
            };
        }
예제 #6
0
        private void CheckSyncState(ZPushAccount account)
        {
            // TODO: we probably want one invocation for all accounts
            using (ZPushConnection connection = account.Connect())
                using (ZPushWebServiceDevice deviceService = connection.DeviceService)
                {
                    // Fetch
                    DeviceDetails details = deviceService.Execute(new GetDeviceDetailsRequest());
                    if (details != null)
                    {
                        bool wasSyncing = false;

                        // Create or update session
                        SyncSession session = account.GetFeatureData <SyncSession>(this, null);
                        if (session == null)
                        {
                            session = new SyncSession(this, account);
                        }
                        else
                        {
                            wasSyncing = session.IsSyncing;
                        }

                        session.Add(details);

                        // Store with the account
                        account.SetFeatureData(this, null, session);

                        if (wasSyncing != session.IsSyncing)
                        {
                            // Sync state has changed, update the schedule
                            Watcher.Sync.SetTaskSchedule(_task, account, session.IsSyncing ? CheckPeriodSync : (TimeSpan?)null);
                        }
                    }
                }

            // Update the total for all accounts
            UpdateTotalSyncState();

            // Check for stalls
            CheckSyncStalled(account);
        }
예제 #7
0
        internal IRecipient FindSendAsSender(ZPushAccount zpush, GABUser user)
        {
            // First try a simple resolve, this will work if the username is unique
            IRecipient recip = ThisAddIn.Instance.ResolveRecipient(user.UserName);

            if (recip != null)
            {
                // If it's resolved, we're good. Otherwise dispose and continue
                if (recip.IsResolved)
                {
                    return(recip);
                }
                else
                {
                    recip.Dispose();
                }
            }

            // Search through GAB to find the user
            if (GABLookup)
            {
                GABHandler handler = FeatureGAB.FindGABForAccount(zpush);
                if (handler != null && handler.Contacts != null)
                {
                    // Look for the email address. If found, use the account associated with the GAB
                    using (ISearch <IContactItem> search = handler.Contacts.Search <IContactItem>())
                    {
                        search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, user.UserName);
                        using (IContactItem result = search.SearchOne())
                        {
                            if (result != null)
                            {
                                // Try resolving by email
                                return(ThisAddIn.Instance.ResolveRecipient(result.Email1Address));
                            }
                        }
                    }
                }
            }

            return(null);
        }
        private void OpenWebApp()
        {
            ZPushAccount account = Watcher.CurrentZPushAccount();

            if (account == null)
            {
                return;
            }

            // Get the url
            string url = AutoDiscover(account);

            if (url == null)
            {
                return;
            }

            // Open the browser
            System.Diagnostics.Process.Start(url);
        }
        private void CheckUpgradesGabSynced(GABHandler gab)
        {
            ThisAddIn.Instance.InUI(() =>
            {
                ZPushAccount account = gab.ActiveAccount;
                ICollection <SharedFolder> shares = _sharedFolders.GetCachedFolders(account);
                if (shares == null)
                {
                    using (SharedFoldersManager manager = _sharedFolders.Manage(account))
                    {
                        shares = manager.GetCurrentShares(null);
                    }
                }

                if (shares != null)
                {
                    UpdateSendAsAddresses(account, shares, true);
                }
            }, false);
        }
예제 #10
0
 private void MailEvents_ItemSend(IMailItem item, ref bool cancel)
 {
     using (IStore store = item.GetStore())
     {
         ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
         if (zpush != null)
         {
             string address = item.SenderEmailAddress;
             if (address != null && address != zpush.Account.SmtpAddress)
             {
                 Logger.Instance.Trace(this, "SendAs: {0}: {1}", address, item.SenderName);
                 item.SetProperty(Constants.ZPUSH_SEND_AS, address);
                 if (item.SenderName != null)
                 {
                     item.SetProperty(Constants.ZPUSH_SEND_AS_NAME, item.SenderName);
                 }
             }
         }
     }
 }
        public SharedFolder GetSharedFolder(IFolder folder)
        {
            if (folder == null)
            {
                return(null);
            }

            // Check that we can get the id
            SyncId folderId = folder.SyncId;

            Logger.Instance.Trace(this, "GetSharedFolder1: {0}", folderId);
            if (folderId == null || !folderId.IsCustom)
            {
                return(null);
            }

            // Get the ZPush account
            ZPushAccount account = Watcher.Accounts.GetAccount(folder);

            Logger.Instance.Trace(this, "GetSharedFolder2: {0}", account);
            if (account == null)
            {
                return(null);
            }

            // Get the shared folders
            Dictionary <SyncId, SharedFolder> shared = account.GetFeatureData <Dictionary <SyncId, SharedFolder> >(this, KEY_SHARES);

            Logger.Instance.Trace(this, "GetSharedFolder3: {0}", shared?.Count);
            if (shared == null)
            {
                return(null);
            }

            SharedFolder share = null;

            shared.TryGetValue(folderId, out share);
            Logger.Instance.Trace(this, "GetSharedFolder4: {0}", share);

            return(share);
        }
        /// <summary>
        /// Fetches the signatures for the account.
        /// </summary>
        /// <param name="account">The account.</param>
        /// <returns>The signature hash</returns>
        private string FetchSignatures(ZPushAccount account)
        {
            Logger.Instance.Debug(this, "Fetching signatures for account {0}", account);
            using (ZPushConnection connection = account.Connect())
                using (ZPushWebServiceInfo infoService = connection.InfoService)
                {
                    Logger.Instance.Trace(this, "Executing request: {0}", account);
                    GetSignatures result = infoService.Execute(new GetSignaturesRequest());
                    Logger.Instance.Trace(this, "Executed request: {0} -> {1}", account, result);

                    // Store the signatures
                    Dictionary <object, string> fullNames = new Dictionary <object, string>();
                    using (ISignatures signatures = ThisAddIn.Instance.GetSignatures())
                    {
                        Logger.Instance.Trace(this, "Storing signatures: {0}", account);
                        foreach (Signature signature in result.all.Values)
                        {
                            Logger.Instance.Trace(this, "Storing signature: {0}: {1}", account, signature);
                            string name = StoreSignature(signatures, account, signature);
                            Logger.Instance.Trace(this, "Stored signature: {0}: {1}: {2}", account, name, signature);
                            fullNames.Add(signature.id, name);
                        }
                    }

                    // Set default signatures if available and none are set
                    if (!string.IsNullOrEmpty(result.new_message) && ShouldSetSignature(account.SignatureNewMessage))
                    {
                        Logger.Instance.Trace(this, "Setting signature new message: {0}: {1}", account, result.new_message);
                        account.SignatureNewMessage = fullNames[result.new_message];
                    }
                    if (!string.IsNullOrEmpty(result.replyforward_message) && ShouldSetSignature(account.SignatureReplyForwardMessage))
                    {
                        Logger.Instance.Trace(this, "Setting signature reply message: {0}: {1}", account, result.replyforward_message);
                        account.SignatureReplyForwardMessage = fullNames[result.replyforward_message];
                    }

                    Logger.Instance.Trace(this, "Signature synced: {0}: {1}", account, result.hash);
                    return(result.hash);
                }
        }
예제 #13
0
        private IRecipient FindSendAsSender(ZPushAccount zpush, IFolder folder)
        {
            SyncId syncId = folder.SyncId;

            if (syncId != null)
            {
                string address = zpush.GetSendAsAddress(syncId);
                if (address == null)
                {
                    // Check if it should have an address
                    SharedFolder shared = _sharedFolders?.GetSharedFolder(folder);
                    if (shared?.FlagSendAsOwner == true)
                    {
                        // See if we can get it now
                        address = FindSendAsAddress(zpush, shared);

                        if (address == null)
                        {
                            // Should have it, error
                            MessageBox.Show(ThisAddIn.Instance.Window,
                                            Properties.Resources.SharedFolders_SendAsFailed_Label,
                                            Properties.Resources.SharedFolders_SendAsFailed_Title,
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error
                                            );
                        }
                    }
                }

                if (address != null)
                {
                    IRecipient resolved = ThisAddIn.Instance.ResolveRecipient(address);
                    if (resolved != null)
                    {
                        return(resolved);
                    }
                }
            }
            return(null);
        }
        public SyncStateDialog(FeatureSyncState feature, ZPushAccount currentAccount)
        {
            InitializeComponent();

            // Ensure these are in sync with ResyncOption
            _syncButtons = new Button[]
            {
                buttonGAB, buttonSignatures, buttonServerData, buttonFullResync
            };
            this._feature = feature;
            comboAccounts.SelectedIndex = 0;

            // Add the accounts
            foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts())
            {
                comboAccounts.Items.Add(account);
            }
            if (currentAccount != null)
            {
                comboAccounts.SelectedItem = currentAccount;
            }
        }
        private void AddUserFolders(GABUser user, ZPushAccount wholeStore, Dictionary <BackendId, SharedFolder> currentShares, bool select)
        {
            if (user == null)
            {
                return;
            }

            // If the user is already fetched, reuse the node
            StoreTreeNode node;

            if (!_userFolders.TryGetValue(user, out node))
            {
                if (!user.HasFullName)
                {
                    // Try to fill in the full name
                    user = gabLookup.LookupExact(user.UserName);
                }

                string sendAsAddress = _featureSendAs?.FindSendAsAddress(_account, user);

                // Add the node
                node = new StoreTreeNode(_folders, gabLookup.GAB,
                                         user, sendAsAddress,
                                         user.DisplayName, currentShares ?? new Dictionary <BackendId, SharedFolder>(),
                                         wholeStore != null,
                                         wholeStore?.ShowReminders == true);
                node.DirtyChanged      += UserSharesChanged;
                node.CheckStateChanged += WholeStoreShareChanged;
                _userFolders.Add(user, node);
                kTreeFolders.RootNodes.Add(node);
            }

            if (select)
            {
                FocusNode(node, !_folders.SupportsWholeStore);
            }
        }
예제 #16
0
 /// <summary>
 /// Creates an instance with a dedicated connection.
 /// </summary>
 /// <param name="account">The account which will be connected to</param>
 public SharedFoldersAPI(ZPushAccount account) : this(account.Connect(), true)
 {
 }
예제 #17
0
 public bool SupportsSyncTimeFrame(ZPushAccount account)
 {
     return(account?.ZPushVersion?.IsAtLeast(2, 4) == true);
 }
예제 #18
0
 internal void UpdateSendAsAddresses(ZPushAccount zpush, ICollection <SharedFolder> shares)
 {
     UpdateSendAsAddresses(zpush, shares, false);
 }
 private void Watcher_AccountDiscovered(ZPushAccount account)
 {
     // Start an autodiscover for each account
     AutoDiscover(account);
 }
예제 #20
0
 public void OpenShare(ZPushAccount account, GABUser store)
 {
     _shares.Add(new KeyValuePair <ZPushAccount, GABUser>(account, store));
 }
        private void dialogButtons_Apply(object sender, EventArgs e)
        {
            int folderCount = 0;

            // Check if all fields are properly set
            foreach (StoreTreeNode storeNode in _userFolders.Values)
            {
                // Check totals
                folderCount += storeNode.CurrentShares.Count();

                // Check modified folders
                if (storeNode.IsDirty)
                {
                    foreach (SharedFolder folder in storeNode.CurrentShares)
                    {
                        // Check if the send-as address has been resolved (or entered) correctly
                        if (folder.FlagSendAsOwner && string.IsNullOrWhiteSpace(folder.SendAsAddress))
                        {
                            // Find the tree node
                            KTreeNode folderNode = storeNode.FindNode(folder);
                            if (folderNode != null)
                            {
                                // See if we can obtain it from a parent
                                TryInitSendAsAddressParent(folderNode as FolderTreeNode);
                                if (!string.IsNullOrWhiteSpace(folder.SendAsAddress))
                                {
                                    continue;
                                }

                                // If the node is already selected, explicitly warn about the send-as address
                                // Otherwise, selecting it will pop up the warning
                                if (folderNode.IsSelected)
                                {
                                    TryInitSendAsAddress();
                                }
                                else
                                {
                                    FocusNode(folderNode, false);
                                }
                            }
                            return;
                        }
                    }
                }
            }

            // Check total number of folders
            if (folderCount >= _feature.MaxFolderCount)
            {
                MessageBox.Show(ThisAddIn.Instance.Window,
                                Properties.Resources.SharedFolders_TooManyFolders_Body,
                                Properties.Resources.SharedFolders_TooManyFolders_Title,
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error
                                );
                // And don't apply anything
                return;
            }

            BusyText = Properties.Resources.SharedFolders_Applying_Label;
            KUITask.New((ctx) =>
            {
                // We reuse the same busy indicationg for all calls. A count is kept to ensure it's removed.
                ApplyState state = new ApplyState();

                foreach (StoreTreeNode storeNode in _userFolders.Values)
                {
                    // Check modified folders
                    if (storeNode.IsDirty)
                    {
                        ctx.AddBusy(1);
                        ++state.folders;

                        // Check removed shares
                        _folders.RemoveSharesForStore(storeNode.User, storeNode.RemovedShares);

                        // Set shares
                        _folders.SetSharesForStore(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken);
                    }

                    // And modified stores
                    if (storeNode.IsWholeStoreDirty)
                    {
                        state.stores.Add(storeNode);
                    }
                }

                return(state);
            })
            .OnSuccess((ctx, state) =>
            {
                // Update UI state
                foreach (StoreTreeNode storeNode in _userFolders.Values)
                {
                    if (storeNode.IsDirty)
                    {
                        storeNode.ChangesApplied();
                    }
                }

                ctx.AddBusy(-state.folders);

                List <ZPushAccount> syncAdditional = new List <ZPushAccount>();

                // Handle stores
                if (state.stores.Count > 0)
                {
                    List <StoreTreeNode> add = new List <StoreTreeNode>();

                    // Remove any unshared store
                    foreach (StoreTreeNode store in state.stores)
                    {
                        if (store.WantShare)
                        {
                            // Check if it must be added
                            if (!store.IsShared)
                            {
                                add.Add(store);
                            }

                            // Update reminders for existing stores
                            if (store.ShowReminders != store.ShowRemindersInitial)
                            {
                                ZPushAccount storeAccount = store.WholeStoreAccount;
                                if (storeAccount != null)
                                {
                                    storeAccount.ShowReminders = store.ShowReminders;
                                    syncAdditional.Add(storeAccount);
                                    // Update UI state
                                    store.ShowRemindersInitial = store.ShowReminders;
                                    WholeStoreShareChanged(store);
                                }
                            }
                            continue;
                        }
                        else
                        {
                            // Remove it
                            _feature.RemoveSharedStore(_account, store.User);
                            store.IsShared = false;
                            WholeStoreShareChanged(store);
                        }
                    }

                    // Check for any new stores
                    if (add.Count > 0)
                    {
                        bool restart = MessageBox.Show(ThisAddIn.Instance.Window,
                                                       Properties.Resources.SharedFolders_WholeStoreRestart_Body,
                                                       Properties.Resources.SharedFolders_WholeStoreRestart_Title,
                                                       MessageBoxButtons.OKCancel,
                                                       MessageBoxIcon.Information
                                                       ) == DialogResult.OK;

                        // Reset state. Also do this when restarting, to avoid warning message about unsaved changes
                        foreach (StoreTreeNode node in state.stores)
                        {
                            node.WantShare = node.IsShared;
                        }

                        if (!restart)
                        {
                            return;
                        }

                        // Restart
                        IRestarter restarter   = ThisAddIn.Instance.Restarter();
                        restarter.CloseWindows = true;
                        foreach (StoreTreeNode node in state.stores)
                        {
                            restarter.OpenShare(_account, node.User, node.ShowReminders);
                        }
                        restarter.Restart();
                    }

                    // Update UI state
                    foreach (StoreTreeNode storeNode in _userFolders.Values)
                    {
                        storeNode.ChangesApplied();
                    }
                    CheckDirty();
                }

                // Sync accounts
                foreach (ZPushAccount account in syncAdditional)
                {
                    _feature.Sync(account);
                }

                if (state.folders != 0)
                {
                    // Sync account
                    _feature.Sync(_account);

                    // Show success
                    ShowCompletion(Properties.Resources.SharedFolders_Applying_Success);
                }
            }, true)
            .OnError((x) =>
            {
                ErrorUtil.HandleErrorNew(typeof(FeatureSharedFolders), "Exception applying shared folders for account {0}", x,
                                         Properties.Resources.SharedFolders_Applying_Title,
                                         Properties.Resources.SharedFolders_Applying_Failure,
                                         _account.DisplayName);
            })
            .Start(this);
        }
 public void Sync(ZPushAccount account)
 {
     account.Account.SendReceive(new AcaciaTask(null, this, "SyncShares", () => SyncShares(account)));
 }
 internal SharedFoldersManager Manage(ZPushAccount account)
 {
     return(new SharedFoldersManager(this, account));
 }
 public void ManageFolder(ZPushAccount account, SyncId folderId)
 {
     new SharedFoldersDialog(this, account, folderId).ShowDialog();
 }
예제 #25
0
 public Request(ZPushAccount account, CancellationToken cancel)
 {
     this._account = account;
     this._cancel  = cancel;
     this._client  = CreateClient(account);
 }
예제 #26
0
 public SyncSession(FeatureSyncState feature, ZPushAccount account)
 {
     this._feature = feature;
     this._account = account;
 }
예제 #27
0
 /// <summary>
 /// Returns a SyncState for the specified account, or all accounts.
 /// </summary>
 /// <param name="account">The account, or null to fetch a SyncState for all accounts</param>
 public SyncState GetSyncState(ZPushAccount account)
 {
     return(new SyncStateImpl(this, account == null ? Watcher.Accounts.GetAccounts().ToArray() : new ZPushAccount[] { account }));
 }
예제 #28
0
 public SharedFoldersManager(FeatureSharedFolders featureSharedFolders, ZPushAccount account)
 {
     this._feature = featureSharedFolders;
     this._account = account;
     _api          = new SharedFoldersAPI(account);
 }
 private void Watcher_AccountDiscovered(ZPushAccount account)
 {
     account.ConfirmedChanged += Account_ConfirmedChanged;
 }
예제 #30
0
 public void AddAccount(ZPushAccount account, IFolder folder)
 {
     _accounts.Add(account);
     _accountFolders.Add(folder);
 }