<commit_before>// kmacctpop.cpp
// Authors: <NAME> and <NAME>

#include "kmacctpop.moc"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <mimelib/mimepp.h>
#include <kmfolder.h>
#include <kmmessage.h>
#include <qtextstream.h>
#include <kconfig.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <kapp.h>

#include "kmacctpop.h"
#include "kalarmtimer.h"
#include "kmglobal.h"
#include "kbusyptr.h"
#include "kmacctfolder.h"
#include "kmfiltermgr.h"
#include <klocale.h>


//-----------------------------------------------------------------------------
KMAcctPop::KMAcctPop(KMAcctMgr* aOwner, const char* aAccountName):
  KMAcctPopInherited(aOwner, aAccountName)
{
  initMetaObject();

  mStorePasswd = FALSE;
  mLeaveOnServer = FALSE;
  mRetrieveAll = TRUE;
  mProtocol = 3;
  mPort = 110;
}


//-----------------------------------------------------------------------------
KMAcctPop::~KMAcctPop()
{
}


//-----------------------------------------------------------------------------
const char* KMAcctPop::type(void) const
{
  return "pop";
}


//-----------------------------------------------------------------------------
void KMAcctPop::init(void)
{
  mHost   = "";
  mPort   = 110;
  mLogin  = "";
  mPasswd = "";
  mProtocol = 3;
  mStorePasswd = FALSE;
  mLeaveOnServer = FALSE;
  mRetrieveAll = TRUE;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::processNewMail(KMIOStatus *wid)
{
  void (*oldHandler)(int);
  void (*pipeHandler)(int);
  bool result;

  // Before we do anything else let's ignore the friggin' SIGALRM signal
  // This signal somehow interrupts the network functions and messed up
  // DwPopClient::Open().
  oldHandler = signal(SIGALRM, SIG_IGN);
  // Another one of those nice little SIGNALS which default action is to 
  // abort the app when received. SIGPIPE is send when e.g the client attempts
  // to write to a TCP socket when the connection was shutdown by the server.
  pipeHandler = signal(SIGPIPE, SIG_IGN);
  result = doProcessNewMail(wid);
  signal(SIGALRM, oldHandler);
  signal(SIGPIPE, pipeHandler);
  return result;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::authenticate(DwPopClient& client)
{
  QString passwd;
  const char* msg=0;
  KMPasswdDialog* dlg;
  bool opened = FALSE;
  int replyCode;

  if(mPasswd.isEmpty() || mLogin.isEmpty())
    msg = i18n("Please set Password and Username");

  passwd = <PASSWORD>(mPasswd);
  

  while (1)
  {
    if (msg)
    {
      dlg = new KMPasswdDialog(NULL, NULL, this, msg,
			       mLogin, passwd);
      if (!dlg->exec()) return FALSE;
      delete dlg;
      msg = 0;
    }

    // Some POP servers close the connection upon failed
    // user/password. So we close the connection here to
    // be sure that everything below runs as we expect it.
    if (opened)
    {
      client.Quit();
      client.Close();
    }
      
    // Open connection to server
    if (client.Open(mHost,mPort) != '+')
      return popError("OPEN", client);
    opened = TRUE;
    app->processEvents();

    // Send user name
    replyCode = client.User((const char*)mLogin);
    if (replyCode == '-')
    {
      msg = i18n("Incorrect Username");
      continue;
    }
    else if (replyCode != '+')
      return popError("USER", client);
    app->processEvents();

    // Send password
    passwd = <PASSWORD>Str(mPasswd);
    
    replyCode = client.Pass((const char*)passwd);
    if (replyCode == '-')
    {
      msg = i18n("Incorrect Password");
      continue;
    }
    else if (replyCode != '+')
      return popError("PASS", client);

    // Ok, we are done
    break;
  }

  return TRUE;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::doProcessNewMail(KMIOStatus *wid)
{
  DwPopClient client;
  QString passwd;
  QString response, status;
  int num, size;	// number of all msgs / size of all msgs
  int id, i;		// id of message to read
  int dummy;
  char dummyStr[32];
  // int replyCode; // ReplyCode need from User & Passwd call.
  KMMessage* msg;
  gotMsgs = FALSE;
  bool doFetchMsg;

  wid->prepareTransmission(host(), KMIOStatus::RETRIEVE);

  // is everything specified ?
  app->processEvents();

  if (mHost.isEmpty() || mPort<=0)
  {
    warning(i18n("Please specify Host, Port  and\n"
		 "destination folder in the settings\n"
		 "and try again."));
    return FALSE;
  }

  client.SetReceiveTimeout(20);

  // Handle connect, user, and password.
  if (!authenticate(client)) return FALSE;

  if (client.Stat() != '+') return popError("STAT", client);
  response = client.SingleLineResponse().c_str();
  sscanf(response.data(), "%3s %d %d", dummyStr, &num, &size);

//#warning "*** If client.Last() cannot be found then install the latest kdesupport"
  if (client.Last() == '+' && !mRetrieveAll)
  {
    response = client.SingleLineResponse().c_str();
    sscanf(response.data(), "%3s %d", dummyStr, &id);
    id++;
  }
  else id = 1;

  // workaround but still is no good. If msgs are too big in size
  // we will get a timeout.
  client.SetReceiveTimeout(40);
	
  while (id <= num)
  {
    if(wid->abortRequested()) {
      client.Quit();
      return gotMsgs;
    }
    wid->updateProgressBar(id,num);
    app->processEvents();
    if (client.List(id) != '+')
      return popError("LIST", client);
    response = client.SingleLineResponse().c_str();
    sscanf(response.data(), "%3s %d %d", dummyStr, &dummy, &size);

    doFetchMsg = TRUE;
    if (size > 4500 && !mRetrieveAll)
    {
      // If the message is large it is cheaper to first load
      // the header to check the status of the message.
      // We will have to load the entire message with the RETR
      // command below, so we will not fetch the header for
      // small messages.
      if (client.Top(id,1) != '+')
	return popError("TOP", client);
      response = client.MultiLineResponse().c_str();
      i = response.find("\nStatus:");
      if (i<0) i = response.find("\rStatus:");
      if (i>=0)
      {
	status = response.mid(i+8,32).stripWhiteSpace();
	if (strnicmp(status,"RO",2)==0 ||
	    strnicmp(status,"OR",2)==0)
	{
	  doFetchMsg=FALSE;
	  debug("message %d is old -- no need to download it", id);
	}
      }
    }

    if (doFetchMsg)
    {
      if (client.Retr(id) != '+')
	return popError("RETR", client);
      response = client.MultiLineResponse().c_str();

      msg = new KMMessage;
      msg->fromString(response,TRUE);
      if (mRetrieveAll || msg->status()!=KMMsgStatusOld)
	processNewMsg(msg);
      else delete msg;
    }

    if(!mLeaveOnServer)
    {
      if(client.Dele(id) != '+')
	return popError("DELE",client);
      else 
	cout << client.SingleLineResponse().c_str();
    }

    gotMsgs = TRUE;
    id++;
  }
  wid->transmissionCompleted();
  client.Quit();
  return gotMsgs;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::popError(const QString aStage, DwPopClient& aClient) const
{
  QString msg, caption;
  kbp->idle();

  caption = i18n("Pop Mail Error");

  // First we assume the worst: A network error
  if (aClient.LastFailure() != DwProtocolClient::kFailNoFailure)
  {
    caption = i18n("Pop Mail Network Error");
    msg = aClient.LastFailureStr();
  }

  // Maybe it is an app specific error
  else if (aClient.LastError() != DwProtocolClient::kErrNoError)
  {
    msg = aClient.LastErrorStr();
  }
  
  // Not all commands return multiLineResponses. If they do not
  // they return singleLineResponses and the multiLR command return NULL
  else
  {
    msg = aClient.MultiLineResponse().c_str();
    if (msg.isEmpty()) msg = aClient.SingleLineResponse().c_str();
    if (msg.isEmpty()) msg = i18n("Unknown error");
    // Negative response by the server e.g STAT responses '- ....'
  }

  QString tmp;
  tmp.sprintf(i18n("Account: %s\nIn %s:\n%s"), name().data(), 
	      aStage.data(),msg.data());
  KMsgBox::message(0, caption, tmp);
  //kbp->busy();
  aClient.Quit();
  return gotMsgs;
}


//-----------------------------------------------------------------------------
void KMAcctPop::readConfig(KConfig& config)
{
  KMAcctPopInherited::readConfig(config);


  mLogin = config.readEntry("login", "");
  mStorePasswd = config.readNumEntry("store-passwd", TRUE);
  if (mStorePasswd) mPasswd = config.readEntry("passwd");
  else mPasswd = "";
  mHost = config.readEntry("host");
  mPort = config.readNumEntry("port");
  mProtocol = config.readNumEntry("protocol");
  mLeaveOnServer = config.readNumEntry("leave-on-server", FALSE);
  mRetrieveAll = config.readNumEntry("retrieve-all", FALSE);
}


//-----------------------------------------------------------------------------
void KMAcctPop::writeConfig(KConfig& config)
{
  KMAcctPopInherited::writeConfig(config);

  config.writeEntry("login", mLogin);
  config.writeEntry("store-passwd", mStorePasswd);
  if (mStorePasswd) config.writeEntry("passwd", mPasswd);
  else config.writeEntry("passwd", "");

  config.writeEntry("host", mHost);
  config.writeEntry("port", mPort);
  config.writeEntry("protocol", mProtocol);
  config.writeEntry("leave-on-server", mLeaveOnServer);
  config.writeEntry("retrieve-all", mRetrieveAll);
}


//-----------------------------------------------------------------------------
const QString KMAcctPop::encryptStr(const QString aStr)
{
  unsigned int i, val;
  unsigned int len = aStr.length();
  QCString result;
  result.resize(len+1);

  for (i=0; i<len; i++)
  {
    val = aStr[i] - ' ';
    val = (255-' ') - val;
    result[i] = (char)(val + ' ');
  }
  result[i] = '\0';

  return result;
}


//-----------------------------------------------------------------------------
const QString KMAcctPop::decryptStr(const QString aStr)
{
  return encryptStr(aStr);
}


//-----------------------------------------------------------------------------<commit_msg>encryptStr(const QString aStr) uses ASCII representation. Adding a QString::ascii() conversion<commit_after>// kmacctpop.cpp
// Authors: <NAME> and <NAME>

#include "kmacctpop.moc"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <mimelib/mimepp.h>
#include <kmfolder.h>
#include <kmmessage.h>
#include <qtextstream.h>
#include <kconfig.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <kapp.h>

#include "kmacctpop.h"
#include "kalarmtimer.h"
#include "kmglobal.h"
#include "kbusyptr.h"
#include "kmacctfolder.h"
#include "kmfiltermgr.h"
#include <klocale.h>


//-----------------------------------------------------------------------------
KMAcctPop::KMAcctPop(KMAcctMgr* aOwner, const char* aAccountName):
  KMAcctPopInherited(aOwner, aAccountName)
{
  initMetaObject();

  mStorePasswd = FALSE;
  mLeaveOnServer = FALSE;
  mRetrieveAll = TRUE;
  mProtocol = 3;
  mPort = 110;
}


//-----------------------------------------------------------------------------
KMAcctPop::~KMAcctPop()
{
}


//-----------------------------------------------------------------------------
const char* KMAcctPop::type(void) const
{
  return "pop";
}


//-----------------------------------------------------------------------------
void KMAcctPop::init(void)
{
  mHost   = "";
  mPort   = 110;
  mLogin  = "";
  mPasswd = "";
  mProtocol = 3;
  mStorePasswd = FALSE;
  mLeaveOnServer = FALSE;
  mRetrieveAll = TRUE;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::processNewMail(KMIOStatus *wid)
{
  void (*oldHandler)(int);
  void (*pipeHandler)(int);
  bool result;

  // Before we do anything else let's ignore the friggin' SIGALRM signal
  // This signal somehow interrupts the network functions and messed up
  // DwPopClient::Open().
  oldHandler = signal(SIGALRM, SIG_IGN);
  // Another one of those nice little SIGNALS which default action is to 
  // abort the app when received. SIGPIPE is send when e.g the client attempts
  // to write to a TCP socket when the connection was shutdown by the server.
  pipeHandler = signal(SIGPIPE, SIG_IGN);
  result = doProcessNewMail(wid);
  signal(SIGALRM, oldHandler);
  signal(SIGPIPE, pipeHandler);
  return result;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::authenticate(DwPopClient& client)
{
  QString passwd;
  const char* msg=0;
  KMPasswdDialog* dlg;
  bool opened = FALSE;
  int replyCode;

  if(mPasswd.isEmpty() || mLogin.isEmpty())
    msg = i18n("Please set Password and Username");

  passwd = decryptStr(mPasswd);
  

  while (1)
  {
    if (msg)
    {
      dlg = new KMPasswdDialog(NULL, NULL, this, msg,
			       mLogin, passwd);
      if (!dlg->exec()) return FALSE;
      delete dlg;
      msg = 0;
    }

    // Some POP servers close the connection upon failed
    // user/password. So we close the connection here to
    // be sure that everything below runs as we expect it.
    if (opened)
    {
      client.Quit();
      client.Close();
    }
      
    // Open connection to server
    if (client.Open(mHost,mPort) != '+')
      return popError("OPEN", client);
    opened = TRUE;
    app->processEvents();

    // Send user name
    replyCode = client.User((const char*)mLogin);
    if (replyCode == '-')
    {
      msg = i18n("Incorrect Username");
      continue;
    }
    else if (replyCode != '+')
      return popError("USER", client);
    app->processEvents();

    // Send password
    passwd = <PASSWORD>Str(mPasswd);
    
    replyCode = client.Pass((const char*)passwd);
    if (replyCode == '-')
    {
      msg = i18n("Incorrect Password");
      continue;
    }
    else if (replyCode != '+')
      return popError("PASS", client);

    // Ok, we are done
    break;
  }

  return TRUE;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::doProcessNewMail(KMIOStatus *wid)
{
  DwPopClient client;
  QString passwd;
  QString response, status;
  int num, size;	// number of all msgs / size of all msgs
  int id, i;		// id of message to read
  int dummy;
  char dummyStr[32];
  // int replyCode; // ReplyCode need from User & Passwd call.
  KMMessage* msg;
  gotMsgs = FALSE;
  bool doFetchMsg;

  wid->prepareTransmission(host(), KMIOStatus::RETRIEVE);

  // is everything specified ?
  app->processEvents();

  if (mHost.isEmpty() || mPort<=0)
  {
    warning(i18n("Please specify Host, Port  and\n"
		 "destination folder in the settings\n"
		 "and try again."));
    return FALSE;
  }

  client.SetReceiveTimeout(20);

  // Handle connect, user, and password.
  if (!authenticate(client)) return FALSE;

  if (client.Stat() != '+') return popError("STAT", client);
  response = client.SingleLineResponse().c_str();
  sscanf(response.data(), "%3s %d %d", dummyStr, &num, &size);

//#warning "*** If client.Last() cannot be found then install the latest kdesupport"
  if (client.Last() == '+' && !mRetrieveAll)
  {
    response = client.SingleLineResponse().c_str();
    sscanf(response.data(), "%3s %d", dummyStr, &id);
    id++;
  }
  else id = 1;

  // workaround but still is no good. If msgs are too big in size
  // we will get a timeout.
  client.SetReceiveTimeout(40);
	
  while (id <= num)
  {
    if(wid->abortRequested()) {
      client.Quit();
      return gotMsgs;
    }
    wid->updateProgressBar(id,num);
    app->processEvents();
    if (client.List(id) != '+')
      return popError("LIST", client);
    response = client.SingleLineResponse().c_str();
    sscanf(response.data(), "%3s %d %d", dummyStr, &dummy, &size);

    doFetchMsg = TRUE;
    if (size > 4500 && !mRetrieveAll)
    {
      // If the message is large it is cheaper to first load
      // the header to check the status of the message.
      // We will have to load the entire message with the RETR
      // command below, so we will not fetch the header for
      // small messages.
      if (client.Top(id,1) != '+')
	return popError("TOP", client);
      response = client.MultiLineResponse().c_str();
      i = response.find("\nStatus:");
      if (i<0) i = response.find("\rStatus:");
      if (i>=0)
      {
	status = response.mid(i+8,32).stripWhiteSpace();
	if (strnicmp(status,"RO",2)==0 ||
	    strnicmp(status,"OR",2)==0)
	{
	  doFetchMsg=FALSE;
	  debug("message %d is old -- no need to download it", id);
	}
      }
    }

    if (doFetchMsg)
    {
      if (client.Retr(id) != '+')
	return popError("RETR", client);
      response = client.MultiLineResponse().c_str();

      msg = new KMMessage;
      msg->fromString(response,TRUE);
      if (mRetrieveAll || msg->status()!=KMMsgStatusOld)
	processNewMsg(msg);
      else delete msg;
    }

    if(!mLeaveOnServer)
    {
      if(client.Dele(id) != '+')
	return popError("DELE",client);
      else 
	cout << client.SingleLineResponse().c_str();
    }

    gotMsgs = TRUE;
    id++;
  }
  wid->transmissionCompleted();
  client.Quit();
  return gotMsgs;
}


//-----------------------------------------------------------------------------
bool KMAcctPop::popError(const QString aStage, DwPopClient& aClient) const
{
  QString msg, caption;
  kbp->idle();

  caption = i18n("Pop Mail Error");

  // First we assume the worst: A network error
  if (aClient.LastFailure() != DwProtocolClient::kFailNoFailure)
  {
    caption = i18n("Pop Mail Network Error");
    msg = aClient.LastFailureStr();
  }

  // Maybe it is an app specific error
  else if (aClient.LastError() != DwProtocolClient::kErrNoError)
  {
    msg = aClient.LastErrorStr();
  }
  
  // Not all commands return multiLineResponses. If they do not
  // they return singleLineResponses and the multiLR command return NULL
  else
  {
    msg = aClient.MultiLineResponse().c_str();
    if (msg.isEmpty()) msg = aClient.SingleLineResponse().c_str();
    if (msg.isEmpty()) msg = i18n("Unknown error");
    // Negative response by the server e.g STAT responses '- ....'
  }

  QString tmp;
  tmp.sprintf(i18n("Account: %s\nIn %s:\n%s"), name().data(), 
	      aStage.data(),msg.data());
  KMsgBox::message(0, caption, tmp);
  //kbp->busy();
  aClient.Quit();
  return gotMsgs;
}


//-----------------------------------------------------------------------------
void KMAcctPop::readConfig(KConfig& config)
{
  KMAcctPopInherited::readConfig(config);


  mLogin = config.readEntry("login", "");
  mStorePasswd = config.readNumEntry("store-passwd", TRUE);
  if (mStorePasswd) mPasswd = config.readEntry("passwd");
  else mPasswd = "";
  mHost = config.readEntry("host");
  mPort = config.readNumEntry("port");
  mProtocol = config.readNumEntry("protocol");
  mLeaveOnServer = config.readNumEntry("leave-on-server", FALSE);
  mRetrieveAll = config.readNumEntry("retrieve-all", FALSE);
}


//-----------------------------------------------------------------------------
void KMAcctPop::writeConfig(KConfig& config)
{
  KMAcctPopInherited::writeConfig(config);

  config.writeEntry("login", mLogin);
  config.writeEntry("store-passwd", mStorePasswd);
  if (mStorePasswd) config.writeEntry("passwd", <PASSWORD>);
  else config.writeEntry("passwd", "");

  config.writeEntry("host", mHost);
  config.writeEntry("port", mPort);
  config.writeEntry("protocol", mProtocol);
  config.writeEntry("leave-on-server", mLeaveOnServer);
  config.writeEntry("retrieve-all", mRetrieveAll);
}


//-----------------------------------------------------------------------------
const QString KMAcctPop::encryptStr(const QString aStr)
{
  unsigned int i, val;
  unsigned int len = aStr.length();
  const char* asciiStr = aStr.ascii();
  QCString result;
  result.resize(len+1);

  for (i=0; i<len; i++)
  {
    val = asciiStr[i] - ' ';
    val = (255-' ') - val;
    result[i] = (char)(val + ' ');
  }
  result[i] = '\0';

  return result;
}


//-----------------------------------------------------------------------------
const QString KMAcctPop::decryptStr(const QString aStr)
{
  return encryptStr(aStr);
}


//-----------------------------------------------------------------------------
{'fraction_non_alphanumeric': 0.23563247136497775, 'fraction_numerical': 0.005902065723003051, 'mean_word_length': 2.21602058870838, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '724594', 'n_tokens_mistral': 6475, 'n_tokens_neox': 6247, 'n_words': 1545}