# 2.11BSD#431 - /usr/src/new/notes/src/newsdump.c

##### Functions

    newsnote          X
    newsresp          X
    tzone             X

##### Variables

    Version           X

       1: #include "parms.h"
       2: #include "structs.h"
       3: #include "newsgate.h"
       4:
       5: #ifdef  RCSIDENT
       6: static char *RCSid = "$Header: newsdump.c,v 1.7.0.10 85/10/31 09:03:40 notes Rel $";
       7: #endif	RCSIDENT
       8:
       9: /*
      10:  *	newsnote - take a note and dump it in a format that news will
      11:  *	understand. Submit the article to the news program as
      12:  *	defined in newsgate.h
      13:  *
      14:  *	newsresp - similar to newsnote, but it dumps a response instead.
      15:  *
      16:  *	The routines build some title lines and other headers for
      17:  *	submission to the news insertion program. The rest of the
      18:  *	article is fed to the news program through a pipe.
      19:  *	This turned out to be mucho mucho easier than building the
      20:  *	properly formatted intersystem files.
      21:  *
      22:  *	Original Coding:	Ray Essick	April 1982
      23:  *	Modified to produce cleaner looking output:
      24:  *				Ray Essick	May 1, 1982
      25:  *				(with good help from Brian Redman (harpo!ber)
      26:  *	Modified to solve meta-character ("'`) problems in popen()
      27:  *				Ray Essick	September 1982
      28:  *
      29:  *	Lots of code by Tw Cook at Hewlett-Packard to implement
      30:  *	compatibility with the USENET standards for news.
      31:  *			January 1984.
      32:  */
      33:
      34: extern char *mnames[];                  /* month names */
      35: FILE * popen ();
      36:
      37: char   *Version = "$Revision: 1.7.0.10 $";      /* Use RCS info */
      38:
      39: newsnote (io, note, notenum, ngroup, backwards)
      40: struct io_f *io;
      41: struct note_f  *note;
      42: char   *ngroup;                     /* to this newsgroup */
      43: {
      44:     FILE * rnews;                   /* rnews pipe */
      45:     char    cmdline[CMDLEN];                /* command line  */
      46:     char    line[TITLEN + 50];              /* scratch line */
      47:     int     i;
      48:     char   *p,
      49:            *q;
      50:     char    ntitle[TITLEN + 10];            /* title */
      51:     char    from[SYSSZ + NAMESZ + 3];           /* formatted author */
      52:     char    path[BUFSIZ];               /* path to author */
      53:     char   *author;                 /* for Path line */
      54:
      55: /*
      56:  *	format some of the internal data structures in a suitable
      57:  *	format to send to the news system.
      58:  */
      59:
      60:     strcpy (ntitle, note -> ntitle);            /* make a title */
      61:     if (backwards)
      62:     {
      63:     strcat (ntitle, " ");               /* separate */
      64:     strcat (ntitle, NFSUFFIX);          /* add suffix */
      65:     }
      66:
      67:     /*
      68:      * From:
      69:      *		author information
      70:      */
      71:     sprintf (from, "%s@%s",             /* author */
      72:         note -> n_auth.aname, note -> n_auth.asystem);
      73: #ifdef  notdef
      74:     /*
      75:      * decided it was better to NOT append a domain here...
      76:      */
      77:     if (index (note -> n_auth.asystem, '.') != (char *) NULL)/* domained */
      78:     {
      79:     sprintf (from, "%s@%s",
      80:         note -> n_auth.aname, note -> n_auth.asystem);
      81:     }
      82:     else
      83:     {
      84:     sprintf (from, "%s@%s.%s",
      85:         note -> n_auth.aname, note -> n_auth.asystem,
      86:         DFLTDOMAIN);                /* append default */
      87:     }
      88: #endif	notdef
      89:     /*
      90:      * Path:
      91:      *	where the article has been
      92:      *  Maybe we want to use some format besides a!b!c, something like
      93:      *  a,b,c
      94:      */
      95:     if (!strcmp (System, note -> n_id.sys))     /* local */
      96:     {
      97:     sprintf (path, "%s", note -> n_id.sys);
      98:     }
      99:     else
     100:     {
     101:     if (!strcmp (note -> n_id.sys, note -> n_from)) /* one hop */
     102:     {
     103:         sprintf (path, "%s!%s",
     104:             System,
     105:             note -> n_id.sys);
     106:     }
     107:     else
     108:     {
     109:         sprintf (path, "%s!%s!%s",          /* several hops */
     110:             System, note -> n_from, note -> n_id.sys);
     111:     }
     112:     }
     113: #ifdef  UGLYPATH                    /* usually so */
     114:     /*
     115:      * Fill in the "authorname" with either a placeholder
     116:      * or the real author name. Key this off whether the unique
     117:      * id matches the author's home system.
     118:      *
     119:      * This will usually use AUTHORPLACEHOLDER on new systems
     120:      * since the unique id's don't have the domains in yet.
     121:      *
     122:      * hacked at to satisfy the public at large still using the
     123:      * Path line although it's not supposed to be good any longer.
     124:      * new code checks to see if things are a common prefix. and
     125:      * that the next character in the longer string is a "."
     126:      * if so, it declares things good enough and uses the real author.
     127:      */
     128:     {
     129:     int     idlen,
     130:             authlen;
     131:     int     isok;
     132:     int     minlen;
     133:
     134:     idlen = strlen (note -> n_id.sys);
     135:     authlen = strlen (note -> n_auth.asystem);
     136:     minlen = idlen < authlen ? idlen : authlen; /* get shortest */
     137:     isok = (strncmp (note -> n_id.sys, note -> n_auth.asystem, minlen) == 0);
     138:     if (isok && idlen < authlen)            /* id is short */
     139:     {
     140:         isok &= (note -> n_auth.asystem[idlen] == '.');
     141:     }
     142:     else
     143:     {
     144:         if (isok && authlen < idlen)
     145:         isok &= (note -> n_id.sys[authlen] == '.');
     146:     }
     147:     if (isok)
     148:         author = note -> n_auth.aname;      /* ok for him */
     149:     else
     150:         author = AUTHORPLACEHOLDER;         /* not local */
     151:     }
     152: #else   !UGLYPATH
     153:     /*
     154:      * the bnews code all assumes that the last component of
     155:      * the Path line is a user name. If we don't append something,
     156:      * that system will see the articles again, since news will
     157:      * disregard it when comparing to see where things have been.
     158:      */
     159:     author = AUTHORPLACEHOLDER;
     160: #endif	UGLYPATH
     161: /*
     162:  *	dump the article
     163:  */
     164:
     165:     if ((rnews = popen (rnewscmd, "w")) == NULL)    /* open news pipe */
     166:     return (-1);                    /* report failure */
     167:
     168:     fprintf (rnews, "Relay-Version: Notesfiles %s; site %s\n",
     169:         Version, System);
     170: /*
     171:  *	Here we make a slight deviation from what one would expect.
     172:  *	We use the LOCAL version of the notes/news gateway to pick
     173:  *	the Posting Version line. This is because we are the version
     174:  *	that actually makes the insertion into the news system.
     175:  *
     176:  *	To back it up, the Usenet Standards papr (rfc whatever) says
     177:  *	that the Posting-version "identifies the software responsible
     178:  *	for entering this message into the network".
     179:  *	Whether the "site" field should be the gatewaying site or where
     180:  *	the article originated is a good question.
     181:  *	I chose to make it the notes->news gateway running locally and
     182:  *	the site where the article originated.
     183:  *
     184:  *	The stuff with the #ifdef notdef is to preserve the old code
     185:  *	that just labeled article we gateway with a Posting version
     186:  *	of "Notesfiles" instead of "Notesfiles 1.x".
     187:  */
     188: #ifdef  notdef
     189:     if (!strcmp (System, note -> n_id.sys))     /* local note */
     190: #endif	notdef
     191:     {
     192:     /*
     193: 	 * always consider ourselves the posting version. We are the
     194: 	 * site that posted it to news!  There could be a question
     195: 	 * about articles gated in two places or which site should be
     196: 	 * there.
     197: 	 */
     198:     fprintf (rnews, "Posting-Version: Notesfiles %s; site %s\n",
     199:         Version, note -> n_id.sys);
     200:     }
     201: #ifdef  notdef
     202:     else                        /* remote note */
     203:     fprintf (rnews, "Posting-Version: Notesfiles; site %s.%s\n",
     204:         note -> n_id.sys, DFLTDOMAIN);      /* unknown version */
     205: #endif	notdef
     206:     fprintf (rnews, "From: %s\n", from);        /* formatted */
     207: /*
     208:  *	Sample format that is legal
     209:  *  fprintf (rnews, "Date: 13-Jan-83 12:08 PST\n");
     210:  */
     211:     fprintf (rnews, "Date: %02d-%3s-%02d %02d:%02d %3s\n",
     212:         note -> n_date.w_day,
     213:         mnames[note -> n_date.w_month],
     214:         note -> n_date.w_year - 1900,
     215:         note -> n_date.w_hours,
     216:         note -> n_date.w_mins,
     217:         tzone (&note -> n_date));
     218:     fprintf (rnews, "Newsgroups: %s\n", ngroup);
     219:     fprintf (rnews, "Subject: %s\n", ntitle);
     220:     fprintf (rnews, "Message-ID: <%ld@%s>\n", note -> n_id.uniqid,
     221:         note -> n_id.sys);
     222:     fprintf (rnews, "Path: %s!%s\n", path, author);
     223:
     224: /*
     225:  *	send out the notesfile specfic headers
     226:  */
     227:     if (note -> n_addr.addr == 0)           /* make sure */
     228:     note -> n_addr.textlen = 0;         /* on empty text */
     229:
     230:     fprintf (rnews, "%s: #N:%s:%ld:%03o:%ld\n",     /* nf header */
     231:         NFLINE1,                    /* "NF-line1" */
     232:         note -> n_id.sys, note -> n_id.uniqid,
     233:         note -> n_stat, ((long) note -> n_addr.textlen));
     234:
     235:     fprintf (rnews, "%s: %s!%s    %3s %2d %02d:%02d:00 %4d\n",
     236:         NFLINE2,                    /* "Nf-line2" */
     237:         note -> n_auth.asystem, note -> n_auth.aname,/* author */
     238:         mnames[note -> n_date.w_month],     /* date written */
     239:         note -> n_date.w_day,
     240:         note -> n_date.w_hours,
     241:         note -> n_date.w_mins,
     242:         note -> n_date.w_year);
     243: /*
     244:  *	Optional headers that we don't hassle with right now:
     245:  *	   Organization:	make a table driven routine to grab
     246:  */
     247:
     248:     putc ('\n', rnews);                 /* separator */
     249:     if (backwards)                  /* include old stuff */
     250:     {
     251:     fprintf (rnews, "#N:%s:%ld:%03o:%ld\n",     /* nf header */
     252:         note -> n_id.sys, note -> n_id.uniqid,
     253:         note -> n_stat, ((long) note -> n_addr.textlen));
     254:
     255:     fprintf (rnews, "%s!%s    %3s %2d %02d:%02d:00 %4d\n",
     256:         note -> n_auth.asystem, note -> n_auth.aname,/* author */
     257:         mnames[note -> n_date.w_month],     /* date written */
     258:         note -> n_date.w_day,
     259:         note -> n_date.w_hours,
     260:         note -> n_date.w_mins,
     261:         note -> n_date.w_year);
     262:     }
     263:     putc ('\n', rnews);                 /* separator */
     264:     pageout (io, &note -> n_addr, rnews);       /* dump text */
     265:     fprintf (rnews, "\n");              /* ensure newline */
     266:     pclose (rnews);                 /* close it */
     267:     sleep (SLEEPTIME);                  /* wait a while */
     268:     return (0);
     269: }
     270:
     271: /*
     272:  *	newsresp
     273:  *
     274:  *	Dump a response to the news system.
     275:  */
     276:
     277: newsresp (io, note, notenum, rsprec, roffset, respnum, ngroup, backwards)
     278: struct io_f *io;
     279: struct note_f  *note;
     280: struct resp_f  *rsprec;
     281: char   *ngroup;
     282: {
     283:     char    cmdline[CMDLEN];                /* leggo brand */
     284:     char    line[TITLEN + 50];              /* scratch */
     285:     FILE * rnews;
     286:     int     i;
     287:     char   *p,
     288:            *q;
     289:     char    ntitle[TITLEN + 20];            /* formatted title */
     290:     char    from[SYSSZ + NAMESZ + 3];           /* formatted author */
     291:     char    path[BUFSIZ];               /* path to author */
     292:     char   *author;                 /* for Path: */
     293:     long    uniquenum;
     294:
     295: /*
     296:  *	pre-format a few fields like titles, author information,
     297:  *	paths to authors, and that sort of gunk.
     298:  */
     299:
     300:     ntitle[0] = '\0';                   /* empty string */
     301:     if (strncmp (note -> ntitle, "Re:", 3) &&       /* is it already */
     302:         strncmp (note -> ntitle, "RE:", 3) &&   /* a response-like */
     303:         strncmp (note -> ntitle, "re:", 3))     /* title? */
     304:     {                           /* flag it as a */
     305:     strcat (ntitle, "Re: ");            /* response */
     306:     }
     307:     strcat (ntitle, note -> ntitle);            /* include title */
     308:     if (backwards)
     309:     {
     310:     strcat (ntitle, " ");
     311:     strcat (ntitle, NFSUFFIX);          /* include old */
     312:     }
     313:
     314:     /*
     315:      * From:
     316:      *	author information
     317:      */
     318:     sprintf (from, "%s@%s",             /* author */
     319:         rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem);
     320: #ifdef  notdef
     321:     /*
     322:      * decided it was better to NOT append a domain at this point
     323:      */
     324:     if (index (rsprec -> r_auth[roffset].asystem, '.') != (char *) NULL)
     325:     {                           /* already domained */
     326:     sprintf (from, "%s@%s",
     327:         rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem);
     328:     }
     329:     else
     330:     {
     331:     sprintf (from, "%s@%s.%s",
     332:         rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem,
     333:         DFLTDOMAIN);
     334:     }
     335: #endif	notdef
     336:     /*
     337:      * Path:
     338:      *	Where the article has been
     339:      */
     340:     if (!strcmp (System, rsprec -> r_id[roffset].sys))  /* local */
     341:     {
     342:     sprintf (path, "%s", rsprec -> r_id[roffset].sys);
     343:     }
     344:     else
     345:     {
     346:     if (!strcmp (rsprec -> r_id[roffset].sys, rsprec -> r_from[roffset]))
     347:     {                       /* one hop */
     348:         sprintf (path, "%s!%s",
     349:             System,
     350:             rsprec -> r_id[roffset].sys);
     351:     }
     352:     else
     353:     {
     354:         sprintf (path, "%s!%s!%s",          /* several hops */
     355:             System,
     356:             rsprec -> r_from[roffset],
     357:             rsprec -> r_id[roffset].sys);
     358:     }
     359:     }
     360: #ifdef  UGLYPATH                    /* usually so */
     361:     /*
     362:      * See if we can use the author's name instead of
     363:      * AUTHORPLACEHOLDER.  Check this by comparin unique id's
     364:      * and the author's system.
     365:      *
     366:      * see similar code above in newsnote() for explanation of the
     367:      * gyrations here.
     368:      */
     369:     {
     370:     int     idlen,
     371:             authlen;
     372:     int     isok;
     373:     int     minlen;
     374:
     375:     idlen = strlen (rsprec -> r_id[roffset].sys);
     376:     authlen = strlen (rsprec -> r_auth[roffset].asystem);
     377:     minlen = idlen < authlen ? idlen : authlen;
     378:     isok = (strncmp (rsprec -> r_id[roffset].sys, rsprec -> r_auth[roffset].asystem, minlen) == 0);
     379:     if (isok && idlen < authlen)            /* id is short */
     380:     {
     381:         isok &= (rsprec -> r_auth[roffset].asystem[idlen] == '.');
     382:     }
     383:     else
     384:     {
     385:         if (isok && authlen < idlen)        /* author syste is short */
     386:         isok &= (rsprec -> r_id[roffset].sys[authlen] == '.');
     387:     }
     388:     if (isok)
     389:         author = rsprec -> r_auth[roffset].aname;
     390:     else
     391:         author = AUTHORPLACEHOLDER;
     392:     }
     393: #else   !UGLYPATH
     394:     /*
     395:      * since bnews programs all assume the last component of the
     396:      * path line is a user name, we have to put something there
     397:      * to keep them from disregarding the system name when trying
     398:      * to see where the article has been.
     399:      */
     400:     author = AUTHORPLACEHOLDER;
     401: #endif	UGLYPATH
     402:
     403: /*
     404:  *	Time to send the article to the news system
     405:  */
     406:
     407:     if ((rnews = popen (rnewscmd, "w")) == NULL)    /* will it work */
     408:     return (-1);                    /* report failure */
     409:
     410:     fprintf (rnews, "Relay-Version: Notesfiles %s; site %s\n",
     411:         Version, System);
     412: #ifdef  notdef
     413:     if (!strcmp (System, rsprec -> r_id[roffset].sys))  /* local note */
     414: #endif	notdef
     415:     {
     416:     /*
     417: 	 * always consider ourselves the posting version. We are the
     418: 	 * site that posted it to news!  There could be a question
     419: 	 * about articles gated in two places or which site should be
     420: 	 * there.
     421: 	 *
     422: 	 * See comments around similar lines within the newsnote()
     423: 	 * routine above
     424: 	 */
     425:     fprintf (rnews, "Posting-Version: Notesfiles %s; site %s\n",
     426:         Version, rsprec -> r_id[roffset].sys);
     427:     }
     428: #ifdef  notdef
     429:     else                        /* remote note */
     430:     fprintf (rnews, "Posting-Version: Notesfiles; site %s.%s\n",
     431:         rsprec -> r_id[roffset].sys, DFLTDOMAIN);/* unknown version */
     432: #endif	notdef
     433:     fprintf (rnews, "From: %s\n", from);        /* formatted */
     434: /*
     435:  *	Sample format that is legal
     436:  *  fprintf (rnews, "Date: 13-Jan-83 12:08 PST\n");
     437:  */
     438:     fprintf (rnews, "Date: %02d-%3s-%02d %02d:%02d %3s\n",
     439:         rsprec -> r_when[roffset].w_day,
     440:         mnames[rsprec -> r_when[roffset].w_month],
     441:         rsprec -> r_when[roffset].w_year - 1900,
     442:         rsprec -> r_when[roffset].w_hours,
     443:         rsprec -> r_when[roffset].w_mins,
     444:         tzone (&rsprec -> r_when[roffset]));
     445:     fprintf (rnews, "Newsgroups: %s\n", ngroup);
     446:     fprintf (rnews, "Subject: %s\n", ntitle);
     447:     fprintf (rnews, "Message-ID: <%ld@%s>\n",
     448:         rsprec -> r_id[roffset].uniqid, rsprec -> r_id[roffset].sys);
     449:     fprintf (rnews, "Path: %s!%s\n", path, author);
     450:
     451: /*
     452:  *	send out the notesfile specfic headers
     453:  */
     454:     fprintf (rnews, "%s: #R:%s:%ld:%s:%ld:%03o:%ld\n",
     455:         NFLINE1,                    /* Nf-ID */
     456:         note -> n_id.sys, note -> n_id.uniqid,
     457:         rsprec -> r_id[roffset].sys,
     458:         rsprec -> r_id[roffset].uniqid,
     459:         rsprec -> r_stat[roffset],
     460:         ((long) rsprec -> r_addr[roffset].textlen));/* force it long */
     461:
     462:
     463:     fprintf (rnews, "%s: %s!%s    %3s %2d %02d:%02d:00 %4d\n",
     464:         NFLINE2,                    /* NF-From */
     465:         rsprec -> r_auth[roffset].asystem, rsprec -> r_auth[roffset].aname,
     466:         mnames[rsprec -> r_when[roffset].w_month],  /* date written */
     467:         rsprec -> r_when[roffset].w_day,
     468:         rsprec -> r_when[roffset].w_hours,
     469:         rsprec -> r_when[roffset].w_mins,
     470:         rsprec -> r_when[roffset].w_year);
     471:     /*
     472:      * we used to negate and multiply by 100 news ids. this was tied
     473:      * to the fact that news and notes id's conflicted.
     474:      * the new code to handle the arbitrary string message ids uses
     475:      * negative numbers to store the length of the original id.
     476:      * we change the following if from <0 to <-100 because
     477:      * we know lengths are likely < 100 and that the old flipped
     478:      * format is definitely <= -100.
     479:      */
     480:     if ((uniquenum = note -> n_id.uniqid) <= -100)  /* re-invert news */
     481:     uniquenum /= (-100);                /* back to normal */
     482:     if (uniquenum >= 0)                 /* normal form */
     483:     {
     484:     fprintf (rnews, "References: <%ld@%s>\n",
     485:         uniquenum, note -> n_id.sys);
     486:     }
     487:     else
     488:     {                           /* all in n_id.sys */
     489:     /*
     490: 	 * print it if we have the entire id.  if we only have a part,
     491: 	 * punt and that's too bad.
     492: 	 */
     493:     if (-uniquenum == strlen (note -> n_id.sys))    /* have it all */
     494:         fprintf (rnews, "References: %s\n", note -> n_id.sys);
     495:     }
     496:
     497:     putc ('\n', rnews);                 /* separator */
     498:     if (backwards)                  /* old stuff included */
     499:     {
     500:     fprintf (rnews, "#R:%s:%ld:%s:%ld:%03o:%ld\n",
     501:         note -> n_id.sys, note -> n_id.uniqid,
     502:         rsprec -> r_id[roffset].sys,
     503:         rsprec -> r_id[roffset].uniqid,
     504:         rsprec -> r_stat[roffset],
     505:         ((long) rsprec -> r_addr[roffset].textlen));/* force it long */
     506:
     507:     fprintf (rnews, "%s!%s    %3s %2d %02d:%02d:00 %4d\n",
     508:         rsprec -> r_auth[roffset].asystem, rsprec -> r_auth[roffset].aname,
     509:         mnames[rsprec -> r_when[roffset].w_month],/* date written */
     510:         rsprec -> r_when[roffset].w_day,
     511:         rsprec -> r_when[roffset].w_hours,
     512:         rsprec -> r_when[roffset].w_mins,
     513:         rsprec -> r_when[roffset].w_year);
     514:     }
     515:     putc ('\n', rnews);                 /* separator */
     516:     pageout (io, &rsprec -> r_addr[roffset], rnews);    /* dump text */
     517:     fprintf (rnews, "\n");              /* ensure a newline */
     518:     pclose (rnews);                 /* close it */
     519:     sleep (SLEEPTIME);                  /* and wait */
     520:     return (0);
     521: }
     522:
     523: /*
     524:  *	A quick and cheap way to calculate a timezone.
     525:  *
     526:  *	This routine makes the assumption that a notesfile site
     527:  *	we gateway for is in the same timezone as our site.
     528:  *
     529:  */
     530:
     531: char   *tzone (when)
     532: struct when_f   when;                   /* unused */
     533: {
     534: #ifdef  BSD42
     535: #include        <sys/time.h>            /* it moved! */
     536: #else
     537: #include        <time.h>
     538: #endif	BSD42
     539: #include    <sys/types.h>               /* for ftime */
     540:
     541:     struct tm  *ltime;
     542:     extern struct tm   *localtime ();
     543:     long    timenow;
     544:
     545: #ifdef  USG
     546:     struct tm  *bp;
     547:     extern char *tzname[];
     548:
     549:     time (&timenow);
     550:     ltime = localtime (&timenow);
     551:     return (tzname[ltime -> tm_isdst]);
     552: #else
     553: /*
     554:  *	for systems that still have the "timezone" function from V7
     555:  */
     556: #include    <sys/timeb.h>               /* for ftime */
     557:     struct timeb    rawtime;
     558:     extern char *timezone ();               /* please lint */
     559:
     560:     ftime (&rawtime);                   /* get information */
     561:     time (&timenow);                    /* get now */
     562:     ltime = localtime (&timenow);           /* see if DST */
     563:     return (timezone ((int) rawtime.timezone, ltime -> tm_isdst));
     564: #endif
     565: }

#### Defined functions

newsnote defined in line 39; used 1 times

- in /usr/src/new/notes/src/newsout.c line 119

newsresp defined in line 277; used 1 times

- in /usr/src/new/notes/src/newsout.c line 146

tzone defined in line 531; used 3 times

- in line 217, 444
- in /usr/src/new/notes/src/newsgate.h line 103

#### Defined variables

RCSid defined in line 6; never used
Version defined in line 37; used 4 times

- in line 169, 199, 411, 426

Last modified: 1985-10-31 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1387 |