Esempio n. 1
0
        public static void SendLastPresence(Service service)
        {
            if (!service.Information.DoesSupport(typeof(PresenceBubble)))
            {
                return;
            }

            lock (LastPresenceBubbles)
            {
                var presenceBubble = LastPresenceBubbles.FirstOrDefault(pb => pb.Service == service);
                if (presenceBubble == null)
                {
                    return;
                }

                Utils.DebugPrint("Sending last presence for service " + service.Information.ServiceName + ". " +
                                 (presenceBubble.Available ? "Available." : "Unavailable."));
                Send(presenceBubble);

                if (presenceBubble.Available)
                {
                    return;
                }
                foreach (var group in BubbleGroupManager.FindAll(presenceBubble.Service))
                {
                    @group.PresenceType = PresenceBubble.PresenceType.Unavailable;
                }
            }
        }
Esempio n. 2
0
        public static void UpdatePartyParticipants(Service service,
                                                   string bubbleGroupAddress, Action <bool> finished = null)
        {
            var bubbleGroup =
                BubbleGroupManager.FindWithAddress(service, bubbleGroupAddress);

            if (bubbleGroup == null)
            {
                finished(false);
            }
            UpdatePartyParticipants(bubbleGroup, () =>
            {
                try
                {
                    BubbleGroupEvents.RaiseBubblesUpdated(bubbleGroup);
                }
                catch
                {
                    // do nothing
                }
                if (finished != null)
                {
                    finished(true);
                }
            });
        }
Esempio n. 3
0
        public static void Delete(BubbleGroup group)
        {
            lock (BubbleGroupDatabase.OperationLock)
            {
                var unifiedGroup = @group as UnifiedBubbleGroup;
                if (unifiedGroup != null)
                {
                    DeleteUnified(unifiedGroup);
                    return;
                }

                var file = BubbleGroupDatabase.GetLocation(@group);

                if (File.Exists(file))
                {
                    File.Delete(file);
                }

                BubbleGroupSync.RemoveFromSync(@group);

                BubbleGroupSync.DeleteBubbleGroupIfHasAgent(@group);

                BubbleGroupManager.BubbleGroupsRemove(@group);
            }
        }
Esempio n. 4
0
        public static void UpdateParties(Service service, string participantAddress)
        {
            Utils.DebugPrint("Updating bubble group parties that contain participant address: " + participantAddress);

            foreach (var @group in
                     BubbleGroupManager.FindAll(@group => @group.IsParty && @group.Service == service && @group.Participants.Any()))
            {
                foreach (var participant in @group.Participants)
                {
                    //TODO: this needs to be made into a comparer eventually
                    //TODO: as it stands... a participant with address 16041234567 != 6041234567
                    if (participant.Address != participantAddress)
                    {
                        continue;
                    }

                    Utils.DebugPrint("Updating " + @group.ID + " (party) with name " + (@group.Title != null
                        ? @group.Title
                        : "[unknown]"));

                    Update(@group);
                    break; //don't update the same group again
                }
            }
        }
        public static UnifiedBubbleGroup CreateUnified(List <BubbleGroup> groups, BubbleGroup primaryGroup)
        {
            lock (BubbleGroupDatabase.OperationLock)
            {
                var unifiedGroupsToKill = new HashSet <UnifiedBubbleGroup>();
                foreach (var group in groups)
                {
                    if (group.IsUnified)
                    {
                        unifiedGroupsToKill.Add(group.Unified);
                        @group.DeregisterUnified();
                    }
                }
                foreach (var unifiedGroup in unifiedGroupsToKill)
                {
                    BubbleGroupManager.BubbleGroupsRemove(unifiedGroup);
                }
                UnifiedBubbleGroupsDatabase.Remove(unifiedGroupsToKill);

                var unified = CreateUnifiedInternal(groups, primaryGroup);
                UnifiedBubbleGroupsDatabase.Add(unified,
                                                new DisaUnifiedBubbleGroupEntry(unified.ID,
                                                                                unified.Groups.Select(innerGroup => innerGroup.ID)
                                                                                .ToArray(), primaryGroup.ID, primaryGroup.ID));
                BubbleGroupManager.BubbleGroupsAdd(unified);
                return(unified);
            }
        }
 public static void Load()
 {
     lock (_lock)
     {
         using (var db = new SqlDatabase <BubbleGroupSettings>(GetPath()))
         {
             var toRemoves = new List <BubbleGroupSettings>();
             foreach (var settings in db.Store.ToList())
             {
                 var bubbleGroup = BubbleGroupManager.Find(settings.Guid);
                 if (bubbleGroup == null)
                 {
                     toRemoves.Add(settings);
                 }
                 else
                 {
                     bubbleGroup.Settings = settings;
                 }
             }
             if (toRemoves.Any())
             {
                 foreach (var toRemove in toRemoves)
                 {
                     db.Remove(toRemove);
                 }
             }
         }
     }
 }
