%PDF- %PDF-
| Direktori : /data/old/usr/local/include/znc/ |
| Current File : //data/old/usr/local/include/znc/Utils.h |
/*
* Copyright (C) 2004-2018 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 ZNC_UTILS_H
#define ZNC_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 = nullptr);
static bool GetNumInput(const CString& sPrompt, unsigned int& uRet,
unsigned int uMin = 0, unsigned int uMax = ~0,
unsigned int uDefault = ~0);
static timeval GetTime();
static unsigned long long GetMillTime();
#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);
/** Supports an additional format specifier for formatting sub-second values:
*
* - %f - sub-second fraction
* - %3f - millisecond (default, if no width is specified)
* - %6f - microsecond
*
* However, note that timeval only supports microsecond precision
* (thus, formatting with higher-than-microsecond precision will
* always result in trailing zeroes), and IRC server-time is specified
* in millisecond precision (thus formatting received timestamps with
* higher-than-millisecond precision will always result in trailing
* zeroes).
*/
static CString FormatTime(const timeval& tv, const CString& sFormat,
const CString& sTZ);
static CString FormatServerTime(const timeval& tv);
static timeval ParseServerTime(const CString& sTime);
static SCString GetTimezones();
static SCString GetEncodings();
/** CIDR notation checker, e.g. "192.0.2.0/24" or "2001:db8::/32"
*
* For historical reasons also allows wildcards, e.g. "192.168.*"
*/
static bool CheckCIDR(const CString& sIP, const CString& sRange);
/// @deprecated Use CMessage instead
static MCString GetMessageTags(const CString& sLine);
/// @deprecated Use CMessage instead
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;
// Used to cache the width of a column
std::map<CString, CString::size_type> m_msuWidths;
};
#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();
CBlowfish(const CBlowfish&) = default;
CBlowfish& operator=(const CBlowfish&) = default;
//! output must be freed
static unsigned char* MD5(const unsigned char* input, unsigned 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,
unsigned int ibytes);
//! must free result
unsigned char* Crypt(unsigned char* input, unsigned 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_mItems(), 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 nullptr
* @param Item The item to check for
* @return Pointer to the item or nullptr if there is no suitable one
*/
V* GetItem(const K& Item) {
Cleanup();
iterator it = m_mItems.find(Item);
if (it == m_mItems.end()) return nullptr;
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(); }
/**
* @brief Returns all entries
*/
std::map<K, V> GetItems() {
Cleanup();
std::map<K, V> mItems;
for (const auto& it : m_mItems) {
mItems[it.first] = it.second.second;
}
return mItems;
}
// 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 // !ZNC_UTILS_H