Files
znc/include/znc/Utils.h
T
Uli Schlachter 62328b2c96 CSmartPtr: Remove, superseded by std::shared_ptr
Signed-off-by: Uli Schlachter <psychon@znc.in>
2014-09-12 15:25:57 +02:00

358 lines
10 KiB
C++

/*
* Copyright (C) 2004-2014 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _UTILS_H
#define _UTILS_H
#include <znc/zncconfig.h>
#include <znc/ZNCString.h>
#include <assert.h>
#include <cstdio>
#include <fcntl.h>
#include <map>
#include <sys/file.h>
#include <sys/time.h>
#include <unistd.h>
#include <vector>
static inline void SetFdCloseOnExec(int fd)
{
int flags = fcntl(fd, F_GETFD, 0);
if (flags < 0)
return; // Ignore errors
// When we execve() a new process this fd is now automatically closed.
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}
static const char g_HexDigits[] = "0123456789abcdef";
class CUtils {
public:
CUtils();
~CUtils();
static CString GetIP(unsigned long addr);
static unsigned long GetLongIP(const CString& sIP);
static void PrintError(const CString& sMessage);
static void PrintMessage(const CString& sMessage, bool bStrong = false);
static void PrintPrompt(const CString& sMessage);
static void PrintAction(const CString& sMessage);
static void PrintStatus(bool bSuccess, const CString& sMessage = "");
#ifndef SWIGPERL
// TODO refactor this
static const CString sDefaultHash;
#endif
static CString GetSaltedHashPass(CString& sSalt);
static CString GetSalt();
static CString SaltedMD5Hash(const CString& sPass, const CString& sSalt);
static CString SaltedSHA256Hash(const CString& sPass, const CString& sSalt);
static CString GetPass(const CString& sPrompt);
static bool GetInput(const CString& sPrompt, CString& sRet, const CString& sDefault = "", const CString& sHint = "");
static bool GetBoolInput(const CString& sPrompt, bool bDefault);
static bool GetBoolInput(const CString& sPrompt, bool *pbDefault = NULL);
static bool GetNumInput(const CString& sPrompt, unsigned int& uRet, unsigned int uMin = 0, unsigned int uMax = ~0, unsigned int uDefault = ~0);
static unsigned long long GetMillTime() {
struct timeval tv;
unsigned long long iTime = 0;
gettimeofday(&tv, NULL);
iTime = (unsigned long long) tv.tv_sec * 1000;
iTime += ((unsigned long long) tv.tv_usec / 1000);
return iTime;
}
#ifdef HAVE_LIBSSL
static void GenerateCert(FILE *pOut, const CString& sHost = "");
#endif /* HAVE_LIBSSL */
static CString CTime(time_t t, const CString& sTZ);
static CString FormatTime(time_t t, const CString& sFormat, const CString& sTZ);
static CString FormatServerTime(const timeval& tv);
static SCString GetTimezones();
static MCString GetMessageTags(const CString& sLine);
static void SetMessageTags(CString& sLine, const MCString& mssTags);
private:
protected:
};
class CException {
public:
typedef enum {
EX_Shutdown,
EX_Restart
} EType;
CException(EType e) {
m_eType = e;
}
virtual ~CException() {}
EType GetType() const { return m_eType; }
private:
protected:
EType m_eType;
};
/** Generate a grid-like output from a given input.
*
* @code
* CTable table;
* table.AddColumn("a");
* table.AddColumn("b");
* table.AddRow();
* table.SetCell("a", "hello");
* table.SetCell("b", "world");
*
* unsigned int idx = 0;
* CString tmp;
* while (table.GetLine(idx++, tmp)) {
* // Output tmp somehow
* }
* @endcode
*
* The above code would generate the following output:
* @verbatim
+-------+-------+
| a | b |
+-------+-------+
| hello | world |
+-------+-------+@endverbatim
*/
class CTable : protected std::vector<std::vector<CString> > {
public:
CTable() {}
virtual ~CTable() {}
/** Adds a new column to the table.
* Please note that you should add all columns before starting to fill
* the table!
* @param sName The name of the column.
* @return false if a column by that name already existed.
*/
bool AddColumn(const CString& sName);
/** Adds a new row to the table.
* After calling this you can fill the row with content.
* @return The index of this row
*/
size_type AddRow();
/** Sets a given cell in the table to a value.
* @param sColumn The name of the column you want to fill.
* @param sValue The value to write into that column.
* @param uRowIdx The index of the row to use as returned by AddRow().
* If this is not given, the last row will be used.
* @return True if setting the cell was successful.
*/
bool SetCell(const CString& sColumn, const CString& sValue, size_type uRowIdx = ~0);
/** Get a line of the table's output
* @param uIdx The index of the line you want.
* @param sLine This string will receive the output.
* @return True unless uIdx is past the end of the table.
*/
bool GetLine(unsigned int uIdx, CString& sLine) const;
/** Return the width of the given column.
* Please note that adding and filling new rows might change the
* result of this function!
* @param uIdx The index of the column you are interested in.
* @return The width of the column.
*/
CString::size_type GetColumnWidth(unsigned int uIdx) const;
/// Completely clear the table.
void Clear();
/// @return The number of rows in this table, not counting the header.
using std::vector<std::vector<CString> >::size;
/// @return True if this table doesn't contain any rows.
using std::vector<std::vector<CString> >::empty;
private:
unsigned int GetColumnIndex(const CString& sName) const;
protected:
std::vector<CString> m_vsHeaders;
std::map<CString, CString::size_type> m_msuWidths; // Used to cache the width of a column
};
#ifdef HAVE_LIBSSL
#include <openssl/aes.h>
#include <openssl/blowfish.h>
#include <openssl/md5.h>
//! does Blowfish w/64 bit feedback, no padding
class CBlowfish {
public:
/**
* @param sPassword key to encrypt with
* @param iEncrypt encrypt method (BF_DECRYPT or BF_ENCRYPT)
* @param sIvec what to set the ivector to start with, default sets it all 0's
*/
CBlowfish(const CString & sPassword, int iEncrypt, const CString & sIvec = "");
~CBlowfish();
//! output must be freed
static unsigned char *MD5(const unsigned char *input, u_int ilen);
//! returns an md5 of the CString (not hex encoded)
static CString MD5(const CString & sInput, bool bHexEncode = false);
//! output must be the same size as input
void Crypt(unsigned char *input, unsigned char *output, u_int ibytes);
//! must free result
unsigned char * Crypt(unsigned char *input, u_int ibytes);
CString Crypt(const CString & sData);
private:
unsigned char *m_ivec;
BF_KEY m_bkey;
int m_iEncrypt, m_num;
};
#endif /* HAVE_LIBSSL */
/**
* @class TCacheMap
* @author prozac <prozac@rottenboy.com>
* @brief Insert an object with a time-to-live and check later if it still exists
*/
template<typename K, typename V = bool>
class TCacheMap {
public:
TCacheMap(unsigned int uTTL = 5000) {
m_uTTL = uTTL;
}
virtual ~TCacheMap() {}
/**
* @brief This function adds an item to the cache using the default time-to-live value
* @param Item the item to add to the cache
*/
void AddItem(const K& Item) {
AddItem(Item, m_uTTL);
}
/**
* @brief This function adds an item to the cache using a custom time-to-live value
* @param Item the item to add to the cache
* @param uTTL the time-to-live for this specific item
*/
void AddItem(const K& Item, unsigned int uTTL) {
AddItem(Item, V(), uTTL);
}
/**
* @brief This function adds an item to the cache using the default time-to-live value
* @param Item the item to add to the cache
* @param Val The value associated with the key Item
*/
void AddItem(const K& Item, const V& Val) {
AddItem(Item, Val, m_uTTL);
}
/**
* @brief This function adds an item to the cache using a custom time-to-live value
* @param Item the item to add to the cache
* @param Val The value associated with the key Item
* @param uTTL the time-to-live for this specific item
*/
void AddItem(const K& Item, const V& Val, unsigned int uTTL) {
if (!uTTL) { // If time-to-live is zero we don't want to waste our time adding it
RemItem(Item); // Remove the item incase it already exists
return;
}
m_mItems[Item] = value(CUtils::GetMillTime() + uTTL, Val);
}
/**
* @brief Performs a Cleanup() and then checks to see if your item exists
* @param Item The item to check for
* @return true if item exists
*/
bool HasItem(const K& Item) {
Cleanup();
return (m_mItems.find(Item) != m_mItems.end());
}
/**
* @brief Performs a Cleanup() and returns a pointer to the object, or NULL
* @param Item The item to check for
* @return Pointer to the item or NULL if there is no suitable one
*/
V* GetItem(const K& Item) {
Cleanup();
iterator it = m_mItems.find(Item);
if (it == m_mItems.end())
return NULL;
return &it->second.second;
}
/**
* @brief Removes a specific item from the cache
* @param Item The item to be removed
* @return true if item existed and was removed, false if it never existed
*/
bool RemItem(const K& Item) {
return (m_mItems.erase(Item) != 0);
}
/**
* @brief Cycles through the queue removing all of the stale entries
*/
void Cleanup() {
iterator it = m_mItems.begin();
while (it != m_mItems.end()) {
if (CUtils::GetMillTime() > (it->second.first)) {
m_mItems.erase(it++);
} else {
++it;
}
}
}
/**
* @brief Clear all entries
*/
void Clear() {
m_mItems.clear();
}
// Setters
void SetTTL(unsigned int u) { m_uTTL = u; }
// !Setters
// Getters
unsigned int GetTTL() const { return m_uTTL; }
// !Getters
protected:
typedef std::pair<unsigned long long, V> value;
typedef typename std::map<K, value>::iterator iterator;
std::map<K, value> m_mItems; //!< Map of cached items. The value portion of the map is for the expire time
unsigned int m_uTTL; //!< Default time-to-live duration
};
#endif // !_UTILS_H