]> git.ipfire.org Git - thirdparty/sarg.git/blob - realtime.c
Add support to decompress xz files
[thirdparty/sarg.git] / realtime.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2015
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"
29 #include "include/filelist.h"
30 #include "include/readlog.h"
31
32 //! Maximum length of the scheme plus host name from the url.
33 #define MAX_URL_HOST_LEN 260
34
35 /*!
36 \brief Data read from an input log file.
37 */
38 struct RealtimeReadLogStruct
39 {
40 //! The time corresponding to the entry.
41 struct tm EntryTime;
42 //! The IP address connecting to internet.
43 char Ip[48];
44 //! The user's name.
45 char User[MAX_USER_LEN];
46 /*!
47 The URL of the visited site.
48
49 The pointer may be NULL if the URL doesn't exists in the log file.
50 */
51 char Url[MAX_URL_HOST_LEN];
52 //! HTTP method or NULL if the information is not stored in the log.
53 char HttpMethod[32];
54 };
55
56 extern FileListObject AccessLog;
57
58 static bool GetLatestModified(char *file_name,int file_name_size)
59 {
60 FileListIterator FIter;
61 const char *file;
62 bool found=false;
63 struct stat st;
64 time_t latest;
65
66 FIter=FileListIter_Open(AccessLog);
67 while ((file=FileListIter_Next(FIter))!=NULL)
68 {
69 if (stat(file,&st)==-1) {
70 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),file,strerror(errno));
71 }
72 if (!found)
73 {
74 found=true;
75 latest=st.st_mtime;
76 safe_strcpy(file_name,file,file_name_size);
77 }
78 else if (st.st_mtime>latest)
79 {
80 latest=st.st_mtime;
81 safe_strcpy(file_name,file,file_name_size);
82 }
83 }
84 FileListIter_Close(FIter);
85 return(found);
86 }
87
88 /*!
89 * \brief Store a log entry.
90 *
91 * \param Dest A pointer to the list entry where to store the entry.
92 * \param Entry The entry to store.
93 */
94 static void StoreLogEntry(struct RealtimeReadLogStruct *Dest,struct ReadLogStruct *Entry)
95 {
96 memcpy(&Dest->EntryTime,&Entry->EntryTime,sizeof(Dest->EntryTime));
97 safe_strcpy(Dest->Ip,Entry->Ip,sizeof(Dest->Ip));
98 if (Entry->Url)
99 {
100 int i;
101 const char *url=Entry->Url;
102
103 // skip the scheme
104 for (i=0 ; i<8 && url[i] && (isalnum(url[i]) || url[i]=='+' || url[i]=='-' || url[i]=='.') ; i++);
105 if (url[i]==':' && url[i+1]=='/' && url[i+2]=='/')
106 {
107 url+=i+3;
108 for (i=0 ; url[i] && url[i]!='/' ; i++);
109 }
110 if (i>=sizeof(Dest->Url)) i=sizeof(Dest->Url)-1;
111 strncpy(Dest->Url,url,i);
112 Dest->Url[i]='\0';
113 }
114 safe_strcpy(Dest->User,Entry->User,sizeof(Dest->User));
115 safe_strcpy(Dest->HttpMethod,Entry->HttpMethod,sizeof(Dest->HttpMethod));
116 }
117
118 static void header(void)
119 {
120 puts("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"");
121 puts(" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
122 puts("<html>\n");
123 puts("<head>\n");
124 if(realtime_refresh)
125 printf(" <meta http-equiv=refresh content=\"%d\" url=\"sarg-php/sarg-realtime.php\"; charset=\"%s\">\n",realtime_refresh,CharSet);
126 else
127 printf(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
128 css(stdout);
129 puts("</head>\n");
130 printf("<body style=\"font-family:%s;font-size:%s;background-color:%s;background-image:url(%s)\">\n",FontFace,TitleFontSize,BgColor,BgImage);
131 puts("<div align=\"center\"><table cellpadding=\"1\" cellspacing=\"1\">\n");
132 printf("<tr><th class=\"title_l\" colspan=\"10\">SARG %s</th></tr>\n",_("Realtime"));
133 printf("<tr><th class=\"text\" colspan=\"10\">%s: %d s</th></tr>\n",_("Auto refresh"),realtime_refresh);
134 printf("<tr><th class=\"header_c\">%s</th><th class=\"header_c\">%s</th><th class=\"header_c\">%s</th><th class=\"header_c\">%s</th><th class=\"header_l\">%s</th></tr>\n",_("DATE/TIME"),_("IP/NAME"),_("USERID"),_("TYPE"),_("ACCESSED SITE"));
135 }
136
137 static void datashow(struct RealtimeReadLogStruct *List,int Index,int Size)
138 {
139 char tbuf[128];
140 char user[MAX_USER_LEN];
141 char name[MAX_USER_LEN];
142 int i;
143 struct RealtimeReadLogStruct *entry;
144
145 header();
146 for (i=0 ; i<realtime_access_log_lines ; i++)
147 {
148 entry=List+Index;
149 Index--;
150 if (Index<0) Index=Size-1;
151
152 if (UserIp)
153 strcpy(user,entry->Ip);
154 else
155 strcpy(user,entry->User);
156 if(Ip2Name)
157 ip2name(user,sizeof(user));
158 user_find(name, sizeof(name), user);
159
160 if (df=='u')
161 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M", &entry->EntryTime);
162 else if (df=='e')
163 strftime(tbuf, sizeof(tbuf), "%d-%m-%Y %H:%M", &entry->EntryTime);
164
165 printf("<tr><td class=\"data\">%s</td><td class=\"data3\">%s</td><td class=\"data3\">%s</td><td class=\"data3\">%s</td><td class=\"data2\"><a href=\"http://%s\">%s</td></tr>\n",
166 tbuf,entry->Ip,name,entry->HttpMethod,entry->Url,entry->Url);
167 }
168
169 puts("</table>\n</div>\n</body>\n</html>\n");
170 fflush(NULL);
171 }
172
173 void realtime(void)
174 {
175 FileObject *fp;
176 char file_name[2048];
177 char *buf;
178 longline line;
179 struct ReadLogStruct log_entry;
180 enum ReadLogReturnCodeEnum log_entry_status;
181 struct LogLineStruct log_line;
182 struct RealtimeReadLogStruct *StoredLogEntries;
183 int StoreIndex=0;
184 int StoreSize=0;
185 int NextIndex=1;
186
187 init_usertab(UserTabFile);
188 LogLine_Init(&log_line);
189
190 /*
191 * Store one more entry to prepare the memory structure in place and reject it if
192 * it is about the same user and url as the last stored one.
193 */
194 StoredLogEntries=calloc(realtime_access_log_lines+1,sizeof(struct RealtimeReadLogStruct));
195 if (!StoredLogEntries)
196 {
197 debuga(__FILE__,__LINE__,_("Not enough memory to store %d records"),realtime_access_log_lines);
198 exit(EXIT_FAILURE);
199 }
200 /*
201 * Clear the url and user strings so that strcmp on the user and url are not
202 * satisfied and the first entry can be stored.
203 */
204 memset(StoredLogEntries,0,sizeof(struct RealtimeReadLogStruct));
205
206 if (!GetLatestModified(file_name,sizeof(file_name)))
207 {
208 debuga(__FILE__,__LINE__,_("No log file to read the last %d lines from\n"),realtime_access_log_lines);
209 exit(EXIT_FAILURE);
210 }
211 fp = FileObject_Open(file_name);
212 if (!fp) {
213 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),file_name,FileObject_GetLastOpenError());
214 exit(EXIT_FAILURE);
215 }
216
217 if ((line=longline_create())==NULL) {
218 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),file_name);
219 exit(EXIT_FAILURE);
220 }
221
222 while((buf=longline_read(fp,line)) != NULL )
223 {
224 log_entry_status=LogLine_Parse(&log_line,&log_entry,buf);
225 if (log_entry_status==RLRC_Unknown)
226 {
227 continue;
228 }
229 if (log_entry_status==RLRC_Ignore)
230 {
231 continue;
232 }
233 if (log_entry.HttpMethod && strstr(RealtimeTypes,log_entry.HttpMethod)==0)
234 continue;
235 if (RealtimeUnauthRec==REALTIME_UNAUTH_REC_IGNORE && log_entry.User[0]=='-' && log_entry.User[1]=='\0')
236 continue;
237 StoreLogEntry(StoredLogEntries+NextIndex,&log_entry);
238 if (strcmp(StoredLogEntries[StoreIndex].User,StoredLogEntries[NextIndex].User)==0 && strcmp(StoredLogEntries[StoreIndex].Url,StoredLogEntries[NextIndex].Url)==0)
239 continue;
240
241 StoreIndex=NextIndex;
242 NextIndex++;
243 if (NextIndex>StoreSize) StoreSize=NextIndex;
244 if (NextIndex>realtime_access_log_lines) NextIndex=0;
245 }
246 if (FileObject_Close(fp)) {
247 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),file_name,FileObject_GetLastCloseError());
248 exit(EXIT_FAILURE);
249 }
250 longline_destroy(&line);
251
252 datashow(StoredLogEntries,StoreIndex,StoreSize);
253 free(StoredLogEntries);
254 }