1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2017-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #include <stdlib.h>
19 #include <mailutils/types.h>
20 #include <mailutils/assoc.h>
21 #include <mailutils/locus.h>
22 #include <mailutils/error.h>
23 #include <mailutils/errno.h>
24 #include <mailutils/diag.h>
25 #include <mailutils/list.h>
26 #include <mailutils/io.h>
27 #include <mailutils/stream.h>
28 #include <mailutils/iterator.h>
29
30 struct mu_ident_ref
31 {
32 size_t count;
33 };
34
35 static mu_assoc_t nametab;
36
37 int
mu_ident_ref(char const * name,char const ** refname)38 mu_ident_ref (char const *name, char const **refname)
39 {
40 int rc;
41 struct mu_ident_ref *ref, **refptr;
42
43 if (!refname)
44 return MU_ERR_OUT_PTR_NULL;
45 if (!name)
46 {
47 *refname = NULL;
48 return 0;
49 }
50
51 if (!nametab)
52 {
53 rc = mu_assoc_create (&nametab, 0);
54 if (rc)
55 {
56 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc);
57 return rc;
58 }
59 mu_assoc_set_destroy_item (nametab, mu_list_free_item);
60 }
61 rc = mu_assoc_install_ref2 (nametab, name, &refptr, refname);
62 switch (rc)
63 {
64 case 0:
65 ref = malloc (sizeof *ref);
66 if (!ref)
67 {
68 rc = errno;
69 mu_assoc_remove (nametab, name);
70 return rc;
71 }
72 *refptr = ref;
73 ref->count = 0;
74 break;
75
76 case MU_ERR_EXISTS:
77 ref = *refptr;
78 break;
79
80 default:
81 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_install_ref2", name, rc);
82 return rc;
83 }
84
85 ref->count++;
86 return 0;
87 }
88
89 int
mu_ident_deref(char const * name)90 mu_ident_deref (char const *name)
91 {
92 struct mu_ident_ref *ref;
93 int rc;
94
95 if (!name || !nametab)
96 return 0;
97
98 rc = mu_assoc_lookup (nametab, name, &ref);
99 switch (rc)
100 {
101 case 0:
102 if (--ref->count == 0)
103 mu_assoc_remove (nametab, name);
104 break;
105
106 case MU_ERR_NOENT:
107 break;
108
109 default:
110 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_lookup", name, rc);
111 return rc;
112 }
113
114 return 0;
115 }
116
117 void
mu_ident_stat(mu_stream_t str)118 mu_ident_stat (mu_stream_t str)
119 {
120 size_t count, i;
121 mu_iterator_t itr;
122
123 mu_stream_printf (str, "BEGIN IDENT STAT\n");
124
125 mu_assoc_count (nametab, &count);
126 mu_stream_printf (str, "N=%zu\n", count);
127
128 if (count > 0)
129 {
130 int rc = mu_assoc_get_iterator (nametab, &itr);
131 if (rc)
132 mu_stream_printf (str, "mu_assoc_get_iterator: %s\n",
133 mu_strerror (rc));
134 else
135 {
136 i = 0;
137 for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
138 mu_iterator_next (itr), i++)
139 {
140 const char *key;
141 struct mu_ident_ref *ref;
142
143 mu_iterator_current_kv (itr,
144 (const void **)&key, (void **)&ref);
145 mu_stream_printf (str, "%04zu: %s: %zu\n", i, key, ref->count);
146 }
147 }
148 mu_iterator_destroy (&itr);
149 }
150 mu_stream_printf (str, "END IDENT STAT\n");
151 }
152
153