Esempio n. 7
0
        public static UnifiedBubbleGroup CreateUnified(List <BubbleGroup> groups, BubbleGroup primaryGroup)
        {
            lock (BubbleGroupDatabase.OperationLock)
            {
                var unifiedGroupsToKill = new HashSet <UnifiedBubbleGroup>();
                foreach (var group in groups)
                {
                    if (group.IsUnified)
                    {
                        unifiedGroupsToKill.Add(group.Unified);
                        @group.DeregisterUnified();
                    }
                }
                foreach (var unifiedGroup in unifiedGroupsToKill)
                {
                    BubbleGroupManager.BubbleGroupsRemove(unifiedGroup);
                }
                BubbleGroupIndex.RemoveUnified(unifiedGroupsToKill.Select(x => x.ID).ToArray());

                var unified = CreateUnifiedInternal(groups, primaryGroup);
                BubbleGroupIndex.AddUnified(unified);
                BubbleGroupManager.BubbleGroupsAdd(unified);
                BubbleGroupSettingsManager.SetUnreadIndicatorGuid(unified, unified.LastBubbleSafe().ID, false);
                return(unified);
            }
        }
Esempio n. 8
0
        public static void SendPresence(Service service, bool available, bool justAddIfNoLastPresence = false)
        {
            if (!service.Information.DoesSupport(typeof(PresenceBubble)))
            {
                return;
            }

            var presenceBubble = new PresenceBubble(Time.GetNowUnixTimestamp(),
                                                    Bubble.BubbleDirection.Outgoing, null,
                                                    false, service, available);

            Utils.DebugPrint("Sending " + (presenceBubble.Available
                ? "available"
                : "unavailble") + " to " +
                             presenceBubble.Service.Information.ServiceName);
            lock (LastPresenceBubbles)
            {
                Action a = () =>
                {
                    LastPresenceBubbles.RemoveAll(pb => pb.Service == presenceBubble.Service);
                    LastPresenceBubbles.Add(presenceBubble);
                };
                if (!justAddIfNoLastPresence)
                {
                    a();
                }
                else
                {
                    var hasPresence = LastPresenceBubbles.Any(x => x.Service == presenceBubble.Service);
                    if (hasPresence)
                    {
                        // do-nothing
                    }
                    else
                    {
                        a();
                    }
                }
            }

            if (!justAddIfNoLastPresence && ServiceManager.IsRunning(service))
            {
                Send(presenceBubble);
            }

            if (justAddIfNoLastPresence)
            {
                return;
            }

            if (available)
            {
                return;
            }
            foreach (var group in BubbleGroupManager.FindAll(service))
            {
                @group.PresenceType = PresenceBubble.PresenceType.Unavailable;
            }
        }
        public static void SetNotQueuedToFailures(BubbleGroup group)
        {
            var groups = BubbleGroupManager.GetInner(@group).Where(x => !x.PartiallyLoaded &&
                                                                   (x.Service.QueuedBubblesParameters != null &&
                                                                    x.Service.QueuedBubblesParameters.SendingBubblesToFailOnServiceStart != null &&
                                                                    x.Service.QueuedBubblesParameters.SendingBubblesToFailOnServiceStart.Any()));

            var failed = new List <Tuple <BubbleGroup, VisualBubble> >();

            foreach (var innerGroup in groups)
            {
                foreach (var bubble in innerGroup)
                {
                    if (bubble.Direction == Bubble.BubbleDirection.Outgoing &&
                        bubble.Status == Bubble.BubbleStatus.Waiting)
                    {
                        if (innerGroup
                            .Service.QueuedBubblesParameters.SendingBubblesToFailOnServiceStart
                            .FirstOrDefault(x => x == bubble.GetType()) != null)
                        {
                            failed.Add(new Tuple <BubbleGroup, VisualBubble>(innerGroup, bubble));
                        }
                    }
                }
            }

            if (!failed.Any())
            {
                return;
            }

            var somethingUpdated = false;

            var failuresGroupedByBubbleGroup = failed.GroupBy(x => x.Item1);

            foreach (var failureGroup in failuresGroupedByBubbleGroup)
            {
                var groupOfBubbles = failureGroup.First().Item1;
                var bubbles        = failureGroup.Select(x => x.Item2).ToArray();

                foreach (var bubble in bubbles)
                {
                    bubble.Status = Bubble.BubbleStatus.Failed;
                }
                BubbleGroupDatabase.UpdateBubble(groupOfBubbles, bubbles, groupOfBubbles.Bubbles.Count + 100); // 100 is really a tolerance here (just in case)
                foreach (var bubble in bubbles)
                {
                    BubbleGroupEvents.RaiseBubbleFailed(bubble, groupOfBubbles);
                }
                somethingUpdated = true;
            }

            if (somethingUpdated)
            {
                BubbleGroupEvents.RaiseBubblesUpdated(@group);
                BubbleGroupEvents.RaiseRefreshed(@group);
            }
        }
Esempio n. 10
0
            public Task <List <VisualBubble> > FetchNext()
            {
                return(Task.Factory.StartNew <List <VisualBubble> >(() =>
                {
                    if (_endReached)
                    {
                        return null;
                    }

                    lock (BubbleGroupDatabase.OperationLock)
                    {
                        var groups = BubbleGroupManager.GetInner(_group);
                        var groupCursors = groups.Select(@group => new Tuple <BubbleGroup, long>(@group, -1)).ToList();

                        var allBubbles = new List <VisualBubble>();

                        var handles = OpenDatabaseStreams(groups).ToList();

                        GetMoreBubbles:

                        var result = LoadDatabaseBubblesOnUnitInto(groups, _day, handles, groupCursors, _selection.BubbleTypes, _selection.Comparer);

                        var bubbles = result.Item1;
                        if (bubbles != null)
                        {
                            allBubbles.AddRange(bubbles);
                        }

                        groupCursors = result.Item2;
                        _day++;

                        var endReached = result.Item2.Count(cursor => cursor.Item2 == -2);
                        if (endReached == result.Item2.Count)
                        {
                            _endReached = true;
                            goto ReturnResult;
                        }
                        if (bubbles == null)
                        {
                            goto GetMoreBubbles;
                        }
                        if (allBubbles.Count < 100)
                        {
                            goto GetMoreBubbles;
                        }

                        ReturnResult:

                        CloseDatabaseStreams(handles);

                        allBubbles.TimSort((x, y) => - x.Time.CompareTo(y.Time));

                        return allBubbles;
                    }
                }));
            }
Esempio n. 11
0
        public static List <VisualBubble> FindAll(Service service, string address)
        {
            var bubbleGroup = BubbleGroupManager.FindWithAddress(service, address);

            if (bubbleGroup == null)
            {
                return(new List <VisualBubble>());
            }
            BubbleGroupFactory.LoadFullyIfNeeded(bubbleGroup);
            return(bubbleGroup.Bubbles.ToList());
        }
Esempio n. 12
0
        public static BubbleGroup AddNewIfNotExist(VisualBubble bubble, bool updateUi = false)
        {
            var group =
                BubbleGroupManager.FindWithAddress(bubble.Service, bubble.Address);

            if (@group != null)
            {
                return(null);
            }

            return(AddNewInternal(bubble, updateUi));
        }
Esempio n. 13
0
        public static void ResetSyncsIfHasAgent(Service service)
        {
            if (!SupportsSync(service))
            {
                return;
            }

            foreach (var group in BubbleGroupManager.FindAll(service))
            {
                group.NeedsSync = true;
            }
        }
        internal static void LoadAll()
        {
            lock (Lock)
            {
                var sw = new Stopwatch();
                sw.Start();

                var location = GetLocation();

                try
                {
                    if (File.Exists(location))
                    {
                        using (var fs = File.OpenRead(location))
                        {
                            var items = Serializer.Deserialize<List<BubbleGroupCache>>(fs);

                            foreach (var item in items)
                            {
                                var associatedGroup = BubbleGroupManager.Find(item.Guid);

                                if (associatedGroup == null)
                                {
                                    continue;
                                }

                                var unifiedGroup = associatedGroup as UnifiedBubbleGroup;
                                if (unifiedGroup != null)
                                {
                                    associatedGroup = unifiedGroup.PrimaryGroup;
                                }
                                Bind(associatedGroup, item);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Utils.DebugPrint("Failed to load bubble group cache: " + ex);
                    if (File.Exists(location))
                    {
                        File.Delete(location);
                    }
                }

                sw.Stop();
                Utils.DebugPrint("Loading bubble group cache took " + sw.ElapsedMilliseconds + "ms.");
            }
        }
Esempio n. 15
0
        internal static void UnloadFullLoad(BubbleGroup group)
        {
            var innerGroups = BubbleGroupManager.GetInner(@group);

            foreach (var innerGroup in innerGroups)
            {
                innerGroup.UnloadFullLoad();
            }
            var unifiedGroup = @group as UnifiedBubbleGroup;

            if (unifiedGroup != null)
            {
                unifiedGroup.UnloadFullUnifiedLoad();
            }
        }
Esempio n. 16
0
        public static bool UpdateQuotedMessageTitle(VisualBubble bubble, Action <string> onTitleUpdated)
        {
            var service = bubble.Service;

            if (!ServiceManager.IsRunning(service))
            {
                return(false);
            }
            if (string.IsNullOrWhiteSpace(bubble.QuotedAddress))
            {
                return(false);
            }

            try
            {
                service.GetQuotedMessageTitle(bubble, result =>
                {
                    var bubbleGroup = BubbleGroupManager.FindWithAddress(bubble.Service, bubble.Address);
                    if (bubbleGroup != null)
                    {
                        var quotedTitles = bubbleGroup.QuotedTitles == null ?
                                           new List <DisaQuotedTitle>() : bubbleGroup.QuotedTitles.ToList();
                        var quotedTitle = quotedTitles.FirstOrDefault(x =>
                                                                      bubbleGroup.Service.BubbleGroupComparer(x.Address, bubble.QuotedAddress));
                        if (quotedTitle == null)
                        {
                            quotedTitles.Add(new DisaQuotedTitle
                            {
                                Address = bubble.QuotedAddress,
                                Title   = result,
                            });
                        }
                        else
                        {
                            quotedTitle.Title = result;
                        }
                        bubbleGroup.QuotedTitles = quotedTitles.ToArray();
                    }
                    onTitleUpdated(result);
                });
                return(true);
            }
            catch (Exception e)
            {
                Utils.DebugPrint("Error getting quoted message title " + e);
                return(false);
            }
        }
Esempio n. 17
0
        public static void UpdateStatus(Service service, string bubbleId, Bubble.BubbleStatus status)
        {
            var serviceGroups = BubbleGroupManager.FindAll(service);

            foreach (var group in serviceGroups)
            {
                foreach (var bubble in @group)
                {
                    if (bubble.ID == bubbleId)
                    {
                        UpdateStatus(bubble, status, @group);
                        return;
                    }
                }
            }
        }
Esempio n. 18
0
        public static IEnumerable <VisualBubble> FindAllUnread(Service service, string address)
        {
            var bubbleGroup = BubbleGroupManager.FindWithAddress(service, address);

            if (bubbleGroup != null)
            {
                foreach (var bubble in bubbleGroup)
                {
                    if (bubble.Direction == Bubble.BubbleDirection.Incoming &&
                        bubble.Time >= BubbleGroupSettingsManager.GetLastUnreadSetTime(bubbleGroup))
                    {
                        yield return(bubble);
                    }
                }
            }
        }
Esempio n. 19
0
        public static void Update(Service service, string bubbleGroupAddress)
        {
            Utils.DebugPrint("Service: " + service.Information.ServiceName + " has called UpdateBubbleGroup with id: " + bubbleGroupAddress);

            var selectedGroup =
                BubbleGroupManager.FindWithAddress(service, bubbleGroupAddress);

            if (selectedGroup == null)
            {
                return;
            }
            Utils.DebugPrint("Updating " + selectedGroup.ID + " with name " + (selectedGroup.Title != null
                ? selectedGroup.Title
                : "[unknown]"));
            Update(selectedGroup);
        }
Esempio n. 20
0
        public static void SendSubscribe(Service service, bool subscribe)
        {
            if (!service.Information.DoesSupport(typeof(SubscribeBubble)))
            {
                return;
            }

            Utils.DebugPrint((subscribe
                ? "Subscribing"
                : "Unsubscribing") + " to " + service.Information.ServiceName
                             + " solo bubble groups.");

            foreach (var bubbleGroup in BubbleGroupManager.FindAll(g => !g.IsParty && g.Service == service))
            {
                SendSubscribe(bubbleGroup, subscribe);
            }
        }
Esempio n. 21
0
        public static bool ResetSyncsIfHasAgent(Service service, string bubbleGroupAddress)
        {
            if (!SupportsSync(service))
            {
                return(false);
            }

            foreach (var group in BubbleGroupManager.FindAll(service))
            {
                if (service.BubbleGroupComparer(group.Address, bubbleGroupAddress))
                {
                    group.NeedsSync = true;
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 22
0
        public static List <BubbleGroup> DeleteUnified(UnifiedBubbleGroup unifiedGroup, bool deleteInnerGroups = true)
        {
            lock (BubbleGroupDatabase.OperationLock)
            {
                foreach (var group in unifiedGroup.Groups)
                {
                    @group.DeregisterUnified();
                    if (deleteInnerGroups)
                    {
                        Delete(@group);
                    }
                }

                BubbleGroupManager.BubbleGroupsRemove(unifiedGroup);
                BubbleGroupIndex.RemoveUnified(unifiedGroup.ID);

                return(deleteInnerGroups ? null : unifiedGroup.Groups);
            }
        }
Esempio n. 23
0
        public static void SetNotQueuedToFailures(Service service)
        {
            if (service is UnifiedService)
            {
                return;
            }

            if (service.QueuedBubblesParameters == null ||
                service.QueuedBubblesParameters.BubblesNotToQueue == null ||
                !service.QueuedBubblesParameters.BubblesNotToQueue.Any())
            {
                return;
            }

            foreach (var group in BubbleGroupManager.FindAll(service))
            {
                SetNotQueuedToFailures(@group);
            }
        }
Esempio n. 24
0
        public static bool UpdateStatus(Service service, string bubbleGroupAddress,
                                        string bubbleId, Bubble.BubbleStatus status)
        {
            var group = BubbleGroupManager.FindWithAddress(service, bubbleGroupAddress);

            if (group == null)
            {
                return(false);
            }
            BubbleGroupFactory.LoadFullyIfNeeded(group);
            foreach (var bubble in @group.Bubbles)
            {
                if (bubble.ID == bubbleId)
                {
                    UpdateStatus(bubble, status, @group);
                    return(true);
                }
            }
            return(false);
        }
Esempio n. 25
0
        public static void Update(Service service, bool optimized = true)
        {
            const int Interval               = 5;
            var       updateCounter          = 0;
            var       groupsDoneCounter      = 0;
            var       groups                 = BubbleGroupManager.FindAll(service);
            var       updateCounterThreshold = groups.Count / Interval;

            foreach (var group in groups)
            {
                Action chainFinished = null;
                if (groups.Count >= Interval)
                {
                    chainFinished = () =>
                    {
                        Action <bool> doUpdate = singleton =>
                        {
                            BubbleGroupEvents.RaiseRefreshed(groups);
                            BubbleGroupEvents.RaiseBubblesUpdated(groups);
                            BubbleGroupEvents.RaiseInformationUpdated(groups);
                        };

                        groupsDoneCounter++;
                        if (groupsDoneCounter % Interval == 0)
                        {
                            updateCounter++;
                            doUpdate(false);
                        }
                        // do the remainder one by one ...
                        else if (updateCounter >= updateCounterThreshold)
                        {
                            doUpdate(true);
                        }
                    };
                }

                Update(@group, optimized, chainFinished);
            }
        }
Esempio n. 26
0
        private static BubbleGroup AddNewInternal(VisualBubble newBubble, bool raiseBubbleInserted)
        {
            var group = new BubbleGroup(newBubble, null, false);

            BubbleGroupSettingsManager.SetUnreadIndicatorGuid(group, group.LastBubbleSafe().ID, true);

            if (ServiceManager.IsRunning(@group.Service))
            {
                newBubble.Service.NewBubbleGroupCreated(@group).ContinueWith(x =>
                {
                    // force the UI to refetch the photo
                    @group.IsPhotoSetFromService = false;
                    BubbleManager.SendSubscribe(@group, true);
                    BubbleGroupUpdater.Update(@group);
                });
            }

            BubbleGroupManager.BubbleGroupsAdd(@group);

            BubbleGroupDatabase.AddBubble(@group, newBubble);

            if (raiseBubbleInserted)
            {
                try
                {
                    BubbleGroupEvents.RaiseBubbleInserted(newBubble, @group);
                }
                catch (Exception ex)
                {
                    Utils.DebugPrint(
                        "Error in notifying the interface that the bubble group has been updated (" +
                        newBubble.Service.Information.ServiceName + "): " + ex.Message);
                }
            }

            BubbleGroupUpdater.Update(@group);

            return(@group);
        }
Esempio n. 27
0
        public static void SetNotQueuedToFailures(BubbleGroup group)
        {
            var nowUnixTimeStamp = Time.GetNowUnixTimestamp();

            var groups = BubbleGroupManager.GetInner(@group).Where(x =>
                                                                   (x.Service.QueuedBubblesParameters != null &&
                                                                    x.Service.QueuedBubblesParameters.BubblesNotToQueue != null &&
                                                                    x.Service.QueuedBubblesParameters.BubblesNotToQueue.Any()));

            if (!groups.Any())
            {
                return;
            }

            foreach (var innerGroup in groups)
            {
                if (HasNotQueued(innerGroup))
                {
                    if (innerGroup.PartiallyLoaded)
                    {
                        BubbleGroupFactory.LoadFullyIfNeeded(innerGroup);
                    }

                    var bubblesSetToFailed = new List <VisualBubble>();

                    foreach (var bubble in innerGroup.Bubbles)
                    {
                        if (bubble.Direction == Bubble.BubbleDirection.Outgoing &&
                            bubble.Status == Bubble.BubbleStatus.Waiting)
                        {
                            if (innerGroup
                                .Service.QueuedBubblesParameters.BubblesNotToQueue
                                .FirstOrDefault(x => x == bubble.GetType()) != null)
                            {
                                var failBubble = innerGroup
                                                 .Service.QueuedBubblesParameters.SendingBubblesToFailOnServiceStart
                                                 .FirstOrDefault(x => x == bubble.GetType()) != null;

                                // Older than 10 minutes, fail it regardless.
                                if (!failBubble && bubble.Time < (nowUnixTimeStamp - 600))
                                {
                                    failBubble = true;
                                }

                                if (failBubble)
                                {
                                    RemoveNotQueued(bubble);
                                    bubble.Status = Bubble.BubbleStatus.Failed;
                                    bubblesSetToFailed.Add(bubble);
                                }
                            }
                        }
                    }

                    if (bubblesSetToFailed.Any())
                    {
                        BubbleGroupDatabase.UpdateBubble(innerGroup, bubblesSetToFailed.ToArray(), 100);
                        foreach (var bubble in bubblesSetToFailed)
                        {
                            BubbleGroupEvents.RaiseBubbleFailed(bubble, innerGroup);
                        }
                        BubbleGroupEvents.RaiseBubblesUpdated(innerGroup);
                        BubbleGroupEvents.RaiseRefreshed(innerGroup);
                    }
                }
            }

            NotQueuedSanityCheckup();
        }
        private static void StopInternal(Service registeredService, bool clearFailures = true)
        {
            if (!IsRegistered(registeredService))
            {
                throw new ServiceSchedulerException("Could not locate service "
                                                    + registeredService.Information.ServiceName + ". Are you sure you registered it?");
            }

            if (clearFailures)
            {
                ClearFailures(registeredService);
            }

            Action deAuthenticate = () =>
            {
                try
                {
                    registeredService.Deauthenticate();
                }
                catch (NotImplementedException)
                {
                }
                catch (Exception ex)
                {
                    GetFlags(registeredService).DeauthenticationFailed = true;
                    Utils.DebugPrint(registeredService.Information.ServiceName +
                                     "service failed to deauthenticate. "
                                     + "This may lead to a memory leak. Problem: " + ex.Message);
                }
            };

            Action disconnect = () =>
            {
                try
                {
                    registeredService.Disconnect();
                }
                catch (NotImplementedException)
                {
                }
                catch (Exception ex)
                {
                    GetFlags(registeredService).DisconnectionFailed = true;
                    Utils.DebugPrint(registeredService.Information.ServiceName +
                                     "service failed to disconnect. "
                                     + "This may lead to a memory leak. Problem: " + ex.Message);
                }
            };

            if (registeredService.Information.Procedure
                == ServiceInfo.ProcedureType.AuthenticateConnect)
            {
                deAuthenticate();
                disconnect();
            }
            else if (registeredService.Information.Procedure
                     == ServiceInfo.ProcedureType.ConnectAuthenticate)
            {
                disconnect();
                deAuthenticate();
            }

            //there may be exceptions, but we have to remove the service.
            GetFlags(registeredService).Running = false;

            foreach (
                var group in
                BubbleGroupManager.FindAll(
                    x => x.Service == registeredService && !(x is UnifiedBubbleGroup)))
            {
                @group.Typing       = false;
                @group.PresenceType = PresenceBubble.PresenceType.Unavailable;
            }
        }
        internal static void OnBubbleReceived(Bubble b)
        {
            var visualBubble = b as VisualBubble;

            if (visualBubble != null)
            {
                try
                {
                    BubbleManager.Group(visualBubble);
                }
                catch (Exception ex)
                {
                    Utils.DebugPrint("Problem in OnBubbleReceived (VisualBubble) from service " +
                                     visualBubble.Service.Information.ServiceName + ": " + ex.Message);
                }

                if (visualBubble.Direction == Bubble.BubbleDirection.Incoming &&
                    IsRunning(visualBubble.Service) &&
                    BubbleQueueManager.HasQueuedBubbles(b.Service.Information.ServiceName, true, true))
                {
                    Utils.DebugPrint("Sending queued bubbles as we're getting some received.");
                    BubbleQueueManager.Send(new [] { b.Service.Information.ServiceName });
                }
            }
            else if (b is AbstractBubble)
            {
                Utils.DebugPrint("We got an abstract bubble: " + b.GetType().Name + " Address: " + b.Address);

                BubbleGroup group = null;

                var deliveredBubble = b as DeliveredBubble;
                if (deliveredBubble != null)
                {
                    @group = BubbleGroupManager.FindWithAddress(deliveredBubble.Service, deliveredBubble.Address);

                    if (@group != null)
                    {
                        BubbleGroupFactory.LoadFullyIfNeeded(@group);

                        var bubbles = @group.Bubbles;

                        for (var i = bubbles.Count - 1; i >= 0; i--)
                        {
                            var bubble = bubbles[i];

                            if (bubble.ID != deliveredBubble.VisualBubbleID)
                            {
                                continue;
                            }

                            BubbleManager.UpdateStatus(bubble, Bubble.BubbleStatus.Delivered, @group);

                            if (@group.Service.Information.DoesSupport(typeof(DeliveredBubbleReceipt)))
                            {
                                BubbleManager.Send(new DeliveredBubbleReceipt(Time.GetNowUnixTimestamp(), Bubble.BubbleDirection.Outgoing,
                                                                              @group.Service, bubble));
                            }

                            break;
                        }
                    }
                }

                var readBubble = b as ReadBubble;
                if (readBubble != null)
                {
                    @group = BubbleGroupManager.FindWithAddress(readBubble.Service, readBubble.Address);
                    if (@group != null)
                    {
                        BubbleGroupFactory.LoadFullyIfNeeded(@group);

                        if (@group.ReadTimes == null || [email protected])
                        {
                            @group.ReadTimes = new []
                            {
                                new DisaReadTime
                                {
                                    ParticipantAddress = readBubble.ParticipantAddress,
                                    Time = readBubble.ReadTime
                                }
                            };
                        }
                        else
                        {
                            var readTimes = @group.ReadTimes.ToList();

                            var duplicateReadTime = readTimes.FirstOrDefault(x =>
                                                                             @group.Service.BubbleGroupComparer(x.ParticipantAddress, readBubble.ParticipantAddress));
                            if (duplicateReadTime != null)
                            {
                                readTimes.Remove(duplicateReadTime);
                            }

                            readTimes.Add(new DisaReadTime
                            {
                                ParticipantAddress = readBubble.ParticipantAddress,
                                Time = readBubble.ReadTime
                            });

                            @group.ReadTimes = readTimes.ToArray();
                        }
                    }
                }

                var prescenceBubble = b as PresenceBubble;
                if (prescenceBubble != null)
                {
                    @group = BubbleGroupManager.Find(bubbleGroup =>
                                                     !bubbleGroup.IsParty &&
                                                     bubbleGroup.Service ==
                                                     prescenceBubble.Service &&
                                                     prescenceBubble.Service.BubbleGroupComparer(
                                                         bubbleGroup.Address,
                                                         prescenceBubble.Address));

                    if (@group != null)
                    {
                        if ([email protected] && !prescenceBubble.Available)
                        {
                            var oldPresence = @group.PresenceType;
                            @group.PresenceType = PresenceBubble.PresenceType.Unavailable;
                            if (oldPresence != prescenceBubble.Presence)
                            {
                                BubbleGroupManager.UpdateLastOnline(@group);
                            }
                        }
                        else
                        {
                            @group.PresenceType         = prescenceBubble.Presence;
                            @group.PresencePlatformType = prescenceBubble.Platform;
                        }

                        if (!prescenceBubble.Available)
                        {
                            @group.Typing = false;
                        }
                    }
                }

                var typingBubble = b as TypingBubble;
                if (typingBubble != null)
                {
                    @group = BubbleGroupManager.Find(bubbleGroup =>
                                                     !bubbleGroup.IsParty &&
                                                     bubbleGroup.Service ==
                                                     typingBubble.Service &&
                                                     typingBubble.Service.BubbleGroupComparer(
                                                         bubbleGroup.Address,
                                                         typingBubble.Address));

                    if (@group != null)
                    {
                        if (@group.Presence)
                        {
                            @group.Typing        = typingBubble.Typing;
                            @group.TypingIsAudio = typingBubble.IsAudio;
                        }
                        else
                        {
                            @group.Typing = false;
                        }
                    }
                }

                try
                {
                    if (@group != null)
                    {
                        BubbleGroupEvents.RaiseNewAbstractBubble(b as AbstractBubble, @group);
                    }
                }
                catch (Exception ex)
                {
                    Utils.DebugPrint("Problem in OnBubbleReceived (AbstractBubble) from service " +
                                     b.Service.Information.ServiceName + ": " + ex.Message);
                }
            }
        }
        public static Task Start(Service service, bool smartStart = false, int smartStartSeconds = 10)
        {
            return(Task.Factory.StartNew(() =>
            {
                using (var wakeLock = Platform.AquireWakeLock("DisaStart"))
                {
                    if (IsRunning(service))
                    {
                        Utils.DebugPrint(
                            "The service is already running. Preventing possible deadlock. SmartStart? " +
                            smartStart);
                        return;
                    }

                    if (IsStarting(service))
                    {
                        Utils.DebugPrint(
                            "The service is being started. Preventing possible deadlock. SmartStart? " +
                            smartStart);
                        return;
                    }

                    Action epilogue = () => { GetFlags(service).Starting = false; };

                    lock (service)
                    {
                        GetFlags(service).Aborted = false;
                        GetFlags(service).AbortedSpecial = false;
                        GetFlags(service).Starting = true;
                        GetFlags(service).ManualSettingsNeeded = false;

                        Utils.DebugPrint("Loading settings for service " + service.Information.ServiceName);
                        try
                        {
                            var settings = SettingsManager.Load(service);
                            if (settings == null)
                            {
                                Utils.DebugPrint("Failed to load saved settings for "
                                                 + service.Information.ServiceName +
                                                 ". Will try to initialize with no settings...");
                                if (!service.InitializeDefault())
                                {
                                    Utils.DebugPrint(
                                        "Service doesn't allow initializing without settings. Needs manual input.");
                                    GetFlags(service).ManualSettingsNeeded = true;
                                    ServiceEvents.RaiseServiceManualSettingsNeeded(service);
                                }
                                else
                                {
                                    Utils.DebugPrint("Service initialized under no settings.");
                                }
                            }
                            else
                            {
                                Utils.DebugPrint("Loading saved settings! Initializing...");
                                if (service.Initialize(settings))
                                {
                                    Utils.DebugPrint("Successfully initialized service!");
                                }
                                else
                                {
                                    Utils.DebugPrint("Failed to initialize service. Needs manual input.");
                                    GetFlags(service).ManualSettingsNeeded = true;
                                    ServiceEvents.RaiseServiceManualSettingsNeeded(service);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Utils.DebugPrint("Failed: " + ex);
                            epilogue();
                            return;
                        }

                        Utils.DebugPrint("Starting service " + service.Information.ServiceName);

                        try
                        {
                            if (service.Information.UsesInternet &&
                                !Platform.HasInternetConnection())
                            {
                                throw new Exception("No internet connection. Cannot connect service: "
                                                    + service.Information.ServiceName);
                            }

                            StartInternal(service, wakeLock);
                        }
                        catch (ServiceSchedulerException ex)
                        {
                            Utils.DebugPrint("Problem in scheduler: " + ex.Message);
                            epilogue();
                            return;
                        }
                        catch (ServiceSpecialRestartException)
                        {
                            Utils.DebugPrint("Service " + service.Information.ServiceName +
                                             " is asking to be restarted on connect/authenticate. This should be called sparingly, Disa can easily " +
                                             "break under these circumstances. Restarting...");
                            StopInternal(service);
                            epilogue();
                            Start(service, smartStart, smartStartSeconds);
                            return;
                        }
                        catch (ServiceExpiredException)
                        {
                            Utils.DebugPrint("The service " + service.Information.ServiceName +
                                             " has expired. :(");
                            GetFlags(service).Aborted = true;
                            GetFlags(service).Expired = true;
                            ServiceEvents.RaiseServiceExpired(service);
                            StopInternal(service);
                            epilogue();
                            return;
                        }
                        catch (Exception ex)
                        {
                            if (smartStart)
                            {
                                StopInternal(service, false);

                                if (smartStartSeconds > 600)
                                {
                                    Utils.DebugPrint("Service " + service.Information.ServiceName +
                                                     " needs to wait over 10minutes to be restarted." +
                                                     " Killing SmartStart. The service will not be restarted. Reason: " + ex);
                                    epilogue();
                                    return;
                                }

                                Utils.DebugPrint("Service " + service.Information.ServiceName +
                                                 " failed to be started. SmartStart enabled. "
                                                 + "Service being scheduled to be re-started in T-" +
                                                 smartStartSeconds + " seconds! Reason: " + ex);

                                var hasSmartStart = new object();
                                service.HasSmartStart = hasSmartStart;

                                Platform.ScheduleAction(smartStartSeconds,
                                                        new WakeLockBalancer.ActionObject(() =>
                                {
                                    if (IsAborted(service))
                                    {
                                        Utils.DebugPrint(
                                            "Service " +
                                            service.Information
                                            .ServiceName +
                                            " tried to be started, but it deemed killed.");
                                        return;
                                    }

                                    if (service.HasSmartStart !=
                                        hasSmartStart)
                                    {
                                        Utils.DebugPrint(
                                            "This smart start has been invalidated. There " +
                                            "seems to be another one on the block.");
                                        return;
                                    }

                                    Utils.DebugPrint(
                                        "Smart start is firing the service " +
                                        service.Information
                                        .ServiceName +
                                        " up again!");

                                    StopInternal(service);
                                    Start(service, true, smartStartSeconds * 2);
                                }, WakeLockBalancer.ActionObject.ExecuteType.TaskWithWakeLock));

                                epilogue();
                                return;
                            }

                            Utils.DebugPrint("Failed to start service " + service.Information.ServiceName +
                                             " (No SmartStart) : " + ex);
                            StopInternal(service, false);
                            epilogue();
                            return;
                        }

                        BubbleManager.SendSubscribe(service, true);
                        BubbleManager.SendLastPresence(service);

                        service.ReceivingBubblesThread = new Thread(() =>
                        {
                            try
                            {
                                StartReceiveBubbles(service);
                            }
                            catch (ThreadAbortException)
                            {
                                Utils.DebugPrint(
                                    "Abort thread excepton in receiving bubbles on service (outer thread) " +
                                    service.Information.ServiceName);
                            }
                            catch (Exception ex)
                            {
                                Utils.DebugPrint(">>>>>>>>> " + ex.Message + " " + ex.StackTrace);
                            }
                            Utils.DebugPrint("Receiving bubbles for service " +
                                             service.Information.ServiceName + " has come to an end.");
                        });
                        service.ReceivingBubblesThread.Start();

                        GetFlags(service).Starting = false;

                        BubbleManager.SetNotQueuedToFailures(service);

                        Utils.Delay(1000).ContinueWith(x =>
                        {
                            BubbleGroupSync.ResetSyncsIfHasAgent(service);
                            BubbleGroupUpdater.Update(service);
                            BubbleQueueManager.Send(new[] { service.Information.ServiceName });
                            BubbleGroupManager.ProcessUpdateLastOnlineQueue(service);
                        });
                    }
                }
            }));
        }