Back to index

opendkim  2.6.2
Classes | Defines | Functions | Variables
repute.c File Reference
#include "build-config.h"
#include <sys/param.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <ut.h>
#include "repute.h"

Go to the source code of this file.

Classes

struct  repute_io
struct  repute_handle
struct  repute_lookup

Defines

#define REPUTE_BUFBASE   1024
#define REPUTE_URL   1024

Functions

static size_t repute_curl_writedata (char *ptr, size_t size, size_t nmemb, void *userdata)
static int repute_name_to_code (struct repute_lookup *tbl, const char *name)
static REPUTE_STAT repute_parse (const char *buf, size_t buflen, float *rep, float *conf, unsigned long *sample, unsigned long *limit, time_t *when)
static struct repute_iorepute_get_io (REPUTE rep)
static void repute_put_io (REPUTE rep, struct repute_io *rio)
static REPUTE_STAT repute_doquery (struct repute_io *rio, const char *url)
static void repute_get_error (struct repute_io *rio, char *buf, size_t buflen)
static int repute_get_template (REPUTE rep)
void repute_init (void)
REPUTE repute_new (const char *server, unsigned int reporter)
void repute_close (REPUTE rep)
const char * repute_curlversion (REPUTE rep)
void repute_useragent (REPUTE rep, const char *ua)
REPUTE_STAT repute_query (REPUTE rep, const char *domain, float *repout, float *confout, unsigned long *sampout, unsigned long *limitout, time_t *whenout)
const char * repute_error (REPUTE rep)

Variables

static char repute_c_id [] = "$Id$"

Class Documentation

struct repute_io

Definition at line 47 of file repute.c.

Collaboration diagram for repute_io:
Class Members
size_t repute_alloc
char * repute_buf
CURL * repute_curl
CURLcode repute_errcode
struct repute_io * repute_next
size_t repute_offset
unsigned int repute_rcode
struct repute_handle

Definition at line 58 of file repute.c.

Collaboration diagram for repute_handle:
Class Members
const char * rep_curlversion
char rep_error
struct repute_io * rep_ios
pthread_mutex_t rep_lock
unsigned int rep_reporter
const char * rep_server
char rep_uritemp
const char * rep_useragent
struct repute_lookup

Definition at line 70 of file repute.c.

Class Members
int rt_code
const char * rt_name

Define Documentation

#define REPUTE_BUFBASE   1024

Definition at line 43 of file repute.c.

#define REPUTE_URL   1024

Definition at line 44 of file repute.c.


Function Documentation

void repute_close ( REPUTE  rep)

Definition at line 826 of file repute.c.

{
       struct repute_io *rio;
       struct repute_io *next;

       assert(rep != NULL);

       rio = rep->rep_ios;
       while (rio != NULL)
       {
              next = rio->repute_next;

              if (rio->repute_buf != NULL)
                     free(rio->repute_buf);
              if (rio->repute_curl != NULL)
                     curl_easy_cleanup(rio->repute_curl);
              free(rio);

              rio = next;
       }

       pthread_mutex_destroy(&rep->rep_lock);

       free((void *) rep->rep_server);

       free(rep);
}

Here is the caller graph for this function:

static size_t repute_curl_writedata ( char *  ptr,
size_t  size,
size_t  nmemb,
void *  userdata 
) [static]

Definition at line 131 of file repute.c.

{
       size_t need;
       struct repute_io *io;

       io = userdata;

       need = size * nmemb;

       if (io->repute_buf == NULL)
       {
              io->repute_alloc = MAX(REPUTE_BUFBASE, need);
              io->repute_buf = malloc(io->repute_alloc);
              if (io->repute_buf == NULL)
                     return 0;
              memset(io->repute_buf, '\0', io->repute_alloc);
       }
       else if (io->repute_offset + need > io->repute_alloc)
       {
              size_t newsize;
              char *newbuf;

              newsize = MAX(io->repute_alloc * 2, io->repute_alloc + need);
              newbuf = realloc(io->repute_buf, newsize);
              if (newbuf == NULL)
              {
                     return 0;
              }
              else
              {
                     memset(newbuf + io->repute_offset, '\0',
                            newsize - io->repute_offset);
              }
              io->repute_buf = newbuf;
              io->repute_alloc = newsize;
       }

       memcpy(io->repute_buf + io->repute_offset, ptr, need);

       io->repute_offset += need;

       return need;
}

Here is the caller graph for this function:

const char* repute_curlversion ( REPUTE  rep)

Definition at line 865 of file repute.c.

{
       assert(rep != NULL);

       return rep->rep_curlversion;
}

Here is the caller graph for this function:

static REPUTE_STAT repute_doquery ( struct repute_io rio,
const char *  url 
) [static]

Definition at line 590 of file repute.c.

{
       CURLcode cstatus;
       long rcode;

       assert(rio != NULL);
       assert(url != NULL);

       cstatus = curl_easy_setopt(rio->repute_curl, CURLOPT_WRITEDATA, rio);
       if (cstatus != CURLE_OK)
       {
              rio->repute_errcode = cstatus;
              return REPUTE_STAT_INTERNAL;
       }

       cstatus = curl_easy_setopt(rio->repute_curl, CURLOPT_URL, url);
       if (cstatus != CURLE_OK)
       {
              rio->repute_errcode = cstatus;
              return REPUTE_STAT_INTERNAL;
       }

       rio->repute_errcode = 0;
       rio->repute_rcode = 0;
       memset(rio->repute_buf, '\0', rio->repute_alloc);

       cstatus = curl_easy_perform(rio->repute_curl);
       if (cstatus != CURLE_OK)
       {
              rio->repute_errcode = cstatus;
              return REPUTE_STAT_QUERY;
       }

       cstatus = curl_easy_getinfo(rio->repute_curl, CURLINFO_RESPONSE_CODE,
                                   &rcode);
       if (rcode != 200)
              return REPUTE_STAT_QUERY;

       return REPUTE_STAT_OK;
}

Here is the caller graph for this function:

const char* repute_error ( REPUTE  rep)

Definition at line 1026 of file repute.c.

{
       assert(rep != NULL);

       return rep->rep_error;
}

Here is the caller graph for this function:

static void repute_get_error ( struct repute_io rio,
char *  buf,
size_t  buflen 
) [static]

Definition at line 644 of file repute.c.

{
       assert(rio != NULL);
       assert(buf != NULL);

       if (rio->repute_rcode != 0)
              snprintf(buf, buflen, "HTTP error code %u", rio->repute_rcode);
       else
              snprintf(buf, buflen, curl_easy_strerror(rio->repute_errcode));
}

Here is the caller graph for this function:

static struct repute_io* repute_get_io ( REPUTE  rep) [static, read]

Definition at line 495 of file repute.c.

{
       assert(rep != NULL);

       struct repute_io *rio = NULL;

       pthread_mutex_lock(&rep->rep_lock);

       if (rep->rep_ios != NULL)
       {
              rio = rep->rep_ios;

              rep->rep_ios = rep->rep_ios->repute_next;

              rio->repute_offset = 0;
       }
       else
       {
              rio = malloc(sizeof *rio);
              if (rio != NULL)
              {
                     rio->repute_alloc = 0;
                     rio->repute_offset = 0;
                     rio->repute_buf = NULL;
                     rio->repute_next = NULL;

                     rio->repute_curl = curl_easy_init();
                     if (rio->repute_curl == NULL)
                     {
                            free(rio);
                            rio = NULL;
                     }
                     else
                     {
                            int status;

                            status = curl_easy_setopt(rio->repute_curl,
                                                      CURLOPT_WRITEFUNCTION,
                                                        repute_curl_writedata);
                            if (status != CURLE_OK)
                            {
                                   free(rio);
                                   rio = NULL;
                            }

                            if (rep->rep_useragent != NULL)
                            {
                                   (void) curl_easy_setopt(rio->repute_curl,
                                                           CURLOPT_USERAGENT,
                                                           rep->rep_useragent);
                            }
                     }
              }
       }

       pthread_mutex_unlock(&rep->rep_lock);

       return rio;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int repute_get_template ( REPUTE  rep) [static]

Definition at line 668 of file repute.c.

{
       int out;
       int cstatus;
       long rcode;
       struct repute_io *rio;
       URITEMP ut;
       char url[REPUTE_BUFBASE + 1];

       assert(rep != NULL);

       ut = ut_init();
       if (ut == NULL)
              return REPUTE_STAT_INTERNAL;

       if (ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "scheme", REPUTE_URI_SCHEME) != 0 ||
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "service", (void *) rep->rep_server) != 0 ||
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "application", REPUTE_URI_APPLICATION) != 0)
       {
              ut_destroy(ut);
              return REPUTE_STAT_INTERNAL;
       }

       if (ut_generate(ut, REPUTE_URI_TEMPLATE, url, sizeof url) <= 0)
       {
              ut_destroy(ut);
              return REPUTE_STAT_INTERNAL;
       }

       ut_destroy(ut);

       rio = repute_get_io(rep);
       if (rio == NULL)
              return REPUTE_STAT_INTERNAL;

       cstatus = curl_easy_setopt(rio->repute_curl, CURLOPT_WRITEDATA, rio);
       if (cstatus != CURLE_OK)
       {
              snprintf(rep->rep_error, sizeof rep->rep_error, "%s",
                       curl_easy_strerror(cstatus));
              repute_put_io(rep, rio);
              return REPUTE_STAT_INTERNAL;
       }

       cstatus = curl_easy_setopt(rio->repute_curl, CURLOPT_URL, url);
       if (cstatus != CURLE_OK)
       {
              snprintf(rep->rep_error, sizeof rep->rep_error, "%s",
                       curl_easy_strerror(cstatus));
              repute_put_io(rep, rio);
              return REPUTE_STAT_INTERNAL;
       }

       cstatus = curl_easy_perform(rio->repute_curl);
       if (cstatus != CURLE_OK)
       {
              snprintf(rep->rep_error, sizeof rep->rep_error, "%s",
                       curl_easy_strerror(cstatus));
              repute_put_io(rep, rio);
              return REPUTE_STAT_QUERY;
       }

       cstatus = curl_easy_getinfo(rio->repute_curl, CURLINFO_RESPONSE_CODE,
                                   &rcode);
       if (rcode != 200)
       {
              snprintf(rep->rep_error, sizeof rep->rep_error,
                       "HTTP response code %u", (unsigned int) rcode);
              repute_put_io(rep, rio);
              return REPUTE_STAT_QUERY;
       }

       (void) snprintf(rep->rep_uritemp, sizeof rep->rep_uritemp, "%s",
                       rio->repute_buf);
       if (rep->rep_uritemp[rio->repute_offset - 1] == '\n')
              rep->rep_uritemp[rio->repute_offset - 1] = '\0';

       repute_put_io(rep, rio);

       return REPUTE_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void repute_init ( void  )

Definition at line 764 of file repute.c.

{
#ifdef USE_XML2
       xmlInitParser();
#endif /* USE_XML2 */

       curl_global_init(CURL_GLOBAL_ALL);
}

Here is the caller graph for this function:

static int repute_name_to_code ( struct repute_lookup tbl,
const char *  name 
) [static]

Definition at line 187 of file repute.c.

{
       int c;

       assert(tbl != NULL);
       assert(name != NULL);

       for (c = 0; ; c++)
       {
              if (tbl[c].rt_name == NULL ||
                  strcasecmp(name, tbl[c].rt_name) == 0)
                     return tbl[c].rt_code;
       }

       return -1;
}

Here is the caller graph for this function:

REPUTE repute_new ( const char *  server,
unsigned int  reporter 
)

Definition at line 785 of file repute.c.

{
       struct repute_handle *new;
       curl_version_info_data *vinfo;

       assert(server != NULL);

       new = malloc(sizeof *new);
       if (new == NULL)
              return NULL;

       memset(new, '\0', sizeof *new);

       new->rep_reporter = reporter;
       new->rep_server = strdup(server);
       if (new->rep_server == NULL)
       {
              free(new);
              return NULL;
       }

       vinfo = curl_version_info(CURLVERSION_NOW);
       if (vinfo != NULL && vinfo->version != NULL)
              new->rep_curlversion = strdup(vinfo->version);

       pthread_mutex_init(&new->rep_lock, NULL);

       return new;
}

Here is the caller graph for this function:

static REPUTE_STAT repute_parse ( const char *  buf,
size_t  buflen,
float *  rep,
float *  conf,
unsigned long *  sample,
unsigned long *  limit,
time_t *  when 
) [static]

Definition at line 220 of file repute.c.

{
       _Bool found_dkim = FALSE;
       _Bool found_spam = FALSE;
       int code;
       float conftmp;
       float reptmp;
       unsigned long sampletmp;
       unsigned long limittmp;
       time_t whentmp;
       char *p;
       const char *start;
#ifdef USE_XML2
       xmlDocPtr doc = NULL;
       xmlNode *node = NULL;
       xmlNode *reputon = NULL;
#endif /* USE_XML2 */
#ifdef USE_JANSSON
       json_t *root = NULL;
       json_t *exts = NULL;
       json_t *obj = NULL;
       json_error_t error;
#endif /* USE_JANSSON */

       assert(buf != NULL);
       assert(rep != NULL);

#ifdef USE_XML2
       xmlSetGenericErrorFunc(NULL, repute_libxml2_errhandler);
#endif /* USE_XML2 */

       /* skip any header found */
       /* XXX -- this should verify a desirable Content-Type */
       for (start = buf; *start != '\0'; start++)
       {
              if (*start == '\n' && *(start + 1) == '\n')
              {
                     buflen = buflen - (start - buf + 2);
                     buf = start + 2;
                     break;
              }
              else if (*start == '\r' &&
                       *(start + 1) == '\n' &&
                       *(start + 2) == '\r' &&
                       *(start + 3) == '\n')
              {
                     buflen = buflen - (start - buf + 4);
                     buf = start + 4;
                     break;
              }
       }

#ifdef USE_JANSSON
       root = json_loads(buf, 0, &error);
       if (root == NULL)
              return REPUTE_STAT_PARSE;

       exts = json_object_get(root, REPUTE_XML_EXTENSION);
       if (exts != NULL && !json_is_object(exts))
       {
              json_decref(root);
              return REPUTE_STAT_PARSE;
       }

       obj = json_object_get(root, REPUTE_XML_ASSERTION);
       if (obj != NULL && json_is_string(obj) &&
           strcasecmp(json_string_value(obj), REPUTE_ASSERT_SPAM) == 0)
              found_spam = TRUE;

       obj = json_object_get(exts, REPUTE_EXT_ID);
       if (obj != NULL && json_is_string(obj) &&
           strcasecmp(json_string_value(obj), REPUTE_EXT_ID_DKIM) == 0)
              found_dkim = TRUE;

       obj = json_object_get(exts, REPUTE_EXT_RATE);
       if (obj != NULL && json_is_number(obj))
              limittmp = (unsigned long) json_integer_value(obj);

       obj = json_object_get(root, REPUTE_XML_RATER_AUTH);
       if (obj != NULL && json_is_number(obj))
              conftmp = (float) json_real_value(obj);

       obj = json_object_get(root, REPUTE_XML_RATING);
       if (obj != NULL && json_is_number(obj))
              reptmp = (float) json_real_value(obj);

       obj = json_object_get(root, REPUTE_XML_SAMPLE_SIZE);
       if (obj != NULL && json_is_number(obj))
              sampletmp = (unsigned long) json_integer_value(obj);

       obj = json_object_get(root, REPUTE_XML_UPDATED);
       if (obj != NULL && json_is_number(obj))
              whentmp = (time_t) json_integer_value(obj);

       if (found_dkim && found_spam)
       {
              *rep = reptmp;
              if (conf != NULL)
                     *conf = conftmp;
              if (sample != NULL)
                     *sample = sampletmp;
              if (when != NULL)
                     *when = whentmp;
              if (limit != NULL)
                     *limit = limittmp;
       }
#endif /* USE_JANSSON */

#ifdef USE_XML2
       doc = xmlParseMemory(buf, buflen);
       if (doc == NULL)
              return REPUTE_STAT_PARSE;

       node = xmlDocGetRootElement(doc);
       if (node == NULL)
       {
              xmlFreeDoc(doc);
              return REPUTE_STAT_PARSE;
       }

       /* confirm root's name */
       if (node->name == NULL ||
           strcasecmp(node->name, REPUTE_NAME_REPUTATION) != 0 ||
           node->children == NULL)
       {
              xmlFreeDoc(doc);
              return REPUTE_STAT_PARSE;
       }

       /* iterate through nodes looking for a reputon */
       for (node = node->children; node != NULL; node = node->next)
       {
              /* skip unnamed things or things that aren't reputons */
              if (node->name == NULL ||
                  node->type != XML_ELEMENT_NODE ||
                  strcasecmp(node->name, REPUTE_NAME_REPUTON) != 0 ||
                  node->children == NULL)
                     continue;

              found_dkim = FALSE;
              found_spam = FALSE;
              conftmp = 0.;
              reptmp = 0.;
              sampletmp = 0L;
              limittmp = ULONG_MAX;
              whentmp = 0;

              for (reputon = node->children;
                   reputon != NULL;
                   reputon = reputon->next)
              {
                     /* look for the reputon */
                     if (reputon->name == NULL ||
                         reputon->type != XML_ELEMENT_NODE ||
                         reputon->children == NULL ||
                         reputon->children->content == NULL)
                            continue;

                     /* skip unknown names */
                     code = repute_name_to_code(repute_lookup_elements,
                                                reputon->name);
                     if (code == -1)
                            continue;

                     switch (code)
                     {
                       case REPUTE_XML_CODE_RATER:
                            /*
                            **  We assume for now that we got an answer
                            **  from the same place we asked.
                            */

                            break;

                       case REPUTE_XML_CODE_RATER_AUTH:
                            conftmp = strtof(reputon->children->content,
                                             &p);
                            if (*p != '\0' || conftmp < 0 || conftmp > 1)
                                   continue;

                       case REPUTE_XML_CODE_ASSERTION:
                            if (strcasecmp(reputon->children->content,
                                           REPUTE_ASSERT_SPAM) == 0)
                                   found_spam = TRUE;
                            break;

                       case REPUTE_XML_CODE_EXTENSION:
                            if (strcasecmp(reputon->children->content,
                                           REPUTE_EXT_ID_BOTH) == 0)
                            {
                                   found_dkim = TRUE;
                            }
                            else if (strncasecmp(reputon->children->content,
                                                 REPUTE_EXT_RATE_COLON,
                                                 sizeof REPUTE_EXT_RATE_COLON - 1) == 0)
                            {
                                   errno = 0;
                                   limittmp = strtoul(reputon->children->content + sizeof REPUTE_EXT_RATE_COLON,
                                                       &p, 10);
                                   if (errno != 0)
                                          continue;
                            }
                            break;

                       case REPUTE_XML_CODE_RATED:
                            /*
                            **  We assume for now that we got an answer
                            **  to the right question.
                            */

                            break;

                       case REPUTE_XML_CODE_RATING:
                            reptmp = strtof(reputon->children->content,
                                            &p);
                            if (*p != '\0' || reptmp < -1 || reptmp > 1)
                                   continue;
                            break;

                       case REPUTE_XML_CODE_SAMPLE_SIZE:
                            errno = 0;
                            sampletmp = strtoul(reputon->children->content,
                                                &p, 10);
                            if (errno != 0)
                                   continue;
                            break;

                       case REPUTE_XML_CODE_UPDATED:
                            errno = 0;
                            whentmp = strtoul(reputon->children->content,
                                              &p, 10);
                            if (errno != 0)
                                   continue;
                            break;

                       default:
                            break;
                     }
              }

              if (found_dkim && found_spam)
              {
                     *rep = reptmp;
                     if (conf != NULL)
                            *conf = conftmp;
                     if (sample != NULL)
                            *sample = sampletmp;
                     if (when != NULL)
                            *when = whentmp;
                     if (limit != NULL)
                            *limit = limittmp;

                     break;
              }
       }

       xmlFreeDoc(doc);
#endif /* USE_XML2 */

       return REPUTE_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void repute_put_io ( REPUTE  rep,
struct repute_io rio 
) [static]

Definition at line 567 of file repute.c.

{
       assert(rep != NULL);
       assert(rio != NULL);

       pthread_mutex_lock(&rep->rep_lock);

       rio->repute_next = rep->rep_ios;
       rep->rep_ios = rio;

       pthread_mutex_unlock(&rep->rep_lock);
}

Here is the caller graph for this function:

REPUTE_STAT repute_query ( REPUTE  rep,
const char *  domain,
float *  repout,
float *  confout,
unsigned long *  sampout,
unsigned long *  limitout,
time_t *  whenout 
)

Definition at line 909 of file repute.c.

{
       REPUTE_STAT status;
       float conf;
       float reputation;
       unsigned long samples;
       unsigned long limit;
       time_t when;
       struct repute_io *rio;
       URITEMP ut;
       char genurl[REPUTE_URL];
       char template[REPUTE_URL];

       assert(rep != NULL);
       assert(domain != NULL);
       assert(repout != NULL);

       if (rep->rep_uritemp[0] == '\0')
       {
              if (repute_get_template(rep) != REPUTE_STAT_OK)
                     return REPUTE_STAT_QUERY;
       }

       ut = ut_init();
       if (ut == NULL)
              return REPUTE_STAT_INTERNAL;

       if (rep->rep_reporter != 0)
       {
              snprintf(genurl, sizeof genurl, "%u", rep->rep_reporter);
              if (ut_keyvalue(ut, UT_KEYTYPE_STRING,
                              "reporter", genurl) != 0)
              {
                     ut_destroy(ut);
                     return REPUTE_STAT_INTERNAL;
              }
       }

       if (ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "subject", (void *) domain) != 0 ||
#ifdef USE_JANSSON
           ut_keyvalue(ut, UT_KEYTYPE_STRING, "format", "json") != 0 ||
#endif /* USE_JANSSON */
#ifdef USE_XML2
           ut_keyvalue(ut, UT_KEYTYPE_STRING, "format", "xml") != 0 ||
#endif /* USE_XML2 */
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "scheme", REPUTE_URI_SCHEME) != 0 ||
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "service", (void *) rep->rep_server) != 0 ||
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "application", REPUTE_URI_APPLICATION) != 0 ||
           ut_keyvalue(ut, UT_KEYTYPE_STRING,
                       "assertion", REPUTE_ASSERT_SPAM) != 0)
       {
              ut_destroy(ut);
              return REPUTE_STAT_INTERNAL;
       }

       if (ut_generate(ut, rep->rep_uritemp, genurl, sizeof genurl) <= 0)
       {
              ut_destroy(ut);
              return REPUTE_STAT_INTERNAL;
       }

       ut_destroy(ut);

       rio = repute_get_io(rep);
       if (rio == NULL)
              return REPUTE_STAT_INTERNAL;

       status = repute_doquery(rio, genurl);
       if (status != REPUTE_STAT_OK)
       {
              repute_get_error(rio, rep->rep_error, sizeof rep->rep_error);
              repute_put_io(rep, rio);
              return status;
       }

       status = repute_parse(rio->repute_buf, rio->repute_offset,
                             &reputation, &conf, &samples, &limit, &when);
       if (status != REPUTE_STAT_OK)
       {
              snprintf(rep->rep_error, sizeof rep->rep_error,
                       "error parsing reply");
              repute_put_io(rep, rio);
              return status;
       }

       *repout = reputation;
       if (confout != NULL)
              *confout = conf;
       if (sampout != NULL)
              *sampout = samples;
       if (whenout != NULL)
              *whenout = when;
       if (limitout != NULL)
              *limitout = limit;

       repute_put_io(rep, rio);

       return REPUTE_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void repute_useragent ( REPUTE  rep,
const char *  ua 
)

Definition at line 884 of file repute.c.

{
       if (rep->rep_useragent != NULL)
              free((void *) rep->rep_useragent);

       rep->rep_useragent = strdup(ua);
}

Here is the caller graph for this function:


Variable Documentation

char repute_c_id[] = "$Id$" [static]

Definition at line 6 of file repute.c.