]> git.ipfire.org Git - thirdparty/sarg.git/blob - grepday.c
107b958f7ad655ec4fec1b28b3045900cb63f831
[thirdparty/sarg.git] / grepday.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2010
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
30 #if defined(HAVE_GD)
31
32 #if defined(HAVE_ICONV_H) && defined(gdFTEX_Unicode)
33 #include <iconv.h>
34 #define USE_ICONV 1
35 #endif
36
37 struct GraphDataStruct
38 {
39 int lavender;
40 int darkblue;
41 int dimgray;
42 int goldenrod;
43 int goldenrod2;
44 int gray;
45 int silver;
46 int black;
47 //! The color of the top side of a graph bar.
48 int color1;
49 //! The color of the right side of a graph bar.
50 int color2;
51 //! The color of the front side of a graph bar.
52 int color3;
53 //! The libgd image we are drawing on.
54 gdImage *im;
55 //! An allocated buffer to convert the string into UTF-8.
56 char *string;
57 //! The number of bytes allocated for the string buffer.
58 size_t string_size;
59 //! The bottom border of the graph.
60 int BottomGraph;
61 //! The top border of the graph.
62 int TopGraph;
63 //! The left border of the graph.
64 int LeftGraph;
65 //! The right border of the graph.
66 int RightGraph;
67 //! The height at which the bottom depth border of the graph extends.
68 int BottomDepth;
69 //! The distance between two ticks on the horizontal axis.
70 double XScale;
71 //! The distance between two ticks on the vertical axis.
72 double YScale;
73 //! The exterior length of a tick on the scales.
74 int TickLength;
75 //! The distance, in pixels, between two ticks along the Y axis.
76 int YTickSpace;
77 };
78
79 enum PlotType
80 {
81 PTG_LinBin,
82 PTG_LogBin,
83 PTG_Time,
84 };
85
86 struct PlotStruct
87 {
88 //! The data points to plot.
89 long long int *datapoints;
90 //! The number of points to plot.
91 int npoints;
92 //! The minimum data to plot along the Y axis.
93 long long int ymin;
94 //! The maximum data to plot along the Y axis.
95 long long int ymax;
96 //! The type of Y axis to draw.
97 enum PlotType ytype;
98 //! The label to write on the X axis.
99 const char *XLabel;
100 //! The label to write on the Y axis.
101 const char *YLabel;
102 };
103
104 enum TextRefPos
105 {
106 TRP_TopLeft,
107 TRP_TopCenter,
108 TRP_TopRight,
109 TRP_BottomLeft,
110 TRP_BottomCenter,
111 TRP_BottomRight,
112 TRP_CenterLeft,
113 TRP_Center,
114 TRP_CenterRight,
115 };
116
117 #ifdef USE_ICONV
118 //! The iconv object to convert the text from the locale character set to UTF-8.
119 iconv_t localtoutf=(iconv_t)-1;
120 #endif
121
122 static void Sarg_gdImageStringFT (struct GraphDataStruct *gdata, int fg, char *fontlist,
123 double ptsize, double angle, int x, int y, const char *string,enum TextRefPos RefPos)
124 {
125 char *sstring;
126 char *retval;
127 int brect[8];
128 int minx,miny,maxx,maxy;
129 int i;
130
131 #ifdef USE_ICONV
132 if (localtoutf!=(iconv_t)-1) {
133 const char *str;
134 char *sstr;
135 size_t slen, sslen;
136
137 slen = strlen(string) + 1; // We must include string termination character
138 sslen = slen * 3; // We assume that the UTF8 string will not be bigger than 3 times the original size.
139 if (sslen>gdata->string_size) {
140 sstring = (char *)realloc(gdata->string,sslen);
141 if (!sstring) {
142 debuga(_("realloc error (%zu bytes required)\n"),sslen);
143 exit(EXIT_FAILURE);
144 }
145 gdata->string=(char *)sstring;
146 gdata->string_size=sslen;
147 } else {
148 sstring=gdata->string;
149 sslen=gdata->string_size;
150 }
151
152 str = string;
153 sstr = sstring;
154 if (iconv (localtoutf, (ICONV_CONST char **)&str, &slen, &sstr, &sslen)==-1) {
155 debuga(_("(grepday) iconv failed to convert string \"%s\" from %s to UTF-8 - %s\n"),string,CharSet,strerror(errno));
156 sstring=(char *)string; //show something sensible on the graph
157 }
158 } else {
159 sstring=(char *)string; //show something sensible on the graph
160 }
161 #else
162 sstring=(char *)string;
163 #endif
164
165 if (RefPos!=TRP_BottomLeft) {
166 retval = gdImageStringFTEx (NULL, brect, fg, fontlist, ptsize, angle, 0, 0, sstring, gdFTEX_Unicode);
167 if (retval) {
168 debuga(_("libgd failed to calculate the bounding box of the text \"%s\": %s\n"),sstring,retval);
169 exit(EXIT_FAILURE);
170 }
171 /*
172 From libgd documentation, brect contains this without taking into account the angle:
173 0 lower left corner, X position
174 1 lower left corner, Y position
175 2 lower right corner, X position
176 3 lower right corner, Y position
177 4 upper right corner, X position
178 5 upper right corner, Y position
179 6 upper left corner, X position
180 7 upper left corner, Y position
181 */
182 minx=maxx=brect[0];
183 miny=maxy=brect[1];
184 for (i=2 ; i<7 ; i+=2) {
185 if (minx>brect[i]) minx=brect[i];
186 if (maxx<brect[i]) maxx=brect[i];
187 if (miny>brect[i+1]) miny=brect[i+1];
188 if (maxy<brect[i+1]) maxy=brect[i+1];
189 }
190 }
191
192 switch (RefPos)
193 {
194 case TRP_TopLeft:
195 y-=miny;
196 break;
197
198 case TRP_TopCenter:
199 x-=(maxx-minx)/2;
200 y-=miny;
201 break;
202
203 case TRP_TopRight:
204 x-=maxx;
205 y-=miny;
206 break;
207
208 case TRP_BottomLeft:
209 break;
210
211 case TRP_BottomCenter:
212 x-=(maxx-minx)/2;
213 break;
214
215 case TRP_BottomRight:
216 x-=maxx;
217 break;
218
219 case TRP_Center:
220 x-=(maxx-minx)/2;
221 y+=(maxy-miny)/2;
222 break;
223
224 case TRP_CenterLeft:
225 y+=(maxy-miny)/2;
226 break;
227
228 case TRP_CenterRight:
229 x-=maxx;
230 y+=(maxy-miny)/2;
231 break;
232 }
233 retval = gdImageStringFTEx (gdata->im, brect, fg, fontlist, ptsize, angle, x, y, sstring, gdFTEX_Unicode);
234 if (retval) {
235 debuga(_("libgd failed to render the text \"%s\": %s\n"),sstring,retval);
236 exit(EXIT_FAILURE);
237 }
238 }
239
240 static void bar(struct GraphDataStruct *gdata,int x1,double y,const char *label)
241 {
242 gdPoint points[4];
243 int val=0;
244 int width2;
245
246 val=gdata->BottomGraph+5-(int)(y*gdata->YScale+0.5);
247 width2=(int)(gdata->XScale/4.);
248
249 // front side of the bar
250 if (val<gdata->BottomDepth)
251 gdImageFilledRectangle(gdata->im, x1-width2, val, x1+width2, gdata->BottomDepth, gdata->color3);
252
253 // top side of the bar
254 points[0].x = x1-width2+5;
255 points[0].y = val-5;
256 points[1].x = x1-width2;
257 points[1].y = val;
258 points[2].x = x1+width2;
259 points[2].y = val;
260 points[3].x = x1+width2+5;
261 points[3].y = val-5;
262 gdImageFilledPolygon(gdata->im, points, 4, gdata->color1);
263
264 gdImageLine(gdata->im, x1+2, val-2, x1+2, val-10, gdata->dimgray);
265 gdImageFilledRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod);
266 gdImageRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod2);
267
268 Sarg_gdImageStringFT(gdata,gdata->black,GraphFont,6,0.0,x1+2,val-12,label,TRP_BottomCenter);
269
270 // lateral side of the bar
271 if (val<gdata->BottomDepth) {
272 points[0].x = x1+width2+5;
273 points[0].y = val-5;
274 points[1].x = x1+width2;
275 points[1].y = val;
276 points[2].x = x1+width2;
277 points[2].y = gdata->BottomDepth;
278 points[3].x = x1+width2+5;
279 points[3].y = gdata->BottomGraph;
280 gdImageFilledPolygon(gdata->im, points, 4, gdata->color2);
281 }
282
283 return;
284 }
285
286 static int greport_compute_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
287 {
288 double symin,symax;
289 double range;
290 double yscale;
291 double ymag;
292
293 if (pdata->ymin<0.) {
294 debuga(_("Minimum for Y scale of the graph is out of range: %lld\n"),pdata->ymin);
295 return(-1);
296 }
297 if (pdata->ymax<=0.) {
298 debuga(_("Maximum for Y scale of the graph is out of range: %lld\n"),pdata->ymax);
299 return(-1);
300 }
301
302 switch(pdata->ytype)
303 {
304 case PTG_LinBin:
305 symin=(double)pdata->ymin;
306 symax=(double)pdata->ymax;
307 ymag=1024.;
308 break;
309
310 case PTG_LogBin:
311 if (pdata->ymin>0.)
312 symin=log(pdata->ymin);
313 else
314 symin=0.;
315 symax=log(pdata->ymax);
316 ymag=1024.;
317 break;
318
319 case PTG_Time:
320 symin=(double)pdata->ymin;
321 symax=(double)pdata->ymax;
322 ymag=1.;
323 break;
324
325 default:
326 debuga(_("Unknown type %d for Y axis scale\n"),pdata->ytype);
327 return(-1);
328 }
329 gdata->YTickSpace=10;
330
331 range=symax-symin;
332 yscale=(double)(gdata->BottomGraph-gdata->TopGraph)/range;
333 gdata->YScale=yscale;
334 return(0);
335 }
336
337 static void greport_formatbin(double yval,int maxdigits,char *string,int slen)
338 {
339 int len;
340 char schar[]={'\0','k','M','G','T','P'};
341 int scount;
342 int i;
343 int ndigits;
344
345 for (scount=0 ; scount<sizeof(schar)/sizeof(*schar) && yval>=1024. ; scount++)
346 yval/=1024.;
347 if (yval<2.)
348 ndigits=2;
349 else if (yval<3.)
350 ndigits=1;
351 else
352 ndigits=0;
353 if (ndigits>maxdigits) ndigits=maxdigits;
354 len=snprintf(string,slen,"%.*lf",ndigits,yval);
355 if (UseComma)
356 for (i=0 ; i<len ; i++)
357 if (string[i]=='.') string[i]=',';
358 if (schar[scount] && len<slen) {
359 string[len++]=schar[scount];
360 string[len]='\0';
361 }
362 }
363
364 static void greport_draw_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
365 {
366 double yval;
367 int y0;
368 int y;
369 int yt;
370 char YLabel[50];
371 int xexterior;
372 int xinterior;
373 int xtick;
374
375 y0=gdata->BottomGraph;
376 yt=gdata->BottomDepth-gdata->BottomGraph;
377 xexterior=gdata->LeftGraph-10;
378 xinterior=gdata->LeftGraph;
379 xtick=gdata->LeftGraph-10-gdata->TickLength;
380 for(y=y0-gdata->YTickSpace ; y>=gdata->TopGraph ; y-=gdata->YTickSpace) {
381 gdImageLine(gdata->im, xtick, y+yt, xexterior, y+yt, gdata->dimgray);
382 gdImageLine(gdata->im, xexterior, y+yt, xinterior, y, gdata->dimgray);
383 gdImageLine(gdata->im, xinterior, y, gdata->RightGraph, y, gdata->dimgray);
384 switch (pdata->ytype)
385 {
386 case PTG_LinBin:
387 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
388 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
389 break;
390
391 case PTG_LogBin:
392 yval=exp((double)(y0-y)/gdata->YScale+log(pdata->ymin));
393 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
394 break;
395
396 case PTG_Time:
397 {
398 int t;
399
400 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
401 t=(int)(yval/60000.);
402 snprintf(YLabel,sizeof(YLabel),"%02d:%02d",t/60,t%60);
403 break;
404 }
405 }
406 Sarg_gdImageStringFT(gdata,gdata->dimgray,GraphFont,7,0.0,xtick,y+yt,YLabel,TRP_CenterRight);
407 }
408 }
409
410 static void greport_plot(const struct userinfostruct *uinfo,struct PlotStruct *pdata)
411 {
412 FILE *pngout;
413 int x, y;
414 int day;
415 int x1;
416 char graph[MAXLEN];
417 char s[15];
418 char ftime[128];
419 time_t t;
420 struct tm *local;
421 gdPoint points[4];
422 struct GraphDataStruct gdata;
423 const int ImgXSize=720;
424 const int ImgYSize=480;
425 const int LeftMargin=60;
426 const int RightMargin=20;
427 const int TopMargin=60;
428 const int BottomMargin=60;
429 const int TickLength=3;
430 const int ZTickLength=5;
431 double yval;
432 char blabel[50];
433 double logpmin;
434
435 memset(&gdata,0,sizeof(gdata));
436
437 gdata.im = gdImageCreate(ImgXSize, ImgYSize);
438 gdata.BottomGraph=ImgYSize-BottomMargin;
439 gdata.LeftGraph=LeftMargin;
440 gdata.RightGraph=ImgXSize-RightMargin;
441 gdata.TopGraph=TopMargin;
442 gdata.BottomDepth=gdata.BottomGraph+5;
443 gdata.XScale=(double)(gdata.RightGraph-gdata.LeftGraph)/(pdata->npoints+1);
444 if (greport_compute_yaxis(pdata,&gdata)<0) return;
445 gdata.TickLength=TickLength;
446
447 // first allocated color is the background
448 gdata.lavender = gdImageColorAllocate(gdata.im, 230, 230, 250);
449 gdata.gray = gdImageColorAllocate(gdata.im, 192, 192, 192);
450 gdata.silver = gdImageColorAllocate(gdata.im, 211, 211, 211);
451 gdata.black = gdImageColorAllocate(gdata.im, 0, 0, 0);
452 gdata.dimgray = gdImageColorAllocate(gdata.im, 105, 105, 105);
453 gdata.darkblue = gdImageColorAllocate(gdata.im, 0, 0, 139);
454 gdata.goldenrod = gdImageColorAllocate(gdata.im, 234, 234, 174);
455 gdata.goldenrod2 = gdImageColorAllocate(gdata.im, 207, 181, 59);
456
457 if(strcmp(GraphDaysBytesBarColor,"orange") == 0) {
458 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
459 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
460 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
461 }
462 else if(strcmp(GraphDaysBytesBarColor,"blue") == 0) {
463 gdata.color1 = gdImageColorAllocate(gdata.im, 62, 80, 167);
464 gdata.color2 = gdImageColorAllocate(gdata.im, 40, 51, 101);
465 gdata.color3 = gdImageColorAllocate(gdata.im, 57, 73, 150);
466 }
467 else if(strcmp(GraphDaysBytesBarColor,"green") == 0) {
468 gdata.color1 = gdImageColorAllocate(gdata.im,120,166,129);
469 gdata.color2 = gdImageColorAllocate(gdata.im,84,113,82);
470 gdata.color3 = gdImageColorAllocate(gdata.im,158,223,167);
471 }
472 else if(strcmp(GraphDaysBytesBarColor,"yellow") == 0) {
473 gdata.color1 = gdImageColorAllocate(gdata.im,185,185,10);
474 gdata.color2 = gdImageColorAllocate(gdata.im,111,111,10);
475 gdata.color3 = gdImageColorAllocate(gdata.im,166,166,10);
476 }
477 else if(strcmp(GraphDaysBytesBarColor,"brown") == 0) {
478 gdata.color1 = gdImageColorAllocate(gdata.im,97,45,27);
479 gdata.color2 = gdImageColorAllocate(gdata.im,60,30,20);
480 gdata.color3 = gdImageColorAllocate(gdata.im,88,41,26);
481 }
482 else if(strcmp(GraphDaysBytesBarColor,"red") == 0){
483 gdata.color1 = gdImageColorAllocate(gdata.im,185,10,10);
484 gdata.color2 = gdImageColorAllocate(gdata.im,111,10,10);
485 gdata.color3 = gdImageColorAllocate(gdata.im,166,10,10);
486 } else {
487 debuga(_("Unknown color \"%s\" requested for the graph. Using orange instead\n"),GraphDaysBytesBarColor);
488 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
489 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
490 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
491 }
492
493 // rectangle around the image
494 gdImageRectangle(gdata.im, 0, 0, ImgXSize-1, ImgYSize-1, gdata.dimgray);
495 // backtround of the graph
496 gdImageFilledRectangle(gdata.im, LeftMargin, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.silver);
497
498 // depth of the left Y axis
499 points[0].x = gdata.LeftGraph-10;
500 points[0].y = gdata.TopGraph+5;
501 points[1].x = gdata.LeftGraph-10;
502 points[1].y = gdata.BottomDepth;
503 points[2].x = gdata.LeftGraph;
504 points[2].y = gdata.BottomGraph;
505 points[3].x = gdata.LeftGraph;
506 points[3].y = gdata.TopGraph;
507 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
508
509 // depth of the bottom X axis
510 points[0].x = gdata.LeftGraph;
511 points[0].y = gdata.BottomGraph;
512 points[1].x = gdata.LeftGraph-10;
513 points[1].y = gdata.BottomDepth;
514 points[2].x = gdata.RightGraph-10;
515 points[2].y = gdata.BottomDepth;
516 points[3].x = gdata.RightGraph;
517 points[3].y = gdata.BottomGraph;
518 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
519
520 // vertical exterior line of the depth
521 gdImageLine(gdata.im, LeftMargin-10, TopMargin+5, LeftMargin-10, gdata.BottomDepth+ZTickLength, gdata.black);
522 // horizontal exterior line of the depth
523 gdImageLine(gdata.im, LeftMargin-10-ZTickLength, gdata.BottomDepth, gdata.RightGraph-10, gdata.BottomDepth, gdata.black);
524 // diagonal line between the two depths
525 gdImageLine(gdata.im, LeftMargin-10, gdata.BottomDepth, LeftMargin, gdata.BottomGraph, gdata.black);
526 // vertical left line of the graph
527 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, LeftMargin, gdata.TopGraph, gdata.black);
528 // horizontal bottom line of the graph
529 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
530 // vertical right line of the graph
531 gdImageLine(gdata.im, gdata.RightGraph, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
532 // diagonal line to close the right of the bottom depth
533 gdImageLine(gdata.im, gdata.RightGraph-10, gdata.BottomDepth, gdata.RightGraph, gdata.BottomGraph, gdata.black);
534
535 // Y axis ticks
536 greport_draw_yaxis(pdata,&gdata);
537
538 // X axis ticks and labels
539 for(y=1; y<=pdata->npoints; y++) {
540 x=gdata.LeftGraph-10+(int)((double)y*gdata.XScale+0.5);
541 gdImageLine(gdata.im, x, gdata.BottomDepth, x, gdata.BottomDepth+TickLength, gdata.dimgray);
542 sprintf(s,"%02d",y);
543 Sarg_gdImageStringFT(&gdata,gdata.dimgray,GraphFont,7,0.0,x,gdata.BottomDepth+TickLength+1,s,TRP_TopCenter);
544 }
545
546 t = time(NULL);
547 local = localtime(&t);
548 if(DateFormat[0]=='u')
549 strftime(ftime, sizeof(ftime), "%b/%d/%Y %H:%M", local);
550 if(DateFormat[0]=='e')
551 strftime(ftime, sizeof(ftime), "%d/%b/%Y-%H:%M", local);
552
553 x=ImgXSize*5/12;
554 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,7,0.0,ImgXSize-10,ImgYSize-10,ftime,TRP_BottomRight);
555 if(ShowSargInfo) Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,_("SARG, "),TRP_BottomRight);
556 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,Title,TRP_BottomLeft);
557 sprintf(warea,_("Period: %s"),period.text);
558 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,27,warea,TRP_BottomLeft);
559 sprintf(warea,_("User: %s"),uinfo->label);
560 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,38,warea,TRP_BottomLeft);
561
562 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,3.141592/2,15,ImgYSize/2,pdata->YLabel,TRP_CenterLeft);
563 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,0.0,ImgXSize/2,ImgYSize-20,pdata->XLabel,TRP_BottomCenter);
564
565 logpmin=(pdata->ytype==PTG_LogBin && pdata->ymin>0.) ? log(pdata->ymin) : 0.;
566 for (day=0 ; day<pdata->npoints ; day++) {
567 if (pdata->datapoints[day]>0) {
568 x1=gdata.LeftGraph-10+(int)((double)(day+1)*gdata.XScale+0.5);
569 switch (pdata->ytype)
570 {
571 case PTG_LinBin:
572 yval=(double)pdata->datapoints[day];
573 if (yval<pdata->ymin)
574 yval=0.;
575 else if (yval>pdata->ymax)
576 yval=pdata->ymax;
577 else
578 yval-=pdata->ymin;
579 greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
580 break;
581 case PTG_LogBin:
582 yval=(double)pdata->datapoints[day];
583 if (yval<=pdata->ymin)
584 yval=0.;
585 else if (yval>pdata->ymax)
586 yval=log(pdata->ymax)-logpmin;
587 else
588 yval=log(yval)-logpmin;
589 greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
590 break;
591 case PTG_Time:
592 {
593 int t;
594
595 yval=(double)pdata->datapoints[day];
596 if (yval<pdata->ymin)
597 yval=0.;
598 else if (yval>pdata->ymax)
599 yval=pdata->ymax;
600 else
601 yval-=pdata->ymin;
602 t=(int)(pdata->datapoints[day]/60000.);
603 snprintf(blabel,sizeof(blabel),"%d:%02d",t/60,t%60);
604 break;
605 }
606 default:
607 yval=-1.;
608 break;
609 }
610 if (yval>=0.) bar(&gdata,x1,yval,blabel);
611 }
612 }
613
614 if (snprintf(graph,sizeof(graph),"%s/%s/graph_day.png",outdirname,uinfo->filename)>=sizeof(graph)) {
615 debuga(_("user name too long for %s/%s/graph_day.png\n"),outdirname,uinfo->filename);
616 exit(EXIT_FAILURE);
617 }
618 if((pngout=fopen(graph,"wb"))==NULL) {
619 debuga(_("(grepday) Cannot open log file %s\n"),graph);
620 exit(EXIT_FAILURE);
621 }
622 gdImagePng(gdata.im, pngout);
623 fclose(pngout);
624 gdImageDestroy(gdata.im);
625
626 if (gdata.string) free(gdata.string);
627 }
628
629 #endif //HAVE_GD
630
631 void greport_prepare(void)
632 {
633 #ifdef HAVE_GD
634 if(access(GraphFont, R_OK) != 0) {
635 debuga(_("(grepday) Fontname %s not found\n"),GraphFont);
636 exit(EXIT_FAILURE);
637 }
638
639 #ifdef USE_ICONV
640 localtoutf = iconv_open ("UTF-8", CharSet);
641 if (localtoutf==(iconv_t)-1) {
642 debuga(_("(grepday) iconv cannot convert from %s to UTF-8 - %s\n"),CharSet,strerror(errno));
643 }
644 #endif
645
646 #endif //HAVE_GD
647 }
648
649 void greport_day(const struct userinfostruct *uinfo)
650 {
651 #ifdef HAVE_GD
652 FILE *fp_in;
653 char wdirname[MAXLEN];
654 char buf[MAXLEN];
655 char colsep;
656 int day;
657 long long int llday;
658 long long int bytes;
659 long long int elap;
660 long long int bytespoints[31];
661 long long int elappoints[31];
662 struct getwordstruct gwarea;
663 struct PlotStruct pdata;
664
665 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.day",tmp,uinfo->filename)>=sizeof(wdirname)) {
666 debuga(_("user name too long for %s/%s.day\n"),tmp,uinfo->filename);
667 exit(EXIT_FAILURE);
668 }
669 if(access(wdirname, R_OK) != 0) {
670 return;
671 }
672 if(!Graphs || GraphFont[0]=='\0') {
673 unlink(wdirname);
674 return;
675 }
676
677 if((fp_in=fopen(wdirname,"r"))==NULL) {
678 debuga(_("(grepday) Cannot open log file %s\n"),wdirname);
679 exit(EXIT_FAILURE);
680 }
681
682 memset(bytespoints,0,sizeof(bytespoints));
683 memset(elappoints,0,sizeof(elappoints));
684 while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
685 fixendofline(buf);
686 getword_start(&gwarea,buf);
687 if (getword_atoll(&llday,&gwarea,'/')<0) {
688 debuga(_("Invalid date in file %s\n"),wdirname);
689 exit(EXIT_FAILURE);
690 }
691 day=(int)llday;
692 if (day<1 || day>31) continue;
693 if (getword_skip(20,&gwarea,'\t')<0 || getword_skip(20,&gwarea,'\t')<0) {
694 debuga(_("Invalid entry in file %s\n"),wdirname);
695 exit(EXIT_FAILURE);
696 }
697 if ((datetimeby & DATETIME_BYTE)!=0) {
698 colsep=((datetimeby & DATETIME_ELAP)!=0) ? '\t' : '\0';
699 if (getword_atoll(&bytes,&gwarea,'\t')<0) {
700 debuga(_("Invalid number of bytes in file %s\n"),wdirname);
701 exit(EXIT_FAILURE);
702 }
703 bytespoints[day-1]+=bytes;
704 }
705 if ((datetimeby & DATETIME_ELAP)!=0) {
706 if (getword_atoll(&elap,&gwarea,'\0')<0) {
707 debuga(_("Invalid elapsed time in file %s\n"),wdirname);
708 exit(EXIT_FAILURE);
709 }
710 elappoints[day-1]+=elap;
711 }
712 }
713 fclose(fp_in);
714 unlink(wdirname);
715
716 if((datetimeby & DATETIME_BYTE)!=0) {
717 memset(&pdata,0,sizeof(pdata));
718 pdata.datapoints=bytespoints;
719 pdata.npoints=31;
720 pdata.XLabel=_("DAYS");
721 pdata.ymin=50LL*1024LL;
722 pdata.ymax=5LL*1024LL*1024LL*1024LL;
723 pdata.ytype=PTG_LogBin;
724 pdata.YLabel=_("BYTES");
725 greport_plot(uinfo,&pdata);
726 } else {
727 memset(&pdata,0,sizeof(pdata));
728 pdata.datapoints=elappoints;
729 pdata.npoints=31;
730 pdata.XLabel=_("DAYS");
731 pdata.ymin=0;
732 pdata.ymax=86400000;
733 pdata.ytype=PTG_Time;
734 pdata.YLabel=_("ELAPSED TIME");
735 greport_plot(uinfo,&pdata);
736 }
737 #endif //HAVE_GD
738
739 return;
740 }
741
742 void greport_cleanup(void)
743 {
744 #ifdef HAVE_GD
745 gdFontCacheShutdown();
746
747 #ifdef USE_ICONV
748 if (localtoutf!=(iconv_t)-1)
749 iconv_close (localtoutf);
750 #endif
751 #endif //HAVE_GD
752 }