#include "policyd.h"


/*
 *
 *
 *                           Policy Daemon
 *
 *  policy daemon is used in conjuction with postfix to combat spam.
 *
 *  Copyright (C) 2004 Cami Sardinha (cami@mweb.co.za)
 *
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the  GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the License, or (at your
 *  option) any later version.
 *
 *  This program  is  distributed  in the hope that  it will be useful, but
 *  WITHOUT  WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free  Software Foundation Inc.,
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *
 */


/*
 * function: throttle_check
 *  purpose: throttle users based on SASL info or envelope FROM
 *   return: 0 for new record, 1 for update
 */
int
throttle_check (unsigned int fd)
{
  unsigned int tnum = 0;
  unsigned int tresult = 0;
  
  mysql_optarray[fd][0] = 0;

  if(DEBUG > 0)
    logmessage("DEBUG: fd: %d checking throttle\n", fd);
  
  /* build up & execute query */
  if(SENDER_THROTTLE_HOST == 1)
  {
    tnum = 1;
    snprintf(mysqlquery_array[fd], 512,
      "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
      " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
      " _log_warn, _log_panic, _abuse_tot"
      " FROM throttle WHERE _from='%s' OR _from='%s' OR _from='%s' OR _from='%s'"
      " ORDER BY _priority DESC LIMIT 1",
      host_array[fd][2], host_array[fd][3], host_array[fd][4], host_array[fd][5]);
    
  } else if((SENDER_THROTTLE_SASL == 1) && (triplet_array[fd][4][0] != 0x00))  {
    tnum = 2;
    snprintf(mysqlquery_array[fd], 512,
      "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
      " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
      " _log_warn, _log_panic, _abuse_tot"
      " FROM throttle WHERE _from='%s'", triplet_array[fd][4]);
  } else {
    tnum = 3;
    snprintf(mysqlquery_array[fd], 512,
      "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
      " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
      " _log_warn, _log_panic, _abuse_tot"
      " FROM throttle WHERE _from='%s' OR _from='@%s'"
      " ORDER BY _priority DESC LIMIT 1",
      triplet_array[fd][1], host_array[fd][7]);
  }
  if(db_charquery(fd) == -1) return(db_failure(fd, "throttle"));    
  
  /* max messages is disabled in database, fall back to config default */
  if(atol(mysqlchar_array[fd][1]) == 0)
    snprintf(mysqlchar_array[fd][1], sizeof(mysqlchar_array[fd][1]),
      "%d", SENDERMSGLIMIT);

  /* max user quota is disabled in database, fall back to config defaults */
  if(atol(mysqlchar_array[fd][5]) == 0)
    snprintf(mysqlchar_array[fd][5], sizeof(mysqlchar_array[fd][5]),
      "%d", SENDERQUOTALIMIT);
  
  /* max time limit is disabled in database, fall back to config defaults */
  if(atol(mysqlchar_array[fd][6]) == 0)
    snprintf(mysqlchar_array[fd][6], sizeof(mysqlchar_array[fd][6]),
      "%d", SENDERTIMELIMIT);

  /* max message size is disabled in database, fall back to config defaults */
  if(atol(mysqlchar_array[fd][7]) == 0)
    snprintf(mysqlchar_array[fd][7], sizeof(mysqlchar_array[fd][7]),
      "%d", SENDERMSGSIZE);

  /* max rcpt limit is disabled in database, fall back to config defaults */
  if(atol(mysqlchar_array[fd][9]) == 0)
    snprintf(mysqlchar_array[fd][9], sizeof(mysqlchar_array[fd][9]),
      "%d", SENDERRCPTLIMIT);

  /* check postfix policy instance */
  snprintf(mysqlquery_array[fd], 512,
    "SELECT COUNT(_instance) from throttle_from_instance \
       WHERE _instance='%s'", triplet_array[fd][6]); 
  if(db_optquery(fd) == -1) return(db_failure(fd, "throttle"));
  
  /* is instance recorded? */
  if(mysql_optarray[fd][0] == 0)
  {
    int expire=0;
    
    /* its not, so record it */
    if(SENDERTIMELIMIT > 0)
      expire=timenow;

    snprintf(mysqlquery_array[fd], 512,
      "INSERT DELAYED INTO throttle_from_instance (_instance,_expire) VALUES ('%s',%d)",
      triplet_array[fd][6], expire);
    if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

    instance_inc[fd] = 1;
  } else {
    instance_inc[fd] = 0;
  }

  /* prepare attributes & thresholds */
  /* count, quota, rcpt */
  tquota[fd] = atof(mysqlchar_array[fd][4]) / atof(mysqlchar_array[fd][5]) * 100;
  tcount[fd] = atof(mysqlchar_array[fd][2]) / atof(mysqlchar_array[fd][1]) * 100;
  trcpt[fd] = atof(mysqlchar_array[fd][10]) / atof(mysqlchar_array[fd][9]) * 100;
  
  /* catch wierd ones */
  if(DEBUG >= 4)
    logmessage("DEBUG: fd: %d: tquota[fd]: %d, tcount[fd]: %d, trcpt[fd]: %d\n",
       fd, tquota[fd], tcount[fd], trcpt[fd]);
  
  /* highest percentage always wins.. mmm.. ugly stuff*/
  if(tquota[fd] >= tcount[fd] && tquota[fd] >= trcpt[fd]) {
    tresult = tquota[fd];
    if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }
  
  if(tcount[fd] >= tquota[fd] && tcount[fd] >= trcpt[fd]) {
    tresult = tcount[fd];
    if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }
    
  if(trcpt[fd]  >= tcount[fd] && trcpt[fd] >= tquota[fd]) {
    tresult = trcpt[fd];
    if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }

  if(DEBUG >= 4)
    logmessage("DEBUG: fd: %d: tresult: %d\n", fd, tresult);

  /* percentage won, set attribute accordingly */
  switch (tresult)
  {
    
    case 0 ... 49:      tattrib_array[fd][0] = 'a'; break;
    case 50 ... 89:     tattrib_array[fd][0] = 'w'; break;
    case 90 ... 900000: tattrib_array[fd][0] = 'p'; break;
    /* allow for big percentage overshoot */

    default:
      logmessage("fatal: throttle_check(): invalid tresult: %d\n", tresult);
      return (-1);
  }

  /* we selectively choose which throttle module we want */
  switch(tnum)
  {
    case 1:
      return(throttle_host(fd));

    case 2:
      return(throttle_sasl(fd));

    case 3:
      return(throttle_from(fd));

    default:
      logmessage("fatal: throttle_check(): no tnum\n");
      return (-1);
  }
  
  return (0); /* never reached */
}
 
/* EOF */
