Added stubs for SendIMEMessageEx[A,W].
[wine] / dlls / netapi32 / nbnamecache.c
1 /* Copyright (c) 2003 Juan Lang
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  * This implementation uses a linked list, because I don't have a decent
18  * hash table implementation handy.  This is somewhat inefficient, but it's
19  * rather more efficient than not having a name cache at all.
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include "nbnamecache.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(netbios);
29
30 typedef struct _NBNameCacheNode
31 {
32     DWORD expireTime;
33     NBNameCacheEntry *entry;
34     struct _NBNameCacheNode *next;
35 } NBNameCacheNode;
36
37 struct NBNameCache
38 {
39     HANDLE heap;
40     CRITICAL_SECTION cs;
41     DWORD entryExpireTimeMS;
42     NBNameCacheNode *head;
43 };
44
45 /* Unlinks the node pointed to by *prev, and frees any associated memory.
46  * If that node's next pointed to another node, *prev now points to it.
47  * Assumes the caller owns cache's lock.
48  */
49 static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
50  NBNameCacheNode **prev)
51 {
52     if (cache && prev && *prev)
53     {
54         NBNameCacheNode *next = (*prev)->next;
55
56         HeapFree(cache->heap, 0, (*prev)->entry);
57         HeapFree(cache->heap, 0, *prev);
58         *prev = next;
59     }
60 }
61
62 /* Walks the list beginning with cache->head looking for the node with name
63  * name.  If the node is found, returns a pointer to the next pointer of the
64  * node _prior_ to the found node (or head if head points to it).  Thus, if the
65  * node's all you want, dereference the return value twice.  If you want to
66  * modify the list, modify the referent of the return value.
67  * While it's at it, deletes nodes whose time has expired (except the node
68  * you're looking for, of course).
69  * Returns NULL if the node isn't found.
70  * Assumes the caller owns cache's lock.
71  */
72 static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache,
73  const char name[NCBNAMSZ])
74 {
75     NBNameCacheNode **ret = NULL;
76
77     if (cache && cache->head)
78     {
79         NBNameCacheNode **ptr;
80
81         ptr = &cache->head;
82         while (ptr && *ptr && (*ptr)->entry)
83         {
84             if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1))
85                 ret = ptr;
86             else
87             {
88                 if (GetTickCount() > (*ptr)->expireTime)
89                     NBNameCacheUnlinkNode(cache, ptr);
90             }
91             if (*ptr)
92                 ptr = &(*ptr)->next;
93         }
94     }
95     return ret;
96 }
97
98 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
99 {
100     struct NBNameCache *cache;
101     
102     
103     if (!heap)
104         heap = GetProcessHeap();
105     cache = (struct NBNameCache *)HeapAlloc(heap, 0,
106      sizeof(struct NBNameCache));
107     if (cache)
108     {
109         cache->heap = heap;
110         InitializeCriticalSection(&cache->cs);
111         cache->entryExpireTimeMS = entryExpireTimeMS;
112         cache->head = NULL;
113     }
114     return cache;
115 }
116
117 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
118 {
119     BOOL ret;
120
121     if (cache && entry)
122     {
123         NBNameCacheNode **node;
124
125         EnterCriticalSection(&cache->cs);
126         node = NBNameCacheWalk(cache, entry->name);
127         if (node)
128         {
129             (*node)->expireTime = GetTickCount() +
130              cache->entryExpireTimeMS;
131             HeapFree(cache->heap, 0, (*node)->entry);
132             (*node)->entry = entry;
133             ret = TRUE;
134         }
135         else
136         {
137             NBNameCacheNode *newNode = (NBNameCacheNode *)HeapAlloc(
138              cache->heap, 0, sizeof(NBNameCacheNode));
139             if (newNode)
140             {
141                 newNode->expireTime = GetTickCount() +
142                  cache->entryExpireTimeMS;
143                 newNode->entry = entry;
144                 newNode->next = cache->head;
145                 cache->head = newNode;
146                 ret = TRUE;
147             }
148             else
149                 ret = FALSE;
150         }
151         LeaveCriticalSection(&cache->cs);
152     }
153     else
154         ret = FALSE;
155     return ret;
156 }
157
158 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
159  const UCHAR name[NCBNAMSZ])
160 {
161     const NBNameCacheEntry *ret;
162     UCHAR printName[NCBNAMSZ];
163
164     memcpy(printName, name, NCBNAMSZ - 1);
165     printName[NCBNAMSZ - 1] = '\0';
166     if (cache)
167     {
168         NBNameCacheNode **node;
169
170         EnterCriticalSection(&cache->cs);
171         node = NBNameCacheWalk(cache, name);
172         if (node)
173             ret = (*node)->entry;
174         else
175             ret = NULL;
176         LeaveCriticalSection(&cache->cs);
177     }
178     else
179         ret = NULL;
180     return ret;
181 }
182
183 BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
184  const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
185 {
186     BOOL ret;
187
188     if (cache)
189     {
190         NBNameCacheNode **node;
191
192         EnterCriticalSection(&cache->cs);
193         node = NBNameCacheWalk(cache, name);
194         if (node && *node && (*node)->entry)
195         {
196             memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
197             ret = TRUE;
198         }
199         else
200             ret = FALSE;
201         LeaveCriticalSection(&cache->cs);
202     }
203     else
204         ret = FALSE;
205     return ret;
206 }
207
208 void NBNameCacheDestroy(struct NBNameCache *cache)
209 {
210     if (cache)
211     {
212         DeleteCriticalSection(&cache->cs);
213         while (cache->head)
214             NBNameCacheUnlinkNode(cache, &cache->head);
215         HeapFree(cache->heap, 0, cache);
216     }
217 }