]> git.ipfire.org Git - thirdparty/sarg.git/blame - userinfo.c
Explicitly link against the math library
[thirdparty/sarg.git] / userinfo.c
CommitLineData
f2ec8c75
FM
1/*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
67302a9e 3 * 1998, 2013
f2ec8c75
FM
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27#include "include/conf.h"
28#include "include/defs.h"
b6b6cb8c 29#include "include/stringbuffer.h"
c4f0ea8f 30#include "include/alias.h"
f2ec8c75
FM
31
32//! The number of users to group in one unit.
33#define USERS_PER_GROUP 50
34
35/*! \brief Group the users in one allocation unit.
36Structure to store a group of users and reduce the number of memory
37allocations.
38*/
39struct usergroupstruct
40{
9bd92830
FM
41 //! The next group of users.
42 struct usergroupstruct *next;
43 //! A group of users.
44 struct userinfostruct list[USERS_PER_GROUP];
45 //! The number of users stored in the list.
46 int nusers;
f2ec8c75
FM
47};
48
93551487
FM
49/*! \brief Hold pointer to scan through the user list.
50*/
51struct userscanstruct
52{
53 //! The group containing the user.
54 struct usergroupstruct *group;
55 //! The index of the user in the group.
56 int index;
57};
58
f2ec8c75
FM
59//! The first group of users.
60static struct usergroupstruct *first_user_group=NULL;
829a53c2
FM
61//! The counter to generate unique user number when ::AnonymousOutputFiles is set.
62static int AnonymousCounter=0;
b6b6cb8c
FM
63//! String buffer to store the user's related constants.
64static StringBufferObject UserStrings=NULL;
c4f0ea8f
FM
65//! User aliases.
66static AliasObject UserAliases=NULL;
f2ec8c75 67
aa6ac9f2 68struct userinfostruct *userinfo_create(const char *userid,const char *ip)
f2ec8c75 69{
9bd92830
FM
70 struct usergroupstruct *group, *last;
71 struct userinfostruct *user;
d09d93c6 72 int i, j, lastuser;
9bd92830
FM
73 int skip;
74 int flen;
75 int count, clen;
76 char cstr[9];
b6b6cb8c
FM
77 char filename[MAX_USER_FNAME_LEN];
78
79 if (!UserStrings) {
80 UserStrings=StringBuffer_Create();
81 if (!UserStrings) {
82 debuga(_("Not enough memory to store the user's strings\n"));
83 exit(EXIT_FAILURE);
84 }
85 }
9bd92830
FM
86
87 last=NULL;
88 for (group=first_user_group ; group ; group=group->next) {
89 if (group->nusers<USERS_PER_GROUP) break;
90 last=group;
91 }
92
93 if (!group) {
94 group=malloc(sizeof(*group));
95 if (!group) {
b6b6cb8c 96 debuga(_("Not enough memory to store user \"%s\"\n"),userid);
9bd92830
FM
97 exit(EXIT_FAILURE);
98 }
99 memset(group,0,sizeof(*group));
100 if (last)
101 last->next=group;
102 else
103 first_user_group=group;
104 }
105 user=group->list+group->nusers++;
106
b6b6cb8c
FM
107 user->id=StringBuffer_Store(UserStrings,userid);
108 if (!user->id) {
109 debuga(_("Not enough memory to store user ID \"%s\"\n"),userid);
110 exit(EXIT_FAILURE);
111 }
112 user->label=user->id; //assign a label to avoid a NULL pointer in case none is provided
aa6ac9f2 113 if (ip) {
dc34d345 114 user->id_is_ip=false;
aa6ac9f2
FM
115 user->ip=StringBuffer_Store(UserStrings,ip);
116 } else {
dc34d345 117 user->id_is_ip=true;
aa6ac9f2
FM
118 user->ip=user->id;
119 }
9bd92830 120
829a53c2 121 if (AnonymousOutputFiles) {
b6b6cb8c 122 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
829a53c2
FM
123 } else {
124 skip=0;
125 j=0;
126 for (i=0 ; userid[i] && j<MAX_USER_FNAME_LEN-1 ; i++) {
127 if (isalnum(userid[i]) || userid[i]=='-' || userid[i]=='_') {
b6b6cb8c 128 filename[j++]=userid[i];
829a53c2
FM
129 skip=0;
130 } else {
131 if (!skip) {
b6b6cb8c 132 filename[j++]='_';
829a53c2
FM
133 skip=1;
134 }
9bd92830
FM
135 }
136 }
b6b6cb8c 137 if (j==0) filename[j++]='_'; //don't leave a file name empty
4754959e 138 flen=j;
b6b6cb8c 139 filename[j]='\0';
829a53c2
FM
140
141 count=0;
142 for (group=first_user_group ; group ; group=group->next) {
143 lastuser=(group->next) ? group->nusers : group->nusers-1;
144 for (i=0 ; i<lastuser ; i++) {
b6b6cb8c 145 if (strcasecmp(filename,group->list[i].filename)==0) {
4754959e 146 clen=sprintf(cstr,"+%X",count++);
829a53c2 147 if (flen+clen<MAX_USER_FNAME_LEN)
b6b6cb8c 148 strcpy(filename+flen,cstr);
829a53c2 149 else
b6b6cb8c 150 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
829a53c2 151 }
9bd92830
FM
152 }
153 }
154 }
b6b6cb8c
FM
155 user->filename=StringBuffer_Store(UserStrings,filename);
156 if (!user->filename)
157 {
158 debuga(_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
159 exit(EXIT_FAILURE);
160 }
9bd92830
FM
161
162 return(user);
f2ec8c75
FM
163}
164
165void userinfo_free(void)
166{
9bd92830 167 struct usergroupstruct *group, *next;
f2ec8c75 168
9bd92830
FM
169 for (group=first_user_group ; group ; group=next) {
170 next=group->next;
171 free(group);
172 }
173 first_user_group=NULL;
b6b6cb8c
FM
174 StringBuffer_Destroy(&UserStrings);
175}
176
177/*!
178 * Store the user's label.
179 * \param uinfo The user info structure created by userinfo_create().
180 * \param label The string label to store.
181 */
182void userinfo_label(struct userinfostruct *uinfo,const char *label)
183{
184 if (!uinfo) return;
185 if (!UserStrings) return;
186 uinfo->label=StringBuffer_Store(UserStrings,label);
187 if (!uinfo->label) {
188 debuga(_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
189 exit(EXIT_FAILURE);
190 }
f2ec8c75
FM
191}
192
193struct userinfostruct *userinfo_find_from_file(const char *filename)
194{
9bd92830
FM
195 struct usergroupstruct *group;
196 int i;
197
198 for (group=first_user_group ; group ; group=group->next) {
199 for (i=0 ; i<group->nusers ; i++)
200 if (strcmp(filename,group->list[i].filename)==0)
201 return(group->list+i);
202 }
203 return(NULL);
f2ec8c75
FM
204}
205
206struct userinfostruct *userinfo_find_from_id(const char *id)
207{
9bd92830
FM
208 struct usergroupstruct *group;
209 int i;
210
211 for (group=first_user_group ; group ; group=group->next) {
212 for (i=0 ; i<group->nusers ; i++)
213 if (strcmp(id,group->list[i].id)==0)
214 return(group->list+i);
215 }
216 return(NULL);
f2ec8c75 217}
93551487 218
05fea6e7
FM
219struct userinfostruct *userinfo_find_from_ip(const char *ip)
220{
221 struct usergroupstruct *group;
222 int i;
223
224 for (group=first_user_group ; group ; group=group->next) {
225 for (i=0 ; i<group->nusers ; i++)
226 if (strcmp(ip,group->list[i].ip)==0)
227 return(group->list+i);
228 }
229 return(NULL);
230}
231
93551487
FM
232/*!
233Start the scanning of the user list.
234
235\return The object to pass to subsequent scanning functions or NULL
236if it failed. The object must be freed with a call to userinfo_stop().
237*/
238userscan userinfo_startscan(void)
239{
240 userscan uscan;
241
242 uscan=malloc(sizeof(*uscan));
243 if (!uscan) return(NULL);
244 uscan->group=first_user_group;
245 uscan->index=0;
246 return(uscan);
247}
248
249/*!
250Free the memory allocated by userinfo_start().
251
252\param uscan The object created by userinfo_start().
253*/
254void userinfo_stopscan(userscan uscan)
255{
256 free(uscan);
257}
258
259/*!
260Get the user pointed to by the object and advance the object
261to the next user.
262
263\param uscan The object created by userinfo_start().
264
265\return The user in the list or NULL if the end of the list
266is reached.
267*/
268struct userinfostruct *userinfo_advancescan(userscan uscan)
269{
270 struct userinfostruct *uinfo;
271
272 if (!uscan) return(NULL);
273 if (!uscan->group) return(NULL);
274 if (uscan->index<0 || uscan->index>=uscan->group->nusers) return(NULL);
275
276 uinfo=uscan->group->list+uscan->index;
277
278 ++uscan->index;
279 if (uscan->index>=uscan->group->nusers) {
280 uscan->group=uscan->group->next;
281 uscan->index=0;
282 }
283 return(uinfo);
284}
a58e6d54
FM
285
286/*!
287Clear the general purpose flag from all the user's info.
288*/
289void userinfo_clearflag(void)
290{
291 struct usergroupstruct *group;
292 int i;
293
294 for (group=first_user_group ; group ; group=group->next) {
295 for (i=0 ; i<group->nusers ; i++)
296 group->list[i].flag=0;
297 }
298}
299
c4f0ea8f
FM
300/*!
301Read the file containing the user names to alias in the report.
302
303\param Filename The name of the file.
304*/
305void read_useralias(const char *Filename)
306{
307 FILE *fi;
308 longline line;
309 char *buf;
310
311 if (debug) debuga(_("Reading user alias file \"%s\"\n"),Filename);
312
313 UserAliases=Alias_Create();
314 if (!UserAliases) {
315 debuga(_("Cannot store user's aliases\n"));
316 exit(EXIT_FAILURE);
317 }
318
319 fi=fopen(Filename,"rt");
320 if (!fi) {
321 debuga(_("Cannot read user name alias file \"%s\" - %s\n"),Filename,strerror(errno));
322 exit(EXIT_FAILURE);
323 }
324
325 if ((line=longline_create())==NULL) {
326 debuga(_("Not enough memory to read the user name aliases\n"));
327 exit(EXIT_FAILURE);
328 }
329
330 while ((buf=longline_read(fi,line)) != NULL) {
331 if (Alias_Store(UserAliases,buf)<0) {
332 debuga(_("While reading \"%s\"\n"),Filename);
333 exit(EXIT_FAILURE);
334 }
335 }
336
337 longline_destroy(&line);
338 fclose(fi);
339
340 if (debug) {
341 debuga(_("List of user names to alias:\n"));
342 Alias_PrintList(UserAliases);
343 }
344}
345
346/*!
347Free the memory allocated by read_useralias().
348*/
349void free_useralias(void)
350{
351 Alias_Destroy(&UserAliases);
352}
353
354/*!
355Replace the user's name or ID by an alias if one is defined.
356
357\param user The user's name or ID as extracted from the report.
358*/
359const char *process_user(const char *user)
360{
361 user=Alias_Replace(UserAliases,user);
362 return(user);
363}