Add signature info to verify category
[gpgol.git] / src / categorymanager.cpp
1 /* @file categorymanager.cpp
2  * @brief Handles category management
3  *
4  * Copyright (C) 2018 Intevation GmbH
5  *
6  * This file is part of GpgOL.
7  *
8  * GpgOL is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * GpgOL is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "categorymanager.h"
23 #include "common.h"
24 #include "mail.h"
25 #include "gpgoladdin.h"
26 #include "oomhelp.h"
27
28 #include <unordered_map>
29
30 class CategoryManager::Private
31 {
32 public:
33   Private()
34   {
35   }
36
37   void createCategory (shared_disp_t store,
38                        const std::string &category, int color)
39     {
40       TSTART;
41       LPDISPATCH categories = get_oom_object (store.get(), "Categories");
42       if (!categories)
43         {
44           STRANGEPOINT;
45           TRETURN;
46         }
47       if (create_category (categories, category.c_str (), color))
48         {
49           log_debug ("%s:%s: Failed to create category %s",
50                      SRCNAME, __func__, anonstr (category.c_str()));
51           TRETURN;
52         }
53       TRETURN;
54     }
55
56   void registerCategory (const std::string &storeID,
57                          const std::string &category)
58     {
59       TSTART;
60       auto storeIt = mCategoryStoreMap.find (storeID);
61       if (storeIt == mCategoryStoreMap.end())
62         {
63           /* First category for this store. Create a new
64              category ref map. */
65           std::unordered_map <std::string, int> categoryMap;
66           categoryMap.insert (std::make_pair (category, 1));
67           mCategoryStoreMap.insert (std::make_pair (storeID, categoryMap));
68           log_debug ("%s:%s: Register category %s in new store %s ref now 1",
69                      SRCNAME, __func__, anonstr (category.c_str()),
70                      anonstr (storeID.c_str()));
71           TRETURN;
72         }
73       auto categoryIt = storeIt->second.find (category);
74       if (categoryIt == storeIt->second.end ())
75         {
76           storeIt->second.insert (std::make_pair (category, 1));
77           log_debug ("%s:%s: Register category %s in store %s ref now 1",
78                      SRCNAME, __func__, anonstr (category.c_str()),
79                      anonstr (storeID.c_str()));
80         }
81       else
82         {
83           categoryIt->second++;
84           log_debug ("%s:%s: Register category %s in store %s ref now %i",
85                      SRCNAME, __func__, anonstr (category.c_str()),
86                      anonstr (storeID.c_str()), categoryIt->second);
87         }
88       TRETURN;
89     }
90
91   void unregisterCategory (const std::string &storeID,
92                            const std::string &category)
93     {
94       TSTART;
95       auto storeIt = mCategoryStoreMap.find (storeID);
96       if (storeIt == mCategoryStoreMap.end ())
97         {
98           log_error ("%s:%s: Unregister called for unregistered store %s",
99                      SRCNAME, __func__, anonstr (storeID.c_str()));
100           TRETURN;
101         }
102       auto categoryIt = storeIt->second.find (category);
103       if (categoryIt == storeIt->second.end ())
104         {
105           log_debug ("%s:%s: Unregister %s not found for store %s",
106                      SRCNAME, __func__, anonstr (category.c_str()),
107                      anonstr (storeID.c_str()));
108           TRETURN;
109         }
110       categoryIt->second--;
111       log_debug ("%s:%s: Unregister category %s in store %s ref now %i",
112                  SRCNAME, __func__, anonstr (category.c_str()),
113                  anonstr (storeID.c_str()), categoryIt->second);
114       if (categoryIt->second < 0)
115         {
116           log_debug ("%s:%s: Unregister %s negative for store %s",
117                      SRCNAME, __func__, anonstr (category.c_str()),
118                      anonstr (storeID.c_str()));
119           TRETURN;
120         }
121       if (categoryIt->second == 0)
122         {
123           log_debug ("%s:%s: Deleting %s for store %s",
124                      SRCNAME, __func__, anonstr (category.c_str()),
125                      anonstr (storeID.c_str()));
126
127           LPDISPATCH store = get_store_for_id (storeID.c_str());
128           if (!store)
129             {
130               STRANGEPOINT;
131               TRETURN;
132             }
133           delete_category (store, category.c_str ());
134           storeIt->second.erase (categoryIt);
135         }
136       TRETURN;
137     }
138
139   bool categoryExistsInMap (const std::string &storeID,
140                             const std::string &category)
141     {
142       const auto it = mCategoryStoreMap.find (storeID);
143       if (it == mCategoryStoreMap.end ())
144         {
145           return false;
146         }
147       return it->second.find (category) != it->second.end();
148     }
149
150 private:
151   /* Map from: store to map of category -> refs. */
152   std::unordered_map<std::string,
153     std::unordered_map<std::string, int> > mCategoryStoreMap;
154 };
155
156 /* static */
157 std::shared_ptr <CategoryManager>
158 CategoryManager::instance ()
159 {
160   return GpgolAddin::get_instance ()->get_category_mngr ();
161 }
162
163 CategoryManager::CategoryManager():
164   d(new Private)
165 {
166 }
167
168 std::string
169 CategoryManager::addCategoryToMail (Mail *mail, const std::string &category, int color)
170 {
171   TSTART;
172   std::string ret;
173   if (!mail || category.empty())
174     {
175       TRETURN ret;
176     }
177
178   auto store = MAKE_SHARED (get_oom_object (mail->item (), "Parent.Store"));
179   if (!store)
180     {
181       log_error ("%s:%s Failed to obtain store",
182                  SRCNAME, __func__);
183       TRETURN std::string ();
184     }
185   char *storeID = get_oom_string (store.get (), "StoreID");
186   if (!storeID)
187     {
188       log_error ("%s:%s Failed to obtain storeID",
189                  SRCNAME, __func__);
190       TRETURN std::string ();
191     }
192   ret = storeID;
193   xfree (storeID);
194
195   if (!d->categoryExistsInMap (ret, category))
196     {
197       d->createCategory (store, category, color);
198     }
199   d->registerCategory (ret, category);
200
201   if (add_category (mail->item (), category.c_str()))
202     {
203       /* Probably the category already existed there
204          so it is not super worrysome. */
205       log_debug ("%s:%s Failed to add category.",
206                  SRCNAME, __func__);
207     }
208   return ret;
209 }
210
211 void
212 CategoryManager::removeCategory (Mail *mail, const std::string &category)
213 {
214   TSTART;
215   if (!mail || category.empty())
216     {
217       STRANGEPOINT;
218       TRETURN;
219     }
220   if (remove_category (mail->item (), category.c_str (), true))
221     {
222       log_debug ("%s:%s Failed to remvoe category.",
223                  SRCNAME, __func__);
224     }
225   d->unregisterCategory (mail->storeID (), category.c_str ());
226
227   TRETURN;
228 }
229
230 /* static */
231 void
232 CategoryManager::removeAllGpgOLCategories ()
233 {
234   TSTART;
235   delete_all_categories_starting_with ("GpgOL: ");
236   TRETURN;
237 }
238
239 /* static */
240 const std::string &
241 CategoryManager::getEncMailCategory ()
242 {
243   static std::string decStr;
244   if (decStr.empty())
245     {
246       decStr = std::string ("GpgOL: ") +
247                             std::string (_("Encrypted Message"));
248     }
249   return decStr;
250 }