diff --git a/Makefile.am b/Makefile.am index a3f8879f..7dbb343b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,10 +6,10 @@ EXTRA_DIST = cfg examples UPGRADE CHANGES FAQ INSTALL_BSD INSTALL_OSX UNINSTALL bin_PROGRAMS = vnstat sbin_PROGRAMS = vnstatd -#if HAVE_LIBGD -#bin_PROGRAMS += vnstati -#endif -#vnstati_LDADD = $(IMAGELIBS) +if HAVE_LIBGD +bin_PROGRAMS += vnstati +endif +vnstati_LDADD = $(IMAGELIBS) vnstat_SOURCES = src/vnstat.c src/vnstat.h \ src/ifinfo.c src/ifinfo.h \ @@ -38,15 +38,14 @@ vnstatd_SOURCES = src/vnstatd.c src/vnstatd.h \ src/id.c src/id.h \ src/daemon.c src/daemon.h -#vnstati_SOURCES = src/vnstati.c src/vnstati.h \ -# src/image.c src/image.h \ -# src/dbsql.c src/dbsql.h \ -# src/dbaccess.c src/dbaccess.h \ -# src/common.c src/common.h \ -# src/misc.c src/misc.h \ -# src/fs.c src/fs.h \ -# src/id.c src/id.h \ -# src/cfg.c src/cfg.h +vnstati_SOURCES = src/vnstati.c src/vnstati.h \ + src/image.c src/image.h \ + src/dbsql.c src/dbsql.h \ + src/common.c src/common.h \ + src/misc.c src/misc.h \ + src/fs.c src/fs.h \ + src/id.c src/id.h \ + src/cfg.c src/cfg.h if HAVE_CHECK TESTS = check_vnstat diff --git a/Makefile.in b/Makefile.in index 10bef23e..ffe77f9f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -78,8 +78,9 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -bin_PROGRAMS = vnstat$(EXEEXT) +bin_PROGRAMS = vnstat$(EXEEXT) $(am__EXEEXT_1) sbin_PROGRAMS = vnstatd$(EXEEXT) +@HAVE_LIBGD_TRUE@am__append_1 = vnstati @HAVE_CHECK_TRUE@TESTS = check_vnstat$(EXEEXT) @HAVE_CHECK_TRUE@check_PROGRAMS = check_vnstat$(EXEEXT) subdir = . @@ -98,6 +99,7 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = +@HAVE_LIBGD_TRUE@am__EXEEXT_1 = vnstati$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) @@ -161,6 +163,12 @@ am_vnstatd_OBJECTS = src/vnstatd.$(OBJEXT) src/ifinfo.$(OBJEXT) \ src/fs.$(OBJEXT) src/id.$(OBJEXT) src/daemon.$(OBJEXT) vnstatd_OBJECTS = $(am_vnstatd_OBJECTS) vnstatd_LDADD = $(LDADD) +am_vnstati_OBJECTS = src/vnstati.$(OBJEXT) src/image.$(OBJEXT) \ + src/dbsql.$(OBJEXT) src/common.$(OBJEXT) src/misc.$(OBJEXT) \ + src/fs.$(OBJEXT) src/id.$(OBJEXT) src/cfg.$(OBJEXT) +vnstati_OBJECTS = $(am_vnstati_OBJECTS) +am__DEPENDENCIES_1 = +vnstati_DEPENDENCIES = $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -193,9 +201,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(check_vnstat_SOURCES) $(vnstat_SOURCES) $(vnstatd_SOURCES) +SOURCES = $(check_vnstat_SOURCES) $(vnstat_SOURCES) $(vnstatd_SOURCES) \ + $(vnstati_SOURCES) DIST_SOURCES = $(am__check_vnstat_SOURCES_DIST) $(vnstat_SOURCES) \ - $(vnstatd_SOURCES) + $(vnstatd_SOURCES) $(vnstati_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ @@ -592,10 +601,7 @@ top_srcdir = @top_srcdir@ SUBDIRS = . dist_man_MANS = man/vnstat.1 man/vnstat.conf.5 man/vnstatd.1 man/vnstati.1 EXTRA_DIST = cfg examples UPGRADE CHANGES FAQ INSTALL_BSD INSTALL_OSX UNINSTALL -#if HAVE_LIBGD -#bin_PROGRAMS += vnstati -#endif -#vnstati_LDADD = $(IMAGELIBS) +vnstati_LDADD = $(IMAGELIBS) vnstat_SOURCES = src/vnstat.c src/vnstat.h \ src/ifinfo.c src/ifinfo.h \ src/dbsql.c src/dbsql.h \ @@ -623,6 +629,15 @@ vnstatd_SOURCES = src/vnstatd.c src/vnstatd.h \ src/id.c src/id.h \ src/daemon.c src/daemon.h +vnstati_SOURCES = src/vnstati.c src/vnstati.h \ + src/image.c src/image.h \ + src/dbsql.c src/dbsql.h \ + src/common.c src/common.h \ + src/misc.c src/misc.h \ + src/fs.c src/fs.h \ + src/id.c src/id.h \ + src/cfg.c src/cfg.h + @HAVE_CHECK_TRUE@check_vnstat_CFLAGS = @CHECK_CFLAGS@ \ @HAVE_CHECK_TRUE@ -DPROCNETDEV=\"testdir/proc/dev\" \ @HAVE_CHECK_TRUE@ -DSYSCLASSNET=\"testdir/sysclassnet\" \ @@ -924,6 +939,13 @@ src/daemon.$(OBJEXT): src/$(am__dirstamp) \ vnstatd$(EXEEXT): $(vnstatd_OBJECTS) $(vnstatd_DEPENDENCIES) $(EXTRA_vnstatd_DEPENDENCIES) @rm -f vnstatd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(vnstatd_OBJECTS) $(vnstatd_LDADD) $(LIBS) +src/vnstati.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/image.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) + +vnstati$(EXEEXT): $(vnstati_OBJECTS) $(vnstati_DEPENDENCIES) $(EXTRA_vnstati_DEPENDENCIES) + @rm -f vnstati$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(vnstati_OBJECTS) $(vnstati_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -960,10 +982,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ibw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/ifinfo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/traffic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/vnstat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/vnstatd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/vnstati.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/check_vnstat-common_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/check_vnstat-config_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/check_vnstat-daemon_tests.Po@am__quote@ diff --git a/README.md b/README.md index 4cfcbb12..7b6e5ac2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ configurable durations. Yearly and 5 minute resolution statistics are now includ * alpha version with working daemon implementation * some sanity checks may be missing or disabled * vnstat (console output) has most features implemented - * vnstati (image output) is disabled + * vnstati (image output) lacks rewrite of most features * getting closer to replace vnStat 1.x ##### Done @@ -47,7 +47,7 @@ configurable durations. Yearly and 5 minute resolution statistics are now includ * continue daemon refactoring * add missing sanity checks to daemon * image outputs - * all + * all but daily * use of 5 minute resolution statistics * feature configurability * freeze database structure diff --git a/src/image.c b/src/image.c index 3cfddca0..389fb3b7 100644 --- a/src/image.c +++ b/src/image.c @@ -1,7 +1,8 @@ #include "common.h" -#include "vnstati.h" +#include "dbsql.h" #include "misc.h" #include "image.h" +#include "vnstati.h" void initimagecontent(IMAGECONTENT *ic) { @@ -18,7 +19,7 @@ void drawimage(IMAGECONTENT *ic) case 1: drawdaily(ic); break; - case 2: +/* case 2: drawmonthly(ic); break; case 3: @@ -47,8 +48,10 @@ void drawimage(IMAGECONTENT *ic) break; case 7: drawhourly(ic, cfg.hourlyrate); - break; + break; */ default: + printf("Error: Not such query mode: %d\n", cfg.qmode); + exit(EXIT_FAILURE); break; } @@ -128,7 +131,7 @@ void colorinit(IMAGECONTENT *ic) colorinitcheck("ctxd", ic->ctxd, cfg.ctxd, rgb); } -void colorinitcheck(char *color, int value, char *cfgtext, int *rgb) +void colorinitcheck(const char *color, const int value, const char *cfgtext, const int *rgb) { if (value==-1) { printf("Error: ImageColorAllocate failed.\n"); @@ -137,13 +140,13 @@ void colorinitcheck(char *color, int value, char *cfgtext, int *rgb) } } -void layoutinit(IMAGECONTENT *ic, char *title, int width, int height) +void layoutinit(IMAGECONTENT *ic, const char *title, const int width, const int height) { struct tm *d; char datestring[64]; /* get time in given format */ - d = localtime(&data.lastupdated); + d = localtime(&ic->interface.updated); strftime(datestring, 64, cfg.hformat, d); /* background, edges */ @@ -169,7 +172,7 @@ void layoutinit(IMAGECONTENT *ic, char *title, int width, int height) gdImageString(ic->im, gdFontGetTiny(), width-114-ic->showedge, height-12-ic->showedge, (unsigned char*)"vnStat / Teemu Toivola", ic->cvnstat); } -void drawlegend(IMAGECONTENT *ic, int x, int y) +void drawlegend(IMAGECONTENT *ic, const int x, const int y) { if (!ic->showlegend) { return; @@ -183,41 +186,38 @@ void drawlegend(IMAGECONTENT *ic, int x, int y) gdImageRectangle(ic->im, x+30, y+4, x+36, y+10, ic->ctext); } -void drawbar(IMAGECONTENT *ic, int x, int y, int len, uint64_t rx, int rxk, uint64_t tx, int txk, uint64_t max) +void drawbar(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max) { - int l; - - rx=mbkbtokb(rx, rxk); - tx=mbkbtokb(tx, txk); + int l, width = len; if ((rx+tx)!=max) { - len=((rx+tx)/(float)max)*len; + width=((rx+tx)/(float)max)*len; } - if (len!=0) { + if (width!=0) { if (tx>rx) { - l=rintf((rx/(float)(rx+tx)*len)); + l=rintf((rx/(float)(rx+tx)*width)); gdImageFilledRectangle(ic->im, x, y+YBEGINOFFSET, x+l, y+YENDOFFSET, ic->crx); gdImageRectangle(ic->im, x, y+YBEGINOFFSET, x+l, y+YENDOFFSET, ic->crxd); - gdImageFilledRectangle(ic->im, x+l, y+YBEGINOFFSET, x+len, y+YENDOFFSET, ic->ctx); - gdImageRectangle(ic->im, x+l, y+YBEGINOFFSET, x+len, y+YENDOFFSET, ic->ctxd); + gdImageFilledRectangle(ic->im, x+l, y+YBEGINOFFSET, x+width, y+YENDOFFSET, ic->ctx); + gdImageRectangle(ic->im, x+l, y+YBEGINOFFSET, x+width, y+YENDOFFSET, ic->ctxd); } else { - l=rintf((tx/(float)(rx+tx)*len)); + l=rintf((tx/(float)(rx+tx)*width)); - gdImageFilledRectangle(ic->im, x, y+YBEGINOFFSET, x+(len-l), y+YENDOFFSET, ic->crx); - gdImageRectangle(ic->im, x, y+YBEGINOFFSET, x+(len-l), y+YENDOFFSET, ic->crxd); + gdImageFilledRectangle(ic->im, x, y+YBEGINOFFSET, x+(width-l), y+YENDOFFSET, ic->crx); + gdImageRectangle(ic->im, x, y+YBEGINOFFSET, x+(width-l), y+YENDOFFSET, ic->crxd); - gdImageFilledRectangle(ic->im, x+(len-l), y+YBEGINOFFSET, x+len, y+YENDOFFSET, ic->ctx); - gdImageRectangle(ic->im, x+(len-l), y+YBEGINOFFSET, x+len, y+YENDOFFSET, ic->ctxd); + gdImageFilledRectangle(ic->im, x+(width-l), y+YBEGINOFFSET, x+width, y+YENDOFFSET, ic->ctx); + gdImageRectangle(ic->im, x+(width-l), y+YBEGINOFFSET, x+width, y+YENDOFFSET, ic->ctxd); } } } -void drawpole(IMAGECONTENT *ic, int x, int y, int len, uint64_t rx, uint64_t tx, uint64_t max) +void drawpole(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max) { int l; @@ -228,7 +228,7 @@ void drawpole(IMAGECONTENT *ic, int x, int y, int len, uint64_t rx, uint64_t tx, gdImageFilledRectangle(ic->im, x+5, y+(len-l), x+12, y+len, ic->ctx); } -void drawdonut(IMAGECONTENT *ic, int x, int y, float rxp, float txp) +void drawdonut(IMAGECONTENT *ic, const int x, const int y, const float rxp, const float txp) { int rxarc = 0, txarc = 0; @@ -265,691 +265,25 @@ void drawdonut(IMAGECONTENT *ic, int x, int y, float rxp, float txp) gdImageFilledArc(ic->im, x, y, DINRAD-2, DINRAD-2, 0, 360, ic->cbackground, 0); } -void drawhours(IMAGECONTENT *ic, int x, int y, int rate) -{ - int i, tmax=0, s=0, step, prev=0, diff=0, chour; - float ratediv; - uint64_t max=1, scaleunit=0; - char buffer[32]; - struct tm *d; - - ic->current = time(NULL); - chour = localtime(&ic->current)->tm_hour; - - if (cfg.rateunit) { - ratediv = 450; /* x * 8 / 3600 */ - } else { - ratediv = 3600; - } - - /* tmax (time max) = current hour */ - /* max = transfer max */ - - for (i = 0; i < 24; i++) { - - /* convert hourly transfer to hourly rate if needed */ - if (rate) { - if ((ic->current-data.hour[i].date) > 3600) { - data.hour[i].rx = data.hour[i].rx / ratediv; - data.hour[i].tx = data.hour[i].tx / ratediv; - } else { - /* scale ongoing hour properly */ - d = localtime(&data.hour[i].date); - if (chour != d->tm_hour) { - data.hour[i].rx = data.hour[i].rx / ratediv; - data.hour[i].tx = data.hour[i].tx / ratediv; - } else { - diff = d->tm_min*60; - if (!diff) { - diff = 1; - } - if (cfg.rateunit==1) { - data.hour[i].rx = data.hour[i].rx * 8 / (float)diff; - data.hour[i].tx = data.hour[i].tx * 8 / (float)diff; - } else { - data.hour[i].rx = data.hour[i].rx / (float)diff; - data.hour[i].tx = data.hour[i].tx / (float)diff; - } - } - } - } - - if (data.hour[i].date>=data.hour[tmax].date) { - tmax=i; - } - if (data.hour[i].rx>=max) { - max=data.hour[i].rx; - } - if (data.hour[i].tx>=max) { - max=data.hour[i].tx; - } - } - - /* scale values */ - scaleunit = getscale(max); - if (max/scaleunit > 4) { - step = 2; - } else { - step = 1; - } - - for (i=step; (uint64_t)(scaleunit*i) <= max; i=i+step) { - s = 121 * ((scaleunit * i) / (float)max); - gdImageLine(ic->im, x+36, y+124-s, x+460, y+124-s, ic->cline); - gdImageLine(ic->im, x+36, y+124-((s+prev)/2), x+460, y+124-((s+prev)/2), ic->clinel); - gdImageString(ic->im, gdFontGetTiny(), x+16, y+121-s, (unsigned char*)getimagevalue(scaleunit*i, 3, rate), ic->ctext); - prev = s; - } - s = 121 * ((scaleunit * i) / (float)max); - if ( ((s+prev)/2) <= 128 ) { - gdImageLine(ic->im, x+36, y+124-((s+prev)/2), x+460, y+124-((s+prev)/2), ic->clinel); - } - - /* scale text */ - if (rate) { - gdImageStringUp(ic->im, gdFontGetTiny(), x-2, y+70, (unsigned char*)getimagescale(scaleunit, 1), ic->ctext); - } else { - gdImageStringUp(ic->im, gdFontGetTiny(), x-2, y+60, (unsigned char*)getimagescale(scaleunit, 0), ic->ctext); - } - - /* x-axis values and poles */ - for (i = 0; i < 24; i++) { - s=tmax-i; - if (s<0) { - s+=24; - } - snprintf(buffer, 32, "%02d ", s); - gdImageString(ic->im, gdFontGetTiny(), x+440-(i*17), y+128, (unsigned char*)buffer, ic->ctext); - drawpole(ic, x+438-(i*17), y, 124, data.hour[s].rx, data.hour[s].tx, max); - } - - /* axis */ - gdImageLine(ic->im, x+36-4, y+124, x+466, y+124, ic->ctext); - gdImageLine(ic->im, x+36, y-10, x+36, y+124+4, ic->ctext); - - /* arrows */ - gdImageLine(ic->im, x+465, y+124, x+462, y+122, ic->ctext); - gdImageLine(ic->im, x+465, y+124, x+462, y+126, ic->ctext); - gdImageLine(ic->im, x+462, y+122, x+462, y+126, ic->ctext); - gdImageLine(ic->im, x+36, y-9, x+38, y-6, ic->ctext); - gdImageLine(ic->im, x+36, y-9, x+34, y-6, ic->ctext); - gdImageLine(ic->im, x+34, y-6, x+38, y-6, ic->ctext); - -} - -void drawsummary(IMAGECONTENT *ic, int type, int rate) -{ - int textx, texty, offset = 0; - int width, height, headermod; - float rxp = 50, txp = 50, mod; - char buffer[512], datebuff[16], daytemp[32]; - time_t yesterday; - struct tm *d; - - switch (type) { - case 1: - width = 980; - height = 200; - break; - case 2: - width = 500; - height = 370; - break; - default: - width = 500; - height = 200; - break; - } - - if (!ic->showheader) { - headermod = 26; - height -= 22; - } else { - headermod = 0; - } - - yesterday=ic->current-86400; - - ic->im = gdImageCreate(width, height); - - colorinit(ic); - - if (strlen(ic->headertext)) { - strncpy_nt(buffer, ic->headertext, 65); - } else { - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s", data.interface); - } else { - snprintf(buffer, 512, "%s (%s)", data.nick, data.interface); - } - } - - layoutinit(ic, buffer, width, height); - - /* today */ - if (data.day[0].rx>1024 || data.day[0].tx>1024) { - rxp = (data.day[0].rx/(float)(data.day[0].rx+data.day[0].tx))*100; - txp = (float)100 - rxp; - } else { - if ( (data.day[0].rx*+data.day[0].rxk)+(data.day[0].tx*+data.day[0].txk) == 0 ) { - rxp = txp = 0; - } else { - rxp = ( ((data.day[0].rx*1024)+data.day[0].rxk) / (float)(((data.day[0].rx*1024)+data.day[0].rxk)+((data.day[0].tx*1024)+data.day[0].txk)) )*100; - txp = (float)100 - rxp; - } - } - - /* do scaling if needed */ - if ( (data.day[0].rx+data.day[0].tx) < (data.day[1].rx+data.day[1].tx) ) { - if ( (data.day[0].rx+data.day[0].tx)>1024 || (data.day[1].rx+data.day[1].tx)>1024 ) { - mod = (data.day[0].rx+data.day[0].tx) / (float)(data.day[1].rx+data.day[1].tx); - } else { - mod = (((data.day[0].rx*1024)+data.day[0].rxk)+((data.day[0].tx*1024)+data.day[0].txk)) / (float)(((data.day[1].rx*1024)+data.day[1].rxk)+((data.day[1].tx*1024)+data.day[1].txk)); - } - rxp = rxp * mod; - txp = txp * mod; - } - - /* move graph to center if there's only one to draw for this line */ - if (!data.day[1].date) { - offset = 85; - } else { - offset = 0; - } - - drawdonut(ic, 150+offset, 75-headermod, rxp, txp); - - textx = 100+offset; - texty = 30-headermod; - - /* get formated date for today */ - d = localtime(&ic->current); - strftime(datebuff, 16, cfg.dformat, d); - - /* get formated date for current day in database */ - d = localtime(&data.day[0].date); - strftime(daytemp, 16, cfg.dformat, d); - - /* change daytemp to today if formated days match */ - if (strcmp(datebuff, daytemp)==0) { - strncpy_nt(daytemp, "today", 32); - } - - snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp); - gdImageString(ic->im, gdFontGetLarge(), textx-54, texty-1, (unsigned char*)buffer, ic->ctext); - - if (cfg.summaryrate) { - d = localtime(&data.lastupdated); - snprintf(buffer, 16, "%15s", getrate(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, d->tm_sec+(d->tm_min*60)+(d->tm_hour*3600), 15)); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+58, (unsigned char*)buffer, ic->ctext); - } else { - texty += 7; - } - - snprintf(buffer, 4, "rx "); - strncat(buffer, getvalue(data.day[0].rx, data.day[0].rxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+18, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, "tx "); - strncat(buffer, getvalue(data.day[0].tx, data.day[0].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+30, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, " = "); - strncat(buffer, getvalue(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+44, (unsigned char*)buffer, ic->ctext); - - - /* yesterday */ - if (data.day[1].date) { - if (data.day[1].rx>1024 || data.day[1].tx>1024) { - rxp = (data.day[1].rx/(float)(data.day[1].rx+data.day[1].tx))*100; - txp = (float)100 - rxp; - } else { - if ( (data.day[1].rx*+data.day[1].rxk)+(data.day[1].tx*+data.day[1].txk) == 0 ) { - rxp = txp = 0; - } else { - rxp = ( ((data.day[1].rx*1024)+data.day[1].rxk) / (float)(((data.day[1].rx*1024)+data.day[1].rxk)+((data.day[1].tx*1024)+data.day[1].txk)) )*100; - txp = (float)100 - rxp; - } - } - - /* do scaling if needed */ - if ( (data.day[1].rx+data.day[1].tx) < (data.day[0].rx+data.day[0].tx) ) { - if ( (data.day[1].rx+data.day[1].tx)>1024 || (data.day[0].rx+data.day[0].tx)>1024 ) { - mod = (data.day[1].rx+data.day[1].tx) / (float)(data.day[0].rx+data.day[0].tx); - } else { - mod = (((data.day[1].rx*1024)+data.day[1].rxk)+((data.day[1].tx*1024)+data.day[1].txk)) / (float)(((data.day[0].rx*1024)+data.day[0].rxk)+((data.day[0].tx*1024)+data.day[0].txk)); - } - rxp = rxp * mod; - txp = txp * mod; - } - - drawdonut(ic, 330, 75-headermod, rxp, txp); - - textx = 280; - texty = 30-headermod; - - /* get formated date for yesterday */ - d = localtime(&yesterday); - strftime(datebuff, 16, cfg.dformat, d); - - /* get formated date for previous day in database */ - d = localtime(&data.day[1].date); - strftime(daytemp, 16, cfg.dformat, d); - - /* change daytemp to yesterday if formated days match */ - if (strcmp(datebuff, daytemp)==0) { - strncpy_nt(daytemp, "yesterday", 32); - } - - snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp); - gdImageString(ic->im, gdFontGetLarge(), textx-54, texty-1, (unsigned char*)buffer, ic->ctext); - - if (cfg.summaryrate) { - snprintf(buffer, 16, "%15s", getrate(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 86400, 15)); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+58, (unsigned char*)buffer, ic->ctext); - } else { - texty += 7; - } - - snprintf(buffer, 4, "rx "); - strncat(buffer, getvalue(data.day[1].rx, data.day[1].rxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+18, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, "tx "); - strncat(buffer, getvalue(data.day[1].tx, data.day[1].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+30, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, " = "); - strncat(buffer, getvalue(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+44, (unsigned char*)buffer, ic->ctext); - } - - /* current month */ - if (data.month[0].rx>1024 || data.month[0].tx>1024) { - rxp = (data.month[0].rx/(float)(data.month[0].rx+data.month[0].tx))*100; - txp = (float)100 - rxp; - } else { - if ( (data.month[0].rx+data.month[0].rxk)+(data.month[0].tx+data.month[0].txk) == 0 ) { - rxp = txp = 0; - } else { - rxp = ( ((data.month[0].rx*1024)+data.month[0].rxk) / (float)(((data.month[0].rx*1024)+data.month[0].rxk)+((data.month[0].tx*1024)+data.month[0].txk)) )*100; - txp = (float)100 - rxp; - } - } - - - /* do scaling if needed */ - if ( (data.month[0].rx+data.month[0].tx) < (data.month[1].rx+data.month[1].tx) ) { - if ( (data.month[0].rx+data.month[0].tx)>1024 || (data.month[1].rx+data.month[1].tx)>1024 ) { - mod = (data.month[0].rx+data.month[0].tx) / (float)(data.month[1].rx+data.month[1].tx); - } else { - mod = (((data.month[0].rx*1024)+data.month[0].rxk)+((data.month[0].tx*1024)+data.month[0].txk)) / (float)(((data.month[1].rx*1024)+data.month[1].rxk)+((data.month[1].tx*1024)+data.month[1].txk)); - } - rxp = rxp * mod; - txp = txp * mod; - } - - /* move graph to center if there's only one to draw for this line */ - if (!data.month[1].month) { - offset = 85; - } else { - offset = 0; - } - - drawdonut(ic, 150+offset, 163-headermod, rxp, txp); - - textx = 100+offset; - texty = 118-headermod; - - d = localtime(&data.month[0].month); - strftime(daytemp, 16, cfg.mformat, d); - - snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp); - gdImageString(ic->im, gdFontGetLarge(), textx-54, texty-1, (unsigned char*)buffer, ic->ctext); - - if (cfg.summaryrate) { - snprintf(buffer, 16, "%15s", getrate(data.month[0].rx+data.month[0].tx, data.month[0].rxk+data.month[0].txk, mosecs(), 15)); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+58, (unsigned char*)buffer, ic->ctext); - } else { - texty += 7; - } - - snprintf(buffer, 4, "rx "); - strncat(buffer, getvalue(data.month[0].rx, data.month[0].rxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+18, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, "tx "); - strncat(buffer, getvalue(data.month[0].tx, data.month[0].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+30, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, " = "); - strncat(buffer, getvalue(data.month[0].rx+data.month[0].tx, data.month[0].rxk+data.month[0].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+44, (unsigned char*)buffer, ic->ctext); - - - /* previous month */ - if (data.month[1].month) { - if (data.month[1].rx>1024 || data.month[1].tx>1024) { - rxp = (data.month[1].rx/(float)(data.month[1].rx+data.month[1].tx))*100; - txp = (float)100 - rxp; - } else { - if ( (data.month[1].rx+data.month[1].rxk)+(data.month[1].tx+data.month[1].txk) == 0 ) { - rxp = txp = 0; - } else { - rxp = ( ((data.month[1].rx*1024)+data.month[1].rxk) / (float)(((data.month[1].rx*1024)+data.month[1].rxk)+((data.month[1].tx*1024)+data.month[1].txk)) )*100; - txp = (float)100 - rxp; - } - } - - /* do scaling if needed */ - if ( (data.month[1].rx+data.month[1].tx) < (data.month[0].rx+data.month[0].tx) ) { - if ( (data.month[1].rx+data.month[1].tx)>1024 || (data.month[0].rx+data.month[0].tx)>1024 ) { - mod = (data.month[1].rx+data.month[1].tx) / (float)(data.month[0].rx+data.month[0].tx); - } else { - mod = (((data.month[1].rx*1024)+data.month[1].rxk)+((data.month[1].tx*1024)+data.month[1].txk)) / (float)(((data.month[0].rx*1024)+data.month[0].rxk)+((data.month[0].tx*1024)+data.month[0].txk)); - } - rxp = rxp * mod; - txp = txp * mod; - } - - drawdonut(ic, 330, 163-headermod, rxp, txp); - - textx = 280; - texty = 118-headermod; - - d = localtime(&data.month[1].month); - strftime(daytemp, 16, cfg.mformat, d); - - snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp); - gdImageString(ic->im, gdFontGetLarge(), textx-54, texty-1, (unsigned char*)buffer, ic->ctext); - - if (cfg.summaryrate) { - snprintf(buffer, 16, "%15s", getrate(data.month[1].rx+data.month[1].tx, data.month[1].rxk+data.month[1].txk, dmonth(d->tm_mon)*86400, 15)); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+58, (unsigned char*)buffer, ic->ctext); - } else { - texty += 7; - } - - snprintf(buffer, 4, "rx "); - strncat(buffer, getvalue(data.month[1].rx, data.month[1].rxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+18, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, "tx "); - strncat(buffer, getvalue(data.month[1].tx, data.month[1].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+30, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, " = "); - strncat(buffer, getvalue(data.month[1].rx+data.month[1].tx, data.month[1].rxk+data.month[1].txk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx-74, texty+44, (unsigned char*)buffer, ic->ctext); - } - - /* all time */ - textx = 385; - texty = 57-headermod; - - gdImageString(ic->im, gdFontGetLarge(), textx+12, texty, (unsigned char*)"all time", ic->ctext); - snprintf(buffer, 4, "rx "); - strncat(buffer, getvalue(data.totalrx, data.totalrxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+24, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, "tx "); - strncat(buffer, getvalue(data.totaltx, data.totaltxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+36, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 4, " = "); - strncat(buffer, getvalue(data.totalrx+data.totaltx, data.totalrxk+data.totaltxk, 12, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+50, (unsigned char*)buffer, ic->ctext); - d = localtime(&data.created); - strftime(datebuff, 16, cfg.tformat, d); - snprintf(daytemp, 7, "since "); - strncat(daytemp, datebuff, 16); - snprintf(buffer, 20, "%19s", daytemp); - gdImageString(ic->im, gdFontGetSmall(), textx-24, texty+70, (unsigned char*)buffer, ic->ctext); - - drawlegend(ic, 410, 155-headermod); - - /* hours if requested */ - switch (type) { - case 1: - drawhours(ic, 500, 46-headermod, rate); - break; - case 2: - drawhours(ic, 6, 215-headermod, rate); - break; - default: - break; - } - -} - -void drawoldsummary(IMAGECONTENT *ic, int type, int rate) -{ - int piex, piey, piew, pieh, arc, textx, texty; - int i, tk, width, height, headermod; - float rxp = 50, txp = 50; - uint64_t t, max, e_rx, e_tx; - char buffer[512], datebuff[16], daytemp[32], daytemp2[32]; - time_t yesterday; - struct tm *d; - - switch (type) { - case 1: - width = 980; - height = 200; - break; - case 2: - width = 500; - height = 370; - break; - default: - width = 500; - height = 200; - break; - } - - if (!ic->showheader) { - headermod = 26; - height -= 22; - } else { - headermod = 0; - } - - yesterday=ic->current-86400; - - ic->im = gdImageCreate(width, height); - - colorinit(ic); - - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s", data.interface); - } else { - snprintf(buffer, 512, "%s (%s)", data.nick, data.interface); - } - - layoutinit(ic, buffer, width, height); - drawlegend(ic, 383, 110-headermod); - - if (data.totalrx || data.totalrxk || data.totaltx || data.totaltxk) { - if (data.totalrx>1024 || data.totaltx>1024) { - rxp = (data.totalrx/(float)(data.totalrx+data.totaltx))*100; - } else { - rxp = ( ((data.totalrx*1024)+data.totalrxk) / (float)(((data.totalrx*1024)+data.totalrxk)+((data.totaltx*1024)+data.totaltxk)) )*100; - } - txp = (float)100 - rxp; - } - - d=localtime(&data.lastupdated); - - if ( data.day[0].rx==0 || data.day[0].tx==0 || (d->tm_hour*60+d->tm_min)==0 ) { - e_rx = e_tx=0; - } else { - e_rx = ((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440; - e_tx = ((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440; - } - - piex = 400; - piey = 63-headermod; - piew = 110; - pieh = 45; - arc = (txp / (float)100) * 360; - - /* pie chart */ - for(i = 14; i > 0; i--) { - gdImageFilledArc(ic->im, piex, piey+i, piew, pieh, 270, 270+arc, ic->ctxd, gdEdged|gdNoFill); - gdImageFilledArc(ic->im, piex, piey+i, piew, pieh, 270+arc, 270, ic->crxd, gdEdged|gdNoFill); - } - - gdImageFilledArc(ic->im, piex, piey, piew, pieh, 270, 270+arc, ic->ctx, 0); - gdImageFilledArc(ic->im, piex, piey, piew, pieh, 270, 270+arc, ic->ctxd, gdEdged|gdNoFill); - gdImageFilledArc(ic->im, piex, piey, piew, pieh, 270+arc, 270, ic->crx, 0); - gdImageFilledArc(ic->im, piex, piey, piew, pieh, 270+arc, 270, ic->crxd, gdEdged|gdNoFill); - - textx = 30; - texty = 48-headermod; - - /* totals */ - snprintf(buffer, 512, " received: %s (%.1f%%)", getvalue(data.totalrx, data.totalrxk, 14, 1), rxp); - gdImageString(ic->im, gdFontGetLarge(), textx, texty, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 512, "transmitted: %s (%.1f%%)", getvalue(data.totaltx, data.totaltxk, 14, 1), txp); - gdImageString(ic->im, gdFontGetLarge(), textx, texty+15, (unsigned char*)buffer, ic->ctext); - snprintf(buffer, 512, " total: %s", getvalue(data.totalrx+data.totaltx, data.totalrxk+data.totaltxk, 14, 1)); - gdImageString(ic->im, gdFontGetLarge(), textx, texty+30, (unsigned char*)buffer, ic->ctext); - - /* get formated date for yesterday */ - d=localtime(&yesterday); - strftime(datebuff, 16, cfg.dformat, d); - - /* get formated date for previous day in database */ - d=localtime(&data.day[1].date); - strftime(daytemp, 16, cfg.dformat, d); - - /* change daytemp to yesterday if formated days match */ - if (strcmp(datebuff, daytemp)==0) { - strncpy_nt(daytemp, "yesterday", 32); - } - - /* get formated date for today */ - d=localtime(&ic->current); - strftime(datebuff, 16, cfg.dformat, d); - - /* get formated date for current day in database */ - d=localtime(&data.day[0].date); - strftime(daytemp2, 16, cfg.dformat, d); - - /* change daytemp to today if formated days match */ - if (strcmp(datebuff, daytemp2)==0) { - strncpy_nt(daytemp2, "today", 32); - } - - textx = 20; - texty = 118-headermod; - - /* yesterday & today */ - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" rx tx total", ic->ctext); - gdImageLine(ic->im, textx-4, texty+16, textx+290, texty+16, ic->cline); - gdImageLine(ic->im, textx-4, texty+49, textx+290, texty+49, ic->cline); - gdImageLine(ic->im, textx+140, texty+4, textx+140, texty+64, ic->cline); - gdImageLine(ic->im, textx+218, texty+4, textx+218, texty+64, ic->cline); - - if (data.day[1].date!=0) { - snprintf(buffer, 32, "%*s ", getpadding(9, daytemp), daytemp); - strncat(buffer, getvalue(data.day[1].rx, data.day[1].rxk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[1].tx, data.day[1].txk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 10, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+20, (unsigned char*)buffer, ic->ctext); - } - - snprintf(buffer, 32, "%*s ", getpadding(9, daytemp2), daytemp2); - strncat(buffer, getvalue(data.day[0].rx, data.day[0].rxk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[0].tx, data.day[0].txk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, 10, 1), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+32, (unsigned char*)buffer, ic->ctext); - - snprintf(buffer, 32, "estimated "); - strncat(buffer, getvalue(e_rx, 0, 10, 2), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(e_tx, 0, 10, 2), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(e_rx+e_tx, 0, 10, 2), 32); - gdImageString(ic->im, gdFontGetSmall(), textx, texty+52, (unsigned char*)buffer, ic->ctext); - - /* search maximum */ - max=1; - for (i = 1; i >= 0; i--) { - if (data.day[i].used) { - - t=data.day[i].rx+data.day[i].tx; - tk=data.day[i].rxk+data.day[i].txk; - - t=mbkbtokb(t, tk); - - if (t>max) { - max=t; - } - } - } - - /* bars for both */ - drawbar(ic, textx+300, texty+24, 165, data.day[1].rx, data.day[1].rxk, data.day[1].tx, data.day[1].txk, max); - drawbar(ic, textx+300, texty+36, 165, data.day[0].rx, data.day[0].rxk, data.day[0].tx, data.day[0].txk, max); - - /* hours if requested */ - switch (type) { - case 1: - drawhours(ic, 500, 46-headermod, rate); - break; - case 2: - drawhours(ic, 16, 215-headermod, rate); - break; - default: - break; - } - -} - -void drawhourly(IMAGECONTENT *ic, int rate) -{ - int width, height, headermod; - char buffer[512]; - - width = 500; - height = 200; - - if (!ic->showheader) { - headermod = 26; - height -= 22; - } else { - headermod = 0; - } - - ic->im = gdImageCreate(width, height); - - colorinit(ic); - - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s / hourly", data.interface); - } else { - snprintf(buffer, 512, "%s (%s) / hourly", data.nick, data.interface); - } - - layoutinit(ic, buffer, width, height); - drawlegend(ic, 242, 183-headermod); - drawhours(ic, 12, 46-headermod, rate); -} - void drawdaily(IMAGECONTENT *ic) { - int textx, texty, lines; - int i, tk, width, height, headermod; - uint64_t t, max, e_rx, e_tx; + int textx, texty; + int width, height, headermod; + uint64_t e_rx, e_tx; char buffer[512], datebuff[16]; struct tm *d; + dbdatalist *datalist = NULL, *datalist_i = NULL; + dbdatalistinfo datainfo; - /* count how many days needs to be shown */ - lines = 0; - for (i = 0; i < 30; i++) { - if (data.day[i].used) { - lines++; - } + if (!db_getdata(&datalist, &datainfo, ic->interface.name, "day", 30)) { + printf("Error: Failed to fetch %s data.\n", "day"); + return; } + datalist_i = datalist; + width = 500; - height = 98 + (12 * lines); + height = 98 + (12 * datainfo.count); if (!ic->showheader) { headermod = 26; @@ -962,15 +296,15 @@ void drawdaily(IMAGECONTENT *ic) colorinit(ic); - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s / daily", data.interface); + if (strcmp(ic->interface.name, ic->interface.alias) == 0 || strlen(ic->interface.alias) == 0) { + snprintf(buffer, 512, "%s / daily", ic->interface.name); } else { - snprintf(buffer, 512, "%s (%s) / daily", data.nick, data.interface); + snprintf(buffer, 512, "%s (%s) / daily", ic->interface.alias, ic->interface.name); } layoutinit(ic, buffer, width, height); - if (lines) { + if (datainfo.count) { if (cfg.ostyle>2) { drawlegend(ic, 432, 40-headermod); } else { @@ -984,223 +318,54 @@ void drawdaily(IMAGECONTENT *ic) if (cfg.ostyle>2) { gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" day rx tx total avg. rate", ic->ctext); gdImageLine(ic->im, textx+2, texty+16, textx+392, texty+16, ic->cline); - gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+300, texty+2, textx+300, texty+40+(12*lines), ic->cline); + gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*datainfo.count), ic->cline); + gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*datainfo.count), ic->cline); + gdImageLine(ic->im, textx+300, texty+2, textx+300, texty+40+(12*datainfo.count), ic->cline); } else { gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" day rx tx total", ic->ctext); gdImageLine(ic->im, textx+2, texty+16, textx+296, texty+16, ic->cline); - gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*lines), ic->cline); + gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*datainfo.count), ic->cline); + gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*datainfo.count), ic->cline); } texty += 20; - /* search maximum */ - max=1; - for (i = 29; i >= 0; i--) { - if (data.day[i].used) { - - t=data.day[i].rx+data.day[i].tx; - tk=data.day[i].rxk+data.day[i].txk; - - if (tk>=1024) { - t+=tk/1024; - tk-=(tk/1024)*1024; - } - - t=(t*1024)+tk; - - if (t>max) { - max=t; - } - } - } - - for (i = 29; i >= 0; i--) { - if (data.day[i].used) { - - d = localtime(&data.day[i].date); - if (strftime(datebuff, 16, cfg.dformat, d)<=8) { - snprintf(buffer, 32, " %*s ", getpadding(8, datebuff), datebuff); - } else { - snprintf(buffer, 32, " %-*s ", getpadding(11, datebuff), datebuff); - } - strncat(buffer, getvalue(data.day[i].rx, data.day[i].rxk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[i].tx, data.day[i].txk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.day[i].rx+data.day[i].tx, data.day[i].rxk+data.day[i].txk, 10, 1), 32); - if (cfg.ostyle>2) { - strcat(buffer, " "); - if (i==0) { - d = localtime(&data.lastupdated); - strncat(buffer, getrate(data.day[i].rx+data.day[i].tx, data.day[i].rxk+data.day[i].txk, d->tm_sec+(d->tm_min*60)+(d->tm_hour*3600), 14), 32); - } else { - strncat(buffer, getrate(data.day[i].rx+data.day[i].tx, data.day[i].rxk+data.day[i].txk, 86400, 14), 32); - } - } - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)buffer, ic->ctext); - if (cfg.ostyle>2) { - drawbar(ic, textx+400, texty+4, 78, data.day[i].rx, data.day[i].rxk, data.day[i].tx, data.day[i].txk, max); - } else { - drawbar(ic, textx+304, texty+4, 170, data.day[i].rx, data.day[i].rxk, data.day[i].tx, data.day[i].txk, max); - } - texty += 12; - } - } - - if (lines==0) { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" no data available", ic->ctext); - texty += 12; - } + while (datalist_i != NULL) { - if (cfg.ostyle>2) { - gdImageLine(ic->im, textx+2, texty+5, textx+392, texty+5, ic->cline); - } else { - gdImageLine(ic->im, textx+2, texty+5, textx+296, texty+5, ic->cline); - } - - if (lines) { - - d=localtime(&data.lastupdated); - if ( data.day[0].rx==0 || data.day[0].tx==0 || (d->tm_hour*60+d->tm_min)==0 ) { - e_rx=e_tx=0; + d = localtime(&datalist_i->timestamp); + if (strftime(datebuff, 16, cfg.dformat, d)<=8) { + snprintf(buffer, 32, " %*s ", getpadding(8, datebuff), datebuff); } else { - e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440; - e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440; + snprintf(buffer, 32, " %-*s ", getpadding(11, datebuff), datebuff); } - snprintf(buffer, 32, " estimated "); - strncat(buffer, getvalue(e_rx, 0, 10, 2), 32); + strncat(buffer, getvalue(datalist_i->rx, 10, 1), 32); strcat(buffer, " "); - strncat(buffer, getvalue(e_tx, 0, 10, 2), 32); + strncat(buffer, getvalue(datalist_i->tx, 10, 1), 32); strcat(buffer, " "); - strncat(buffer, getvalue(e_rx+e_tx, 0, 10, 2), 32); - - gdImageString(ic->im, gdFontGetSmall(), textx, texty+8, (unsigned char*)buffer, ic->ctext); - } - -} - -void drawmonthly(IMAGECONTENT *ic) -{ - int textx, texty, lines; - int i, tk, width, height, headermod; - uint64_t t, max, e_rx, e_tx; - char buffer[512], datebuff[16]; - struct tm *d; - - /* count how many months needs to be shown */ - lines = 0; - for (i = 0; i < 12; i++) { - if (data.month[i].used) { - lines++; + strncat(buffer, getvalue(datalist_i->rx+datalist_i->tx, 10, 1), 32); + if (cfg.ostyle>2) { + strcat(buffer, " "); + if (datalist_i->next == NULL) { + d = localtime(&ic->interface.updated); + strncat(buffer, gettrafficrate(datalist_i->rx+datalist_i->tx, d->tm_sec+(d->tm_min*60)+(d->tm_hour*3600), 14), 32); + } else { + strncat(buffer, gettrafficrate(datalist_i->rx+datalist_i->tx, 86400, 14), 32); + } } - } - - width = 500; - height = 98 + (12 * lines); - - if (!ic->showheader) { - headermod = 26; - height -= 22; - } else { - headermod = 0; - } - - ic->im = gdImageCreate(width, height); - - colorinit(ic); - - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s / monthly", data.interface); - } else { - snprintf(buffer, 512, "%s (%s) / monthly", data.nick, data.interface); - } - - layoutinit(ic, buffer, width, height); - - if (lines) { + gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)buffer, ic->ctext); if (cfg.ostyle>2) { - drawlegend(ic, 432, 40-headermod); + drawbar(ic, textx+400, texty+4, 78, datalist_i->rx, datalist_i->tx, datainfo.max); } else { - drawlegend(ic, 385, 40-headermod); + drawbar(ic, textx+304, texty+4, 170, datalist_i->rx, datalist_i->tx, datainfo.max); } - } - - textx = 10; - texty = 40-headermod; - - if (cfg.ostyle>2) { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" month rx tx total avg. rate", ic->ctext); - gdImageLine(ic->im, textx+2, texty+16, textx+392, texty+16, ic->cline); - gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+300, texty+2, textx+300, texty+40+(12*lines), ic->cline); - } else { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" month rx tx total", ic->ctext); - gdImageLine(ic->im, textx+2, texty+16, textx+296, texty+16, ic->cline); - gdImageLine(ic->im, textx+144, texty+2, textx+144, texty+40+(12*lines), ic->cline); - gdImageLine(ic->im, textx+222, texty+2, textx+222, texty+40+(12*lines), ic->cline); - } - - - texty += 20; - - /* search maximum */ - max=1; - for (i = 11; i >= 0; i--) { - if (data.month[i].used) { - - t=data.month[i].rx+data.month[i].tx; - tk=data.month[i].rxk+data.month[i].txk; - - if (tk>=1024) { - t+=tk/1024; - tk-=(tk/1024)*1024; - } - - t=(t*1024)+tk; - - if (t>max) { - max=t; - } - } - } - - for (i = 11; i >= 0; i--) { - if (data.month[i].used) { - - d = localtime(&data.month[i].month); - if (strftime(datebuff, 16, cfg.mformat, d)<=9) { - snprintf(buffer, 32, " %*s ", getpadding(9, datebuff), datebuff); - } else { - snprintf(buffer, 32, " %-*s ", getpadding(11, datebuff), datebuff); - } - strncat(buffer, getvalue(data.month[i].rx, data.month[i].rxk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.month[i].tx, data.month[i].txk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.month[i].rx+data.month[i].tx, data.month[i].rxk+data.month[i].txk, 10, 1), 32); - if (cfg.ostyle>2) { - strcat(buffer, " "); - if (i==0) { - strncat(buffer, getrate(data.month[0].rx+data.month[0].tx, data.month[0].rxk+data.month[0].txk, mosecs(), 14), 32); - } else { - strncat(buffer, getrate(data.month[i].rx+data.month[i].tx, data.month[i].rxk+data.month[i].txk, dmonth(d->tm_mon)*86400, 14), 32); - } - } - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)buffer, ic->ctext); - if (cfg.ostyle>2) { - drawbar(ic, textx+400, texty+4, 78, data.month[i].rx, data.month[i].rxk, data.month[i].tx, data.month[i].txk, max); - } else { - drawbar(ic, textx+304, texty+4, 170, data.month[i].rx, data.month[i].rxk, data.month[i].tx, data.month[i].txk, max); - } - texty += 12; + texty += 12; + if (datalist_i->next == NULL) { + break; } + datalist_i = datalist_i->next; } - if (lines==0) { + if (!datainfo.count) { gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" no data available", ic->ctext); texty += 12; } @@ -1211,144 +376,26 @@ void drawmonthly(IMAGECONTENT *ic) gdImageLine(ic->im, textx+2, texty+5, textx+296, texty+5, ic->cline); } - if (lines) { + if (datainfo.count) { - d=localtime(&data.month[0].month); - if ( data.month[0].rx==0 || data.month[0].tx==0 || (data.lastupdated-data.month[0].month)==0 ) { + d=localtime(&ic->interface.updated); + if ( datalist_i->rx==0 || datalist_i->tx==0 || (d->tm_hour*60+d->tm_min)==0 ) { e_rx=e_tx=0; } else { - e_rx=(data.month[0].rx/(float)(mosecs()))*(dmonth(d->tm_mon)*86400); - e_tx=(data.month[0].tx/(float)(mosecs()))*(dmonth(d->tm_mon)*86400); + e_rx=((datalist_i->rx)/(float)(d->tm_hour*60+d->tm_min))*1440; + e_tx=((datalist_i->tx)/(float)(d->tm_hour*60+d->tm_min))*1440; } snprintf(buffer, 32, " estimated "); - strncat(buffer, getvalue(e_rx, 0, 10, 2), 32); + strncat(buffer, getvalue(e_rx, 10, 2), 32); strcat(buffer, " "); - strncat(buffer, getvalue(e_tx, 0, 10, 2), 32); + strncat(buffer, getvalue(e_tx, 10, 2), 32); strcat(buffer, " "); - strncat(buffer, getvalue(e_rx+e_tx, 0, 10, 2), 32); + strncat(buffer, getvalue(e_rx+e_tx, 10, 2), 32); gdImageString(ic->im, gdFontGetSmall(), textx, texty+8, (unsigned char*)buffer, ic->ctext); } -} - -void drawtop(IMAGECONTENT *ic) -{ - int textx, texty, lines = 0; - int i, tk, width, height, headermod; - uint64_t t, max = 1; - char buffer[512], datebuff[16]; - struct tm *d; - - /* count how many days needs to be shown and search maximum */ - for (i = 0; i < 10; i++) { - if (data.top10[i].used) { - lines++; - t=data.top10[i].rx+data.top10[i].tx; - tk=data.top10[i].rxk+data.top10[i].txk; - if (tk>=1024) { - t+=tk/1024; - tk-=(tk/1024)*1024; - } - t=(t*1024)+tk; - if (t>max) { - max=t; - } - } - } - - width = 500; - - if (lines) { - height = 86 + (12 * lines); - } else { - height = 98; - } - - if (!ic->showheader) { - headermod = 26; - height -= 22; - } else { - headermod = 0; - } - ic->im = gdImageCreate(width, height); - - colorinit(ic); - - if (strcmp(data.nick, data.interface)==0) { - snprintf(buffer, 512, "%s / top 10", data.interface); - } else { - snprintf(buffer, 512, "%s (%s) / top 10", data.nick, data.interface); - } - - layoutinit(ic, buffer, width, height); - - if (lines) { - if (cfg.ostyle<=2) { - drawlegend(ic, 398, 40-headermod); - } - } - - textx = 10; - texty = 40-headermod; - - if (cfg.ostyle>2) { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" # day rx tx total avg. rate", ic->ctext); - gdImageLine(ic->im, textx+2, texty+16, textx+422, texty+16, ic->cline); - if (lines) { - gdImageLine(ic->im, textx+174, texty+2, textx+174, texty+24+(12*lines), ic->cline); - gdImageLine(ic->im, textx+252, texty+2, textx+252, texty+24+(12*lines), ic->cline); - gdImageLine(ic->im, textx+330, texty+2, textx+330, texty+24+(12*lines), ic->cline); - } - } else { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" # day rx tx total", ic->ctext); - gdImageLine(ic->im, textx+2, texty+16, textx+326, texty+16, ic->cline); - if (lines) { - gdImageLine(ic->im, textx+174, texty+2, textx+174, texty+24+(12*lines), ic->cline); - gdImageLine(ic->im, textx+252, texty+2, textx+252, texty+24+(12*lines), ic->cline); - } - } - - texty += 20; - - for (i = 0; i < 10; i++) { - if (data.top10[i].used) { - - d = localtime(&data.top10[i].date); - if (strftime(datebuff, 16, cfg.tformat, d)<=8) { - snprintf(buffer, 32, " %2d %*s ", i+1, getpadding(8, datebuff), datebuff); - } else { - snprintf(buffer, 32, " %2d %-*s ", i+1, getpadding(11, datebuff), datebuff); - } - strncat(buffer, getvalue(data.top10[i].rx, data.top10[i].rxk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.top10[i].tx, data.top10[i].txk, 10, 1), 32); - strcat(buffer, " "); - strncat(buffer, getvalue(data.top10[i].rx+data.top10[i].tx, data.top10[i].rxk+data.top10[i].txk, 10, 1), 32); - if (cfg.ostyle>2) { - strcat(buffer, " "); - strncat(buffer, getrate(data.top10[i].rx+data.top10[i].tx, data.top10[i].rxk+data.top10[i].txk, 86400, 14), 32); - } - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)buffer, ic->ctext); - if (cfg.ostyle>2) { - drawbar(ic, textx+428, texty+4, 52, data.top10[i].rx, data.top10[i].rxk, data.top10[i].tx, data.top10[i].txk, max); - } else { - drawbar(ic, textx+336, texty+4, 140, data.top10[i].rx, data.top10[i].rxk, data.top10[i].tx, data.top10[i].txk, max); - } - texty += 12; - } - } - - if (lines==0) { - gdImageString(ic->im, gdFontGetSmall(), textx, texty, (unsigned char*)" no data available", ic->ctext); - texty += 12; - } - - if (cfg.ostyle>2) { - gdImageLine(ic->im, textx+2, texty+5, textx+422, texty+5, ic->cline); - } else { - gdImageLine(ic->im, textx+2, texty+5, textx+326, texty+5, ic->cline); - } + dbdatalistfree(&datalist); } void hextorgb(char *input, int *rgb) @@ -1377,7 +424,7 @@ void hextorgb(char *input, int *rgb) } } -void modcolor(int *rgb, int offset, int force) +void modcolor(int *rgb, const int offset, const int force) { int i, overflow = 0; @@ -1418,34 +465,34 @@ void modcolor(int *rgb, int offset, int force) } } -char *getimagevalue(uint64_t kb, int len, int rate) +char *getimagevalue(const uint64_t b, const int len, const int rate) { static char buffer[64]; int declen=0; - if (kb==0){ + if (b==0){ snprintf(buffer, 64, "%*s", len, "--"); } else { /* try to figure out what unit to use */ if (rate) { - if (kb>=1000000000) { /* 1000*1000*1000 - value >=1000 Gbps -> show in Tbps */ - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1000000000); /* 1000*1000*1000 */ - } else if (kb>=1000000) { /* 1000*1000 - value >=1000 Mbps -> show in Gbps */ - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1000000); /* 1000*1000 */ - } else if (kb>=1000) { - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1000); + if (b>=1000000000) { /* 1000*1000*1000 - value >=1000 Gbps -> show in Tbps */ + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1000000000); /* 1000*1000*1000 */ + } else if (b>=1000000) { /* 1000*1000 - value >=1000 Mbps -> show in Gbps */ + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1000000); /* 1000*1000 */ + } else if (b>=1000) { + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1000); } else { - snprintf(buffer, 64, "%*"PRIu64"", len, kb); + snprintf(buffer, 64, "%*"PRIu64"", len, b); } } else { - if (kb>=1048576000) { /* 1024*1024*1000 - value >=1000 GiB -> show in TiB */ - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1073741824); /* 1024*1024*1024 */ - } else if (kb>=1024000) { /* 1024*1000 - value >=1000 MiB -> show in GiB */ - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1048576); /* 1024*1024 */ - } else if (kb>=1000) { - snprintf(buffer, 64, "%*.*f", len, declen, kb/(float)1024); + if (b>=1048576000) { /* 1024*1024*1000 - value >=1000 GiB -> show in TiB */ + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1073741824); /* 1024*1024*1024 */ + } else if (b>=1024000) { /* 1024*1000 - value >=1000 MiB -> show in GiB */ + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1048576); /* 1024*1024 */ + } else if (b>=1000) { + snprintf(buffer, 64, "%*.*f", len, declen, b/(float)1024); } else { - snprintf(buffer, 64, "%*"PRIu64"", len, kb); + snprintf(buffer, 64, "%*"PRIu64"", len, b); } } } @@ -1453,13 +500,13 @@ char *getimagevalue(uint64_t kb, int len, int rate) return buffer; } -char *getimagescale(uint64_t kb, int rate) +char *getimagescale(const uint64_t b, const int rate) { static char buffer[8]; uint32_t limit[3]; int unit; - if (kb==0) { + if (b==0) { snprintf(buffer, 8, "--"); } else { @@ -1478,21 +525,21 @@ char *getimagescale(uint64_t kb, int rate) unit = cfg.unitmode; } - if (kb>=limit[2]) { + if (b>=limit[2]) { snprintf(buffer, 8, "%s", getrateunitprefix(unit, 4)); - } else if (kb>=limit[1]) { + } else if (b>=limit[1]) { snprintf(buffer, 8, "%s", getrateunitprefix(unit, 3)); - } else if (kb>=limit[0]) { + } else if (b>=limit[0]) { snprintf(buffer, 8, "%s", getrateunitprefix(unit, 2)); } else { snprintf(buffer, 8, "%s", getrateunitprefix(unit, 1)); } } else { - if (kb>=1048576000) { /* 1024*1024*1000 - value >=1000 GiB -> show in TiB */ + if (b>=1048576000) { /* 1024*1024*1000 - value >=1000 GiB -> show in TiB */ snprintf(buffer, 8, "%s", getunitprefix(4)); - } else if (kb>=1024000) { /* 1024*1000 - value >=1000 MiB -> show in GiB */ + } else if (b>=1024000) { /* 1024*1000 - value >=1000 MiB -> show in GiB */ snprintf(buffer, 8, "%s", getunitprefix(3)); - } else if (kb>=1000) { + } else if (b>=1000) { snprintf(buffer, 8, "%s", getunitprefix(2)); } else { snprintf(buffer, 8, "%s", getunitprefix(1)); diff --git a/src/image.h b/src/image.h index 14283c64..0923ae0c 100644 --- a/src/image.h +++ b/src/image.h @@ -18,6 +18,7 @@ typedef struct { gdImagePtr im; + interfaceinfo interface; int cbackground, cedge, cheader, cheadertitle, cheaderdate, ctext, cline, clinel, cvnstat; int crx, crxd, ctx, ctxd, cbgoffset, showheader, showedge, showlegend, altdate; char headertext[65]; @@ -27,22 +28,22 @@ typedef struct { void initimagecontent(IMAGECONTENT *ic); void drawimage(IMAGECONTENT *ic); void colorinit(IMAGECONTENT *ic); -void colorinitcheck(char *color, int value, char *cfgtext, int *rgb); -void layoutinit(IMAGECONTENT *ic, char *title, int width, int height); -void drawlegend(IMAGECONTENT *ic, int x, int y); -void drawbar(IMAGECONTENT *ic, int x, int y, int len, uint64_t rx, int rxk, uint64_t tx, int txk, uint64_t max); -void drawpole(IMAGECONTENT *ic, int x, int y, int len, uint64_t rx, uint64_t tx, uint64_t max); -void drawdonut(IMAGECONTENT *ic, int x, int y, float rxp, float txp); -void drawhours(IMAGECONTENT *ic, int x, int y, int rate); +void colorinitcheck(const char *color, const int value, const char *cfgtext, const int *rgb); +void layoutinit(IMAGECONTENT *ic, const char *title, const int width, const int height); +void drawlegend(IMAGECONTENT *ic, const int x, const int y); +void drawbar(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max); +void drawpole(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max); +void drawdonut(IMAGECONTENT *ic, const int x, const int y, const float rxp, const float txp); +/*void drawhours(IMAGECONTENT *ic, int x, int y, int rate); void drawsummary(IMAGECONTENT *ic, int type, int rate); void drawoldsummary(IMAGECONTENT *ic, int type, int rate); -void drawhourly(IMAGECONTENT *ic, int rate); +void drawhourly(IMAGECONTENT *ic, int rate); */ void drawdaily(IMAGECONTENT *ic); -void drawmonthly(IMAGECONTENT *ic); -void drawtop(IMAGECONTENT *ic); +/*void drawmonthly(IMAGECONTENT *ic); +void drawtop(IMAGECONTENT *ic); */ void hextorgb(char *input, int *rgb); -void modcolor(int *rgb, int offset, int force); -char *getimagevalue(uint64_t kb, int len, int rate); -char *getimagescale(uint64_t kb, int rate); +void modcolor(int *rgb, const int offset, const int force); +char *getimagevalue(const uint64_t b, const int len, const int rate); +char *getimagescale(const uint64_t b, const int rate); #endif diff --git a/src/vnstati.c b/src/vnstati.c index 8fd0359b..d4ba66d7 100644 --- a/src/vnstati.c +++ b/src/vnstati.c @@ -16,9 +16,9 @@ vnStat image output - Copyright (c) 2007-2017 Teemu Toivola */ #include "common.h" +#include "dbsql.h" #include "image.h" #include "cfg.h" -#include "dbaccess.h" #include "vnstati.h" int main(int argc, char *argv[]) @@ -58,7 +58,6 @@ int main(int argc, char *argv[]) configlocale(); strncpy_nt(p.interface, cfg.iface, 32); - strncpy_nt(p.dirname, cfg.dbdir, 512); ic.current = time(NULL); /* parse parameters */ @@ -133,9 +132,9 @@ int main(int argc, char *argv[]) } } else if ((strcmp(argv[currentarg],"--dbdir"))==0) { if (currentarg+1interface[0] = '\0'; - p->dirname[0] = '\0'; p->filename[0] = '\0'; p->cfgfile[0] = '\0'; p->cache = 0; @@ -318,16 +317,19 @@ void handlecaching(IPARAMS *p, IMAGECONTENT *ic) } } -void handledatabase(IPARAMS *p) +void handledatabase(IPARAMS *p, IMAGECONTENT *ic) { - if (strstr(p->interface, "+")) { - if (!mergedb(p->interface, p->dirname)) { - exit(EXIT_FAILURE); - } - } else { - if (readdb(p->interface, p->dirname, 0)==1) { - exit(EXIT_FAILURE); - } + if (!db_open(0)) { + printf("Error: Unable to open database \"%s/%s\": %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + exit(EXIT_FAILURE); + } + if (!db_getinterfacecountbyname(p->interface)) { + printf("Error: Interface \"%s\" not found in database.\n", p->interface); + exit(EXIT_FAILURE); + } + if (!db_getinterfaceinfo(p->interface, &ic->interface)) { + printf("Error: Failed to fetch interface \"%s\" info from database.\n", p->interface); + exit(EXIT_FAILURE); } } diff --git a/src/vnstati.h b/src/vnstati.h index 5c401ba3..96be4e3f 100644 --- a/src/vnstati.h +++ b/src/vnstati.h @@ -1,11 +1,9 @@ #ifndef VNSTATI_H #define VNSTATI_H -#include "image.h" - typedef struct { int cache, help; - char interface[32], dirname[512], filename[512], cfgfile[512]; + char interface[32], filename[512], cfgfile[512]; FILE *pngout; } IPARAMS; @@ -13,7 +11,7 @@ void initiparams(IPARAMS *p); void showihelp(IPARAMS *p); void validateinput(IPARAMS *p); void handlecaching(IPARAMS *p, IMAGECONTENT *ic); -void handledatabase(IPARAMS *p); +void handledatabase(IPARAMS *p, IMAGECONTENT *ic); void openoutput(IPARAMS *p); void writeoutput(IPARAMS *p, IMAGECONTENT *ic);