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