This adds the email feature to Duplicati. Currently there is no GUI for this, just advanced options. The options supported are: --send-mail-to="Name <test@example.com>, Other <test2@example.com>, test3@example.com" --send-mail-from="Backup Admin <admin@example.com> --send-mail-subject="Duplicati %OPERATIONNAME% Report" --send-mail-body="%RESULT%%" --send-mail-url="tls://smtp.google.com:587" --send-mail-username="username" --send-mail-password="password" --send-mail-level="Warning" --send-mail-any-operation=true The only required setting is --send-mail-to. If the --send-mail-from is not set, it will use the host of the "to" and set "no-reply@" in front. E.g. --send-mail-to="name@example.com" will cause the sender to be "no-reply@example.com". If the --send-mail-url is not set, a DNS lookup will find the MX record for the first recipient domain, and send directly to that. The url can be either "smtp://server:port" or "tis://server:port". The --send-mail-subject and --send-mail-body parameters can contain placeholders like %RESULT%. Each option will be exported like this, e.g. %volsize% or %use-ssl%. The special placeholders are: %RESULT% - The result/log of the backup %OPERATIONNAME% - The name of the operation, usually "Backup", but could be "Restore" etc. %REMOTEURL% - The backend url %LOCALPATH% - The path to the local folders involved (i.e. the folders being backed up) The --send-mail-level can be either "Success", "Warning" or "Error". Default "Success" means all backups generate an email. "Warning" will only send an email if the backup caused a warning or an error. "Error" will only send an email if the backup failed. The --send-mail-any-operation can be set to "true" if all operations (e.g. "Restore", "Cleanup", "DeleteAllButN", ...) should generate an email. By default only backup operations will send an email. git-svn-id: https://duplicati.googlecode.com/svn/trunk@1436 59da171f-624f-0410-aa54-27559c288bec
172 lines
4.9 KiB
C#
172 lines
4.9 KiB
C#
//Dnslite.cs
|
|
/**
|
|
csc /target:library /out:DnsLib.dll /keyfile:..\..\Duplicati\GUI\Duplicati.snk DnsLite.cs
|
|
*/
|
|
using System;
|
|
using System.Net;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Net.Sockets;
|
|
using System.Collections;
|
|
namespace DnsLib
|
|
{
|
|
public class MXRecord
|
|
{
|
|
public int preference = -1;
|
|
public string exchange = null;
|
|
public override string ToString()
|
|
{
|
|
return "Preference : " + preference + " Exchange : " + exchange;
|
|
}
|
|
}
|
|
public class DnsLite
|
|
{
|
|
private byte[] data;
|
|
private int position, id, length;
|
|
private string name;
|
|
private ArrayList dnsServers;
|
|
private static int DNS_PORT = 53;
|
|
Encoding ASCII = Encoding.ASCII;
|
|
public DnsLite()
|
|
{
|
|
id = DateTime.Now.Millisecond * 60;
|
|
dnsServers = new ArrayList();
|
|
|
|
}
|
|
public void setDnsServers(ArrayList dnsServers)
|
|
{
|
|
this.dnsServers = dnsServers;
|
|
}
|
|
public ArrayList getMXRecords(string host)
|
|
{
|
|
ArrayList mxRecords = null;
|
|
for(int i=0; i < dnsServers.Count; i++)
|
|
{
|
|
try
|
|
{
|
|
mxRecords = getMXRecords(host,(string)dnsServers[i]);
|
|
break;
|
|
}
|
|
catch(IOException)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
return mxRecords;
|
|
}
|
|
private int getNewId() {
|
|
//return a new id
|
|
return ++id;
|
|
}
|
|
public ArrayList getMXRecords(string host,string serverAddress) {
|
|
//opening the UDP socket at DNS server
|
|
//use UDPClient, if you are still with Beta1
|
|
UdpClient dnsClient = new UdpClient(serverAddress, DNS_PORT);
|
|
//preparing the DNS query packet.
|
|
makeQuery(getNewId(),host);
|
|
//send the data packet
|
|
dnsClient.Send(data,data.Length);
|
|
IPEndPoint endpoint = null;
|
|
//receive the data packet from DNS server
|
|
data = dnsClient.Receive(ref endpoint);
|
|
length = data.Length;
|
|
//un pack the byte array & makes an array of MXRecord objects.
|
|
return makeResponse();
|
|
}
|
|
//for packing the information to the format accepted by server
|
|
public void makeQuery(int id,String name) {
|
|
data = new byte[512];
|
|
for(int i = 0; i < 512; ++i)
|
|
{
|
|
data[i] = 0;
|
|
}
|
|
data[0] = (byte) (id >> 8);
|
|
data[1] = (byte) (id & 0xFF );
|
|
data[2] = (byte) 1; data[3] = (byte) 0;
|
|
data[4] = (byte) 0; data[5] = (byte) 1;
|
|
data[6] = (byte) 0; data[7] = (byte) 0;
|
|
data[8] = (byte) 0; data[9] = (byte) 0;
|
|
data[10] = (byte) 0; data[11] = (byte) 0;
|
|
string[] tokens = name.Split(new char[] {'.'});
|
|
string label;
|
|
position = 12;
|
|
for(int j=0; j < tokens.Length; j++) {
|
|
label = tokens[j];
|
|
data[position++] = (byte) (label.Length & 0xFF);
|
|
byte[] b = ASCII.GetBytes(label);
|
|
for(int k=0; k < b.Length; k++) {
|
|
data[position++] = b[k];
|
|
}
|
|
}
|
|
data[position++] = (byte) 0 ; data[position++] = (byte) 0;
|
|
data[position++] = (byte) 15; data[position++] = (byte) 0 ;
|
|
data[position++] = (byte) 1 ;
|
|
}
|
|
//for un packing the byte array
|
|
public ArrayList makeResponse() {
|
|
ArrayList mxRecords = new ArrayList();
|
|
MXRecord mxRecord;
|
|
//NOTE: we are ignoring the unnecessary fields.
|
|
// and takes only the data required to build MX records.
|
|
int qCount = ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
|
|
if (qCount < 0) {
|
|
throw new IOException("invalid question count");
|
|
}
|
|
int aCount = ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
|
|
if (aCount < 0) {
|
|
throw new IOException("invalid answer count");
|
|
}
|
|
position=12;
|
|
for( int i=0;i<qCount; ++i) {
|
|
name = "";
|
|
position = proc(position);
|
|
position += 4;
|
|
}
|
|
for (int i = 0; i < aCount; ++i) {
|
|
name = "";
|
|
position = proc(position);
|
|
position+=10;
|
|
int pref = (data[position++] << 8) | (data[position++] & 0xFF);
|
|
name="";
|
|
position = proc(position);
|
|
mxRecord = new MXRecord();
|
|
mxRecord.preference = pref;
|
|
mxRecord.exchange = name;
|
|
mxRecords.Add(mxRecord);
|
|
}
|
|
return mxRecords;
|
|
}
|
|
private int proc(int position) {
|
|
int len = (data[position++] & 0xFF);
|
|
if(len == 0) {
|
|
return position;
|
|
}
|
|
int offset;
|
|
do {
|
|
if ((len & 0xC0) == 0xC0) {
|
|
if (position >= length) {
|
|
return -1;
|
|
}
|
|
offset = ((len & 0x3F) << 8) | (data[position++] & 0xFF);
|
|
proc(offset);
|
|
return position;
|
|
} else {
|
|
if ((position + len) > length) {
|
|
return -1;
|
|
}
|
|
name += ASCII.GetString(data, position, len);
|
|
position += len;
|
|
}
|
|
if (position > length) {
|
|
return -1;
|
|
}
|
|
len = data[position++] & 0xFF;
|
|
if (len != 0) {
|
|
name += ".";
|
|
}
|
|
}while (len != 0);
|
|
return position;
|
|
}
|
|
}
|
|
}
|