]>
Commit | Line | Data |
---|---|---|
d5c1b1c1 | 1 | /* |
d5c1b1c1 | 2 | * SARG Squid Analysis Report Generator http://sarg.sourceforge.net |
110ce984 | 3 | * 1998, 2015 |
d5c1b1c1 GS |
4 | * |
5 | * SARG donations: | |
6 | * please look at http://sarg.sourceforge.net/donations.php | |
1164c474 FM |
7 | * Support: |
8 | * http://sourceforge.net/projects/sarg/forums/forum/363374 | |
d5c1b1c1 GS |
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" | |
5f3cfd1d | 28 | #include "include/defs.h" |
6068ae56 | 29 | #include "include/filelist.h" |
8b4e9578 | 30 | #include "include/readlog.h" |
6068ae56 | 31 | |
8b4e9578 FM |
32 | //! Maximum length of the scheme plus host name from the url. |
33 | #define MAX_URL_HOST_LEN 260 | |
d5c1b1c1 | 34 | |
8b4e9578 FM |
35 | /*! |
36 | \brief Data read from an input log file. | |
37 | */ | |
38 | struct RealtimeReadLogStruct | |
d5c1b1c1 | 39 | { |
8b4e9578 FM |
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; | |
d5c1b1c1 | 57 | |
8b4e9578 | 58 | static bool GetLatestModified(char *file_name,int file_name_size) |
d5c1b1c1 | 59 | { |
6068ae56 | 60 | FileListIterator FIter; |
8b4e9578 FM |
61 | const char *file; |
62 | bool found=false; | |
63 | struct stat st; | |
64 | time_t latest; | |
ac422f9b | 65 | |
6068ae56 | 66 | FIter=FileListIter_Open(AccessLog); |
8b4e9578 FM |
67 | while ((file=FileListIter_Next(FIter))!=NULL) |
68 | { | |
69 | if (stat(file,&st)==-1) { | |
af961877 | 70 | debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),file,strerror(errno)); |
8b4e9578 FM |
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 | } | |
9bd92830 | 83 | } |
6068ae56 | 84 | FileListIter_Close(FIter); |
8b4e9578 FM |
85 | return(found); |
86 | } | |
d5c1b1c1 | 87 | |
8b4e9578 FM |
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'; | |
08f9b029 | 113 | } |
8b4e9578 FM |
114 | safe_strcpy(Dest->User,Entry->User,sizeof(Dest->User)); |
115 | safe_strcpy(Dest->HttpMethod,Entry->HttpMethod,sizeof(Dest->HttpMethod)); | |
d5c1b1c1 GS |
116 | } |
117 | ||
8b4e9578 | 118 | static void header(void) |
d5c1b1c1 | 119 | { |
8b4e9578 FM |
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]; | |
9bd92830 | 140 | char user[MAX_USER_LEN]; |
8b4e9578 FM |
141 | char name[MAX_USER_LEN]; |
142 | int i; | |
143 | struct RealtimeReadLogStruct *entry; | |
d5c1b1c1 | 144 | |
8b4e9578 FM |
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); | |
d5c1b1c1 | 159 | |
8b4e9578 FM |
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); | |
d5c1b1c1 | 164 | |
8b4e9578 FM |
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); | |
d5c1b1c1 GS |
171 | } |
172 | ||
8b4e9578 | 173 | void realtime(void) |
d5c1b1c1 | 174 | { |
800eafb8 | 175 | FileObject *fp; |
8b4e9578 | 176 | char file_name[2048]; |
9bd92830 | 177 | char *buf; |
9bd92830 | 178 | longline line; |
8b4e9578 FM |
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; | |
d5c1b1c1 | 186 | |
8b4e9578 FM |
187 | init_usertab(UserTabFile); |
188 | LogLine_Init(&log_line); | |
e5b2c6f0 | 189 | |
8b4e9578 FM |
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 | { | |
af961877 | 197 | debuga(__FILE__,__LINE__,_("Not enough memory to store %d records"),realtime_access_log_lines); |
8b4e9578 FM |
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 | { | |
af961877 | 208 | debuga(__FILE__,__LINE__,_("No log file to read the last %d lines from\n"),realtime_access_log_lines); |
8b4e9578 FM |
209 | exit(EXIT_FAILURE); |
210 | } | |
800eafb8 | 211 | fp = FileObject_Open(file_name); |
8b4e9578 | 212 | if (!fp) { |
800eafb8 | 213 | debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),file_name,FileObject_GetLastOpenError()); |
8b4e9578 FM |
214 | exit(EXIT_FAILURE); |
215 | } | |
720f3529 FM |
216 | |
217 | if ((line=longline_create())==NULL) { | |
af961877 | 218 | debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),file_name); |
720f3529 FM |
219 | exit(EXIT_FAILURE); |
220 | } | |
221 | ||
8b4e9578 FM |
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; | |
9bd92830 | 228 | } |
8b4e9578 FM |
229 | if (log_entry_status==RLRC_Ignore) |
230 | { | |
231 | continue; | |
9bd92830 | 232 | } |
8b4e9578 | 233 | if (log_entry.HttpMethod && strstr(RealtimeTypes,log_entry.HttpMethod)==0) |
9bd92830 | 234 | continue; |
8b4e9578 FM |
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) | |
9bd92830 | 239 | continue; |
d6e703cc | 240 | |
8b4e9578 FM |
241 | StoreIndex=NextIndex; |
242 | NextIndex++; | |
243 | if (NextIndex>StoreSize) StoreSize=NextIndex; | |
244 | if (NextIndex>realtime_access_log_lines) NextIndex=0; | |
9bd92830 | 245 | } |
800eafb8 FM |
246 | if (FileObject_Close(fp)) { |
247 | debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),file_name,FileObject_GetLastCloseError()); | |
204781f4 FM |
248 | exit(EXIT_FAILURE); |
249 | } | |
9bd92830 | 250 | longline_destroy(&line); |
d5c1b1c1 | 251 | |
8b4e9578 FM |
252 | datashow(StoredLogEntries,StoreIndex,StoreSize); |
253 | free(StoredLogEntries); | |
d5c1b1c1 | 254 | } |