Install MediaWiki a self hosted wikipedia like app on your server

Install php-apcu:

sudo apt-get install php5-apcu

Now download the latest package and install it:

wget https://releases.wikimedia.org/mediawiki/1.28/mediawiki-1.28.2.tar.gz
tar xvf mediawiki-1.28.2.tar.gz
mv mediawiki-1.28.2 wiki
chown -R www.www *

Now visit yoursite.com/wiki and complete installation there.
In your shell, create a mysql database, user and grant access:

mysql -u root -p
MariaDB [(none)]> create database if not exists mydbname;
use mydbname;
create user 'dbusr'@'localhost' identified by 'password';
grant all on mydbname.* to 'dbusr'@'localhost';
FLUSH PRIVILEGES;
quit;

Now use these auth details on the site.

After installation is done, to change password:
Find user by email id:

mysql -u root -p
show databases;
use oscewiki;
show tables;
SELECT user_name FROM wikiuser WHERE user_email = [email protected]';
quit;
cd maintenance
sudo php changePassword.php --user=myusername --password=newpassword

You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Using cloudflare command line interface

You can easily change anything in your Cloudflare dashboard from the linux command line.

Install the cli

npm install -g cloudflare-cli

By default cfcli will look for “.cfcli.yml” in your home directory (you can also pass in a config file with -c). So create this:

emacs ~/.cfcli.yml
defaults:
    token: fcbe3cbb2894cb5f1871c89222851bf1
    email: [email protected]
    domain: oneofyourdomains.com

The token is actually the Cloudflare Global API key which you can retrieve from My Settings>Account>API Key menu.
All options:

NAME
    cfcli - Interact with cloudflare from the command line
 
SYNOPSIS
    cfcli [options] command [parameters]
 
OPTIONS:
    -c  --config    Path to yml file with config defaults (defaults to ~/.cfcli.yml
    -e  --email     Email of your cloudflare account
    -k  --token     Token for your cloudflare account
    -u  --account   Choose one of your named cloudflare accounts from .cfcli.yml
    -d  --domain    Domain to operate on
    -a  --activate  Activate cloudflare after creating record (for addrecord)
    -f  --format    Format when printing records (csv or table)
    -t  --type      Type of record (for dns record functions)
    -p  --priority  Set priority when adding a record (MX or SRV)
    -l  --ttl       Set ttl on add or edit (120 - 86400 seconds, or 1 for auto)
    -h  --help      Display help
 
COMMANDS:
    add <name> <content>
        Add a DNS record. Use -a to activate cf after creation
    devmode on|off
        Toggle development mode on/off
    disable <name> [content]
        Disable cloudflare caching for given record and optionally specific value
    edit <name> <content>
        Edit a DNS record.
    enable <name> [content]
        Enable cloudflare caching for given record and optionally specific value
    find <name> [content]
        Find a record with given name and optionally specific value
    ls
        List dns records for the domain
    purge [url]
        Purge file at given url or all files if no url given
    rm <name> [content]
        Remove record with given name and optionally specific value
    zones
        List domains in your cloudflare account

Provided examples:

Add a new A record (mail) and activate cloudflare (-a)

cfcli -a -t A add mail 8.8.8.8 
Edit a record (mail) and set the TTL

cfcli --ttl 120 edit  mail 8.8.8.8
Add an SRV record (then 3 numbers are priority, weight and port respectively)

cfcli -t SRV add _sip._tcp.example.com 1 1 1 example.com
Remove all records with the name test

cfcli rm test
Remove record with name test and value 1.1.1.1

cfcli rm test 1.1.1.1
Enable cloudflare for any records that match test

cfcli enable test
Enable cloudflare for a record test with the value test.com

cfcli enable test test.com
Export domain records for test.com to csv

cfcli -d test.com -f csv listrecords > test.csv
Purge a single file from cache

cfcli -d test.com purge http://test.com/script.js
Enable dev mode for test.com domain

cfcli -d test.com devmode on

My examples:

cfcli zones
┌──────────────────────────────────────────────────┬────────────────────┬──────────┬────────────────────────────────────────┐
│ Name                                             │ Plan               │ Active   │ ID                                     │
├──────────────────────────────────────────────────┼────────────────────┼──────────┼────────────────────────────────────────┤
│ mysite.com                                       │ Free Website       │ active   │ f81d72ad7d2a4af5e50060148389ede8       │
├──────────────────────────────────────────────────┼────────────────────┼──────────┼────────────────────────────────────────┤

Adding a CNAME record

cfcli -d eyrie.in -a -t CNAME add testrecord "joomla.com"
Explanation
-d : Work on this domain
-a : Activate the record
-t : type of DNS record
add : Add this record

Output:

Added CNAME record testrecord.eyrie.in -> joomla.com

Editing a DNS record:

cfcli -d eyrie.in -a -t CNAME edit testrecord "joomla.com"

List cloudflare records for a domain:

cfcli -d eyrie.in ls

Listing in comma seperated value (CSV) format:

cfcli -d eyrie.in ls -f csv

To export to text file:

cfcli -d eyrie.in ls -f csv > eyrie.in.csv

You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Import files to seafile from cli

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 8756C4F765C9AC3CB6B85D62379CE192D401AB61
echo deb http://dl.bintray.com/seafile-org/deb jessie main | sudo tee /etc/apt/sources.list.d/seafile.list
sudo apt-get update
apt-get install seafile-cli

Now setup cli:
# choose a folder where to store the seafile client settings e.g ~/seafile-client

mkdir ~/seafile-client            # create the settings folder
seaf-cli init -d ~/seafile-client  # initialise seafile client with this folder
seaf-cli start
seaf-cli is command line interface for seafile client.
Subcommands:
    init:           create config files for seafile client
    start:          start and run seafile client as daemon
    stop:           stop seafile client
    list:           list local liraries
    status:         show syncing status
    download:       download a library from seafile server
    sync:           synchronize an existing folder with a library in
                        seafile server
    desync:         desynchronize a library with seafile server
    create:         create a new library
Detail
======
Seafile client stores all its configure information in a config dir. The default location is `~/.ccnet`. All the commands below accept an option `-c <config-dir>`.
init
----
Initialize seafile client. This command initializes the config dir. It also creates sub-directories `seafile-data` and `seafile` under `parent-dir`. `seafile-data` is used to store internal data, while `seafile` is used as the default location put downloaded libraries.
    seaf-cli init [-c <config-dir>] -d <parent-dir>
start
-----
Start seafile client. This command start `ccnet` and `seaf-daemon`, `ccnet` is the network part of seafile client, `seaf-daemon` manages the files.
    seaf-cli start [-c <config-dir>]
stop
----
Stop seafile client.
    seaf-cli stop [-c <config-dir>]
Download
--------
Download a library from seafile server
    seaf-cli download -l <library-id> -s <seahub-server-url> -d <parent-directory> -u <username> -p <password>
sync
----
Synchronize a library with an existing folder.
    seaf-cli sync -l <library-id> -s <seahub-server-url> -d <existing-folder> -u <username> -p <password>

First retrieve the library id by browsing on the server -> it's in the url after "/repo/"

usage: seaf-cli sync [-h] [-c CONFDIR] [-l LIBRARY] [-s SERVER] [-u USERNAME]
                     [-p PASSWORD] [-d FOLDER]

optional arguments:
  -h, --help            show this help message and exit
  -c CONFDIR, --confdir CONFDIR
                        the config directory
  -l LIBRARY, --library LIBRARY
                        library id
  -s SERVER, --server SERVER
                        URL for seafile server
  -u USERNAME, --username USERNAME
                        username
  -p PASSWORD, --password PASSWORD
                        password
  -d FOLDER, --folder FOLDER
                        the existing local folder


desync
------
Desynchronize a library from seafile server
    seaf-cli desync -d <existing-folder>
create
------
Create a new library
    seaf-cli create -s <seahub-server-url> -n <library-name> -u <username> -p <password> -t <description> [-e <library-password>]
'''

Get library id:

seaf-cli list-remote -s  "https://cloud.joel.co.in" -u "[email protected]" -p "mypassword"
Name    ID
My Library d9d122233-43b6-4af3-21dde-59aawwwww45df11

Now download to local folder:

seaf-cli download -l "d9d122233-43b6-4af3-21dde-59aawwwww45df1" -s  "https://cloud.joel.co.in" -d /tmp/lib -u "[email protected]" -p "mypassword"
Starting to download ...
Library d9d122233-43b6-4af3-21dde-59aawwwww45df1 will be downloaded to /tmp/lib

Now add to this directory:

cp /tmp/att/* /tmp/lib/My\ Library/Shanghumukham-April\ 2017/Arun/

You dont need to upload/sync after adding files. The daemon automatically does that. In fact, if you attempt to sync you get an error:

seaf-cli sync -l "d9d122233-43b6-4af3-21dde-59aawwwww45df1" -s  "https://cloud.joel.co.in" -d /tmp/lib -u "[email protected]" -p "mypassword"
Starting to download ...
Traceback (most recent call last):
  File "/usr/bin/seaf-cli", line 832, in <module>
    main()
  File "/usr/bin/seaf-cli", line 828, in main
    args.func(args)
  File "/usr/bin/seaf-cli", line 568, in seaf_sync
    email, random_key, enc_version, more_info)
  File "/usr/lib/python2.7/dist-packages/pysearpc/client.py", line 112, in newfunc
    return fret(ret_str)
  File "/usr/lib/python2.7/dist-packages/pysearpc/client.py", line 25, in _fret_string
    raise SearpcError(dicts['err_msg'])
pysearpc.common.SearpcError: Repo already exists

It may be a good option to desync at the end lest you end up deleting needed folders/files.

Stopping sync:

seaf-cli desync -d /tmp/lib/My\ Library

Syncing to existing local library after desyncing:

seaf-cli sync -l "d9d122233-43b6-4af3-21dde-59aawwwww45df1" -d /root/SeafileLocalSync -s  "https://cloud.joel.co.in" -u "[email protected]"

More information from the Wiki:

Seafile client for a Cli server
Installation
You can follow this documentaion to install Seafile CLI client on various Linux distributions.

Basic Usage
Initialise & start the client

# choose a folder where to store the seafile client settings e.g ~/seafile-client
mkdir ~/seafile-client            # create the settings folder
seaf-cli init -d ~/seafile-client  # initialise seafile client with this folder
seaf-cli start
Download a library from a server

retrieve the library id by browsing on the server -> it's in the url after /repo/
then
seaf-cli download -l "the id of the library" -s  "the url + port of server" -d "the folder where the library folder will be downloaded" -u "username on server" [-p "password"]
seaf-cli status  # check status of ongoing downloads
# Name  Status  Progress
# Apps    downloading     9984/10367, 9216.1KB/s
Note: if you not supply the password parameter in the command, it will be asked later, which is more safe.

Example: `seaf-cli download -l 0536c006-8a43-449e-8718-39f12111620d -s http://cloud.seafile.com -d /tmp -u [email protected]`
Download a library from a server and sync with an existing folder.

# This is the same as download : replace download by sync 
seaf-cli sync -l "the id of the library" -s  "the url + port of server" -d "the folder where the library will be synced with" -u "username on server" -p "password"
Man documentation
seaf-cli is command line interface for seafile client.

Subcommands:

init                Initialize config directory
start               Start ccnet and seafile daemon
stop                Stop ccnet and seafile daemon
list                List local libraries
list-remote         List remote libraries
status              Show syncing status
download            Download a library from seafile server
download-by-name    Download a library defined by name from seafile server
sync                Sync a library with an existing foler
desync              Desync a library with seafile server
create              Create a library
config              Configure seafile client
Running seaf-cli -h will show the above help. For each subcommand, you can also use -h option to get help, e.g. seaf-cli download -h.

Detail
Seafile client stores all its configure information in a config dir. The default location is ~/.ccnet. All the commands below accept an option -c <config-dir>.

init
Initialize seafile client. This command initializes the config dir. It also creates sub-directories seafile-data and seafile under parent-dir. seafile-data is used to store internal data, while seafile is used as the default location put downloaded libraries.

seaf-cli init [-c <config-dir>] -d <parent-dir>
A file named seafile.ini will be created under ~/.ccnet to record the location of seafile-data directory.

If you want to run multiple instances of Seafile cli client in the same machine, you can specify different config-dir and parent-dir when initializing different client instances. Then the instances can run without interfering each others. When starting the instances, just specify ccnet config directories with the -c option.

start
Start seafile client. This command start ccnet and seaf-daemon, ccnet is the network part of seafile client, seaf-daemon manages the files.

seaf-cli start [-c <config-dir>]
stop
Stop seafile client.

seaf-cli stop [-c <config-dir>]
Download
Download a library from seafile server

seaf-cli download -l <library-id> -s <seahub-server-url> -d <parent-directory> -u <username> [-p <password>]
sync
Synchronize a library with an existing folder.

seaf-cli sync -l <library-id> -s <seahub-server-url> -d <existing-folder> -u <username> [-p <password>]
desync
Desynchronize a library from seafile server

seaf-cli desync -d <existing-folder>
create
Create a new library on server

seaf-cli create [-h] -n library-name -t description [-e library-password] -s server -u username -p password
Skip SSL certificate verify
If you're using self-signed certificate on the server, you should ask the client to skip verifying certificate.

seaf-cli config -k disable_verify_certificate -v true
Set Transfer Speed Limit
Set upload speed limit to 1MB/s :

seaf-cli config -k upload_limit -v 1000000
Set download speed limit to 1MB/s :

seaf-cli config -k download_limit -v 1000000

To sync your Dropbox folder to a new library in Seafile, create a library in Seafile named Dropbox. Then install Dropbox headless on the server and start the daemon:

64-bit:

cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -

Next, run the Dropbox daemon from the newly created .dropbox-dist folder. You will need to authorize after starting the daemon:

~/.dropbox-dist/dropboxd
Dowload the Dropbox helper python script if you want fine grained control:
wget https://www.dropbox.com/download?dl=packages/dropbox.py
mv download\?dl\=packages%2Fdropbox.py dropbox.py
chmod +x dropbox.py
./dropbox.py

Now create a library in Seafile, note its library id (the sequence after /lib/)
Make seafile sync to existing Drobox directory

seaf-cli sync -l [libid] -s "https://cloud.yoursom.com" -u [Username] -d ~/Dropbox

To sync Google Drive:
First install the cli:
apt-get install git cmake build-essential libgcrypt11-dev libyajl-dev \
libboost-all-dev libcurl4-openssl-dev libexpat1-dev libcppunit-dev binutils-dev
git clone https://github.com/Grive/grive.git
cd grive
dpkg-buildpackage -j4 -uc -us
dpkg -i ../grive*deb
mkdir ~/GoogleDrive
cd ~/GoogleDrive
grive -a
seaf-cli sync -l [libid] -s “https://cloud.yoursom.com” -u [Username] -d ~/GoogleDrive
grive &
[/bash]

grive doesnt run as a daemon, so create a cron job to sync files every 5 minutes:

*/5 * * * * cd /root/GoogleDrive && /usr/bin/grive

You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Setting up email with Webmin/Virtualmin

First create a user account (or use a builtin account):
Virtualmin>Edit users:
Add a user:
Email address: [email protected]
POP3 login username is automatically chosen for you. Set the password.
You can test mail sending by logging in at the webmail interface at https://gody.com:20000/?mail

Next add a mail server record:
Webmin>Servers>Bind DNS Servers>
Choose your domain by clicking on it:
Name is the website name typically.
Eg: I want to send mail to [email protected], fill in the following details:
Name gody.com
Mail Server: mail.gody.com
TTL: Default
Priority: 5

Now go to your DNS registrar (Eg Cloudflare) and setup the following records:
Add an MX record.
Name: gody.com
Value: mail.gody.com
TTL 2 minutes

Now test your settings in a POP3 program like Outlook:
Account type: POP3
Incoming mail server: mail.gody.com
Outgoing mail server: mail.gody.com
Username: joel.gody
Password: What you chose.


You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Configure mutt to send email from Google Apps gmail account

This illustrates how to setup mutt so that it sends email from a Google Apps gmail account. Alternately, you can just use a Gmail regular account.

First install mutt:
On Debian:
apt-get install mutt

Now, create a folder for mutt:
mkdir -p /.mutt/cache

Now, edit ~/.muttrc file (it may not exist):
emacs ~/.muttrc

It should have the following contents:

account-hook imap://gmail/ “set
set from = "[email protected]"
set realname = "Server Mailer"
set imap_user = "[email protected]"
set imap_pass = "Be4!testpass"
set folder = "imaps://imap.gmail.com:993"
set spoolfile = "+INBOX"
set postponed ="+[Gmail]/Drafts"
set header_cache =~/.mutt/cache/headers
set message_cachedir =~/.mutt/cache/bodies
set certificate_file =~/.mutt/certificates
set smtp_url = "smtp:[email protected]@smtp.gmail.com:587/"
set smtp_pass = "Be4!testpass"
set move = no
set imap_keepalive = 900

In the above example mutt configuration file, I had already created a Google Apps Mail account [email protected], with the password “Be4!testpass”. Of course you should set a more complex password.

Create a test message:

emacs /tmp/message.txt
TResting
Pot
Got

Now try sending a mail to yourself to test:
mutt -s “Test from mutt” [email protected] < /tmp/message.txt If you get the following error message: "SASL authentication failed, Could not send the message.", it means that there is a problem with the username or password. If it works, you should momentarily receive an email at the target email account that you specified. This is extremely useful, since it allows you to avoid installing a mail server on your VPS.


You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Synchronizing Dropbox files with Hubic

Hubic offers 25 GB of storage for free. It makes sense therefore to transfer your Dropbox-ed files to Hubic.

First download the Dropbox files to your linux server with the dropbox CLI.

cd ~/
wget --content-disposition https://www.dropbox.com/download?plat=lnx.x86_64
tar xf dropbox-lnx.x86_64-2.6.20.tar.gz
~/.dropbox-dist/dropboxd

For 32 bit, you should use https://www.dropbox.com/download?plat=lnx.x86
Alternately, choose a package appropriate for your OS from here.

Now you will be prompted to link your server to Dropbox by visiting a weblink:

#~/.dropbox-dist/dropboxd
This computer isn't linked to any Dropbox account...
Please visit https://www.dropbox.com/cli_link?host_id=d1ecdecdf47d8e38732ffde33256fbb9e43 to link this device.

Enter your Dropbox password to link the server.

This computer is now linked to Dropbox. Welcome Joel

Once it is setup for the first time, you should start the dropbox daemon once again and send it to background.

#~/.dropbox-dist/dropboxd &

Now, install the Hubic package for Debian from http://mir7.ovh.net/ovh-applications/hubic/hubiC-Linux/1.2.4/
Instructions: https://forums.hubic.com/showthread.php?272-hubiC-for-Linux-beta-is-out-!

Summary:

wget http://mir7.ovh.net/ovh-applications/hubic/hubiC-Linux/1.2.4/hubiC-Linux-1.2.4.35-linux.deb
dpkg -i hubiC-Linux-1.2.4.35-linux.deb
apt-get install -f
dbus-daemon --session --fork --print-address

Now use the output of the last command:

export DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-9VodnJEWDS,guid=7d86192aab25825f0feee264532e4bc4'
hubic login [email protected] Dropbox/
hubic start

To automatise login, do:

#hubic login --password_path=/root/.hubicpassword [email protected] Dropbox/

Here, you should be creating a file /root/.hubicpassword which contains your password in plaintext.

To get the status of synchronization, use the following:

hubic status

Keep the Dropbox service running:
You should install the Dropbox CLI (command line interface) which can be used to get the status of dropbox daemon, start and stop the daemon etc.

Install the CLI:

#mkdir -p ~/bin
#wget -O ~/bin/dropbox.py "https://www.dropbox.com/download?dl=packages/dropbox.py"
#chmod +x ~/bin/dropbox.py
 #~/bin/dropbox.py help

Dropbox command-line interface

commands:

Note: use dropbox help to view usage for a specific command.

status get current status of the dropboxd
help provide help
puburl get public url of a file in your dropbox
stop stop dropboxd
running return whether dropbox is running
start start dropboxd
filestatus get current sync status of one or more files
ls list directory contents with current sync status
autostart automatically start dropbox at login
exclude ignores/excludes a directory from syncing
lansync enables or disables LAN sync

Start the daemon with the CLI:

#~/bin/dropbox.py start
Starting Dropbox...Dropbox isn't running!
Done!

Solutions to common problems:
“Cannot contact daemon, are you sure it is running?”

Try the following:

#dbus-launch --sh-syntax
DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-eG8rW6f2iR,guid=c51a477c991da9681f80b58a5376246d';
export DBUS_SESSION_BUS_ADDRESS;
DBUS_SESSION_BUS_PID=1552;

Now do:
#export DBUS_SESSION_BUS_ADDRESS=’unix:abstract=/tmp/dbus-eG8rW6f2iR,guid=c51a477c991da9681f80b58a5376246d’

Now try logging into hubic again.


You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Tracking and reporting a mail spammer

Here’s what I received in my mailbox today:

Delivered-To: [[email protected] removed]
Received: by 10.68.204.234 with SMTP id lb10csp6940pbc;
        Sat, 10 Aug 2013 01:39:05 -0700 (PDT)
X-Received: by 10.60.131.69 with SMTP id ok5mr3471132oeb.70.1376123944596;
        Sat, 10 Aug 2013 01:39:04 -0700 (PDT)
Return-Path: <[email protected]>
Received: from mail-oa0-f46.google.com (mail-oa0-f46.google.com [209.85.219.46])
        by mx.google.com with ESMTPS id sp4si11350425oeb.124.2013.08.10.01.39.04
        for <[[email protected] removed]>
        (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
        Sat, 10 Aug 2013 01:39:04 -0700 (PDT)
Received-SPF: pass (google.com: domain of [email protected] designates 209.85.219.46 as permitted sender) client-ip=209.85.219.46;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of [email protected] designates 209.85.219.46 as permitted sender) [email protected]
Received: by mail-oa0-f46.google.com with SMTP id l10so7944474oag.33
        for <[[email protected] removed]>; Sat, 10 Aug 2013 01:39:04 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=google.com; s=20120113;
        h=x-original-authentication-results:delivered-to:to:subject:from
         :reply-to:message-id:date;
        bh=zSMRbrl//PMEzHQ6OysHgk48CTaa8Hx+QU92JI9AcuE=;
        b=V0jDd5g44xp/IflBQFEPP/A7WMhSgycsjaYSstyMPUC2DZtHGa3m2kexZR5cYbWZW0
         +kgwdapOCTRshF9sHdP9SJ5IfIhwyyd3TExyjzMun0nVaY0Eb8qBkq+ZyjRCXw6Sq4jL
         oguysxDZlQkd9AKLYz5BEFOOJJW4AMMYRu0UikldCbP5xXXdmQE2meXZJoadY9oE9WXA
         qhPhacLCZXEftv6FUWya9oygDEAUDwOnjgo09GB/R4kc+gMx7Nv4K9j+YDFJTK3n7PYQ
         zjppUh9eP6ONxuNrCqzQDAhQP8iSzygLBhvc49vjnZpMFOxsOR4yD4KlpmzrBGvnOaTO
         UEIg==
X-Original-Authentication-Results: mx.google.com;       spf=neutral (google.com: 198.23.248.156 is neither permitted nor denied by best guess record for domain of [email protected]) [email protected]
X-Received: by 10.182.119.229 with SMTP id kx5mr6412591obb.23.1376123944234;
        Sat, 10 Aug 2013 01:39:04 -0700 (PDT)
X-Forwarded-To: [[email protected] removed]
X-Forwarded-For: [[email protected] removed] [[email protected] removed]
Delivered-To: [[email protected] removed]
Received: by 10.182.128.229 with SMTP id nr5csp8850obb;
        Sat, 10 Aug 2013 01:39:03 -0700 (PDT)
X-Received: by 10.68.189.194 with SMTP id gk2mr1027310pbc.194.1376123943050;
        Sat, 10 Aug 2013 01:39:03 -0700 (PDT)
Return-Path: <[email protected]>
Received: from us4.networkpanda.com ([198.23.248.156])
        by mx.google.com with ESMTPS id ie10si14857047pbc.251.2013.08.10.01.39.02
        for <[[email protected] removed]>
        (version=TLSv1 cipher=RC4-SHA bits=128/128);
        Sat, 10 Aug 2013 01:39:03 -0700 (PDT)
Received-SPF: neutral (google.com: 198.23.248.156 is neither permitted nor denied by best guess record for domain of [email protected]) client-ip=198.23.248.156;
Received: from topseo80 by us4.networkpanda.com with local (Exim 4.80.1)
	(envelope-from <[email protected]>)
	id 1V84hR-000004-MM
	for [[email protected] removed]; Sat, 10 Aug 2013 08:39:01 +0000
To: [[email protected] removed]
Subject: VPS Hosting Services Providers
From: [email protected]
Reply-To: [email protected]
X-Mailer: NotOneBit.com Simple Mailer
Message-Id: <[email protected]>
Date: Sat, 10 Aug 2013 08:39:01 +0000
X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
X-AntiAbuse: Primary Hostname - us4.networkpanda.com
X-AntiAbuse: Original Domain - gmail.com
X-AntiAbuse: Originator/Caller UID/GID - [764 765] / [47 12]
X-AntiAbuse: Sender Address Domain - us4.networkpanda.com
X-Get-Message-Sender-Via: us4.networkpanda.com: authenticated_id: topseo80/only user confirmed/virtual account not confirmed

Dear Sir,

I am Hemant Bansal, Business development executive. We are providing quality VPS hosting for websites.

If your website is grown up or not running smoothly, we can provide you quality Virtual private server (VPS) hosting for Rs 800/- only.

In VPS you will get all the features of a dedicated server for fraction of a dedicated server cost. You will get full root access, can host unlimited domains, unlimited email ids. You can install any software which need root access and can set any configuration setting as per your need.

If you are suffering in shared hosting because other sites in shared server are using too much resources or facing problem in email due to your neighbour site is spamming. We recommend you to switch to VPS hosting. A VPS will give you complete independence and lots of room to grow your site.

I will really appreciate if you please let me know your VPS requirement.

We are also providing Reseller and shared hosting.


Warm Regards

Hemant Bansal


P.S. To stop receiving further mail please reply with "Remove" in the subject line.

I went on the trail of this spammer.

Looking at the Original Message text in Gmail, gives me:

X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
X-AntiAbuse: Primary Hostname - us4.networkpanda.com
X-AntiAbuse: Original Domain - gmail.com
X-AntiAbuse: Originator/Caller UID/GID - [764 765] / [47 12]
X-AntiAbuse: Sender Address Domain - us4.networkpanda.com
X-Get-Message-Sender-Via: X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
X-AntiAbuse: Primary Hostname - us4.networkpanda.com
X-AntiAbuse: Original Domain - gmail.com
X-AntiAbuse: Originator/Caller UID/GID - [764 765] / [47 12]
X-AntiAbuse: Sender Address Domain - us4.networkpanda.com
X-Get-Message-Sender-Via: us4.networkpanda.com: authenticated_id: topseo80/only user confirmed/virtual account not confirmed: authenticated_id: topseo80/only user confirmed/virtual account not confirmed

Accordingly I trace the mail server: us4.networkpanda.com

#ping us4.networkpanda.com
PING us4.networkpanda.com (192.227.129.118) 56(84) bytes of data.
64 bytes from host.colocrossing.com (192.227.129.118): icmp_req=1 ttl=48 time=82.4 ms

Now I need to locate the company to whom this IP block has been delegated.

I visit http://whois.arin.net/rest/net/NET-192-227-129-112-1/pft

It gives me the following details:

WHOIS-RWS

Network
NetRange	192.227.129.112 - 192.227.129.127
CIDR	192.227.129.112/28
Name	CC-192-227-129-112-28
Handle	NET-192-227-129-112-1
Parent	CC-12 (NET-192-227-128-0-1)
Net Type	Reallocated
Origin AS	AS36352
Organization	Green Value Hosting, Inc. (GVH-7)
Registration Date	2013-07-28
Last Updated	2013-07-28
Comments	
RESTful Link	http://whois.arin.net/rest/net/NET-192-227-129-112-1
See Also	Related organization's POC records.
See Also	Related delegations.


Organization
Name	Green Value Hosting, Inc.
Handle	GVH-7
Street	1600 Ironwood Dr
City	Normal
State/Province	IL
Postal Code	61761
Country	US
Registration Date	2013-07-15
Last Updated	2013-07-15
Comments	
RESTful Link	http://whois.arin.net/rest/org/GVH-7
Function	Point of Contact
NOC	JONAT8-ARIN (JONAT8-ARIN)
Admin	JONAT8-ARIN (JONAT8-ARIN)
Tech	JONAT8-ARIN (JONAT8-ARIN)
Abuse	JONAT8-ARIN (JONAT8-ARIN)


Point of Contact
Name	Jonathan , Nguyen
Handle	JONAT8-ARIN
Company	Green Value Hositng, Inc.
Street	6 Copps Hill Road
City	Windham
State/Province	NH
Postal Code	03087
Country	US
Registration Date	2013-07-13
Last Updated	2013-07-20
Comments	
Phone	+1-603-339-2886 (Office)
Email	[email protected]
[email protected]
RESTful Link	http://whois.arin.net/rest/poc/JONAT8-ARIN

Now I got the following details. The block was delegated to Greenvalue Hosts, which is a known provider in Webhostingtalk circles. I also got the email details of their abuse department.

Another detail that I got from the mail itself is the mailserver name: us4.networkpanda.com

networkpanda.com seems to be a hosting company, which probably rents a dedicated server from Greenvalue hosts. I reported the spam mail to both companies.

If they don’t take action, the next measure is to report it to Colocrossing, the colocator/dedicated server provider, and also ARIN, which is the IP block delegator agency.

Thanks to @INIZ on Lowendtalk.com for help regarding RIPE databases.

Note: If you do a search on ARIN, by default, they take you to this page: http://whois.arin.net/rest/net/NET-192-227-129-112-1 which does not provide full details. You need to suffix ‘/pft’ to the resulting url to get full details. Eg: http://whois.arin.net/rest/net/NET-192-227-129-112-1/pft

As per ARIN’s post:

The next enhancement is a change to the default output on a query initiated by the search box on the web page for IP addresses, organizations, and ASNs. The query for an IP address or network will return the network as well as the full output of related Organization and Point of Contact (POC) data for the network. Likewise, the query result for an AS number will output the associated organization and related POCs along with the AS number. The query result for an organization, will list all related networks and ASNs, and give full output of associated POCs. This will allow you to view all information on a single web page. This “pft” option is an enhancement to the RESTful web interface, and it is not available on port 43. To use it, append “/pft” to the URL, for example:

http://whois.arin.net/rest/org/ARIN/pft
http://whois.arin.net/rest/net/ NET-192-136-136-0-1/pft
Note again that web search forms will default to using the “pft” option.

Response from the Provider

I had contacted the abuse department of networkpanda.com, whose email server us4.networkpanda.com was used for sending spam email. They responded by blocking the user:

Hello Joel, 

Just as a follow up, the user who was authenticating to this Gmail account to send the messages, was now permanently suspended from our servers. But you will also need to report the account [email protected] to Google, as he will be also using other providers to send spam. 

Thank you for reporting this issue. 

You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Alert by email when root user logins by shell

The following command added to ~/.bash_profile will alert a specified address when a root user signs in.

echo 'ALERT - Root Shell Access () on:' `date` `who` | mail -s "Alert: Root Access from `who | cut -d"(" -f2 | cut -d")" -f1`" [email protected]
source .bashrc

.bashrc is sourced because, at least on Debian squeeze, .bashrc isnt executed if .bash_profile exists.


You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Send mail from bash with attachment

Install mutt.

apt-get install mutt

 

Run mutt with the following syntax:

echo "This is the message body" | mutt -a /somewhere/file -s "subject of message" -- [email protected]

Note that when you use variables, there is a slight modification necessary:

echo $BODY | mutt -a /pathto/file -s "$SUB" -- [email protected]

Note that the subject coming after -s needs to be enclosed in quotes. In fact whenever you need to use variables as parts of the mutt command, you need to enclose the respective variable in double quotes. Single quotes of course escape the variables and would use the variable name as literals.

The sender unless specified is taken as your [email protected], where username is your root shell username, which is usually root.

You can use a file as the BODY field of the email. Can you guess the syntax?

cat /pathto/bodyfile | mutt -a /somewhere/attachmentfile -s "subject of message" -- [email protected]

cat /pathto/bodyfile | mutt -a /somewhere/attachmentfile -s “subject of message” — [email protected]

If you need to specify the sender:

[[email protected]] ~ #cat ~/.muttrc
set from="BackupServer <[email protected]>"

You can change the sender header at runtime, without relying on .muttrc, by building up a variable for the header using quotes for your literals, and concatenate (join) them with variables.

Eg:

Say you need your email to be coming from [email protected], with the name John B. Doe, you’d have to do something like this:

[email protected]
fname="John B. Doe"
hdrst='my_hdr From:'$fname' <'$email'>'

which will build the string:

my_hdr From:John B. Doe<[email protected]>

and send it to the mutt command as a custom header for your email.

echo $BODY | mutt -e "$hdrst" -a fullbackup -s "$SUB" -- [email protected]

Once again, note that the command will fail unless the variables $hdrst and $SUB are enclosed in double quotes.

References:

  1. Official mutt FAQ
  2. Mutt manual
  3. Cybergav blog post

You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.

Wrap a php parser file in WordPress theme

I created a form parser for a WordPress site that would parse the contents of a posted form, and display a success page. I used pure php instead of trying to use a WordPress template or theme. As a downside, the displayed page would not show any WordPress theme.

So I found a solution to import the theme for the php, and this is by including the theme’s header and footer in the php file.

The complete form parser is included below:

<?php

// If title is not displayed before loading the header, WordPress displays "Page not found" as the title

echo "<head>
<title>Your form has been submitted</title>
</head>";

// Include the Main WordPress blog header
include $_SERVER['DOCUMENT_ROOT']."/wp-blog-header.php";

// Include the specific theme header you need
include $_SERVER['DOCUMENT_ROOT']."/wp-content/themes/studiopress/genesis/header.php";

// Your custom code STARTS here

// My code includes two functions. 
// The first part is the background activity which parses the form, checks for errors and then mails it if there arent any errors
// The second part is html code that is displayed to the user to inform them that the form has been submitted.

if(isset($_POST['email'])) {

    // EDIT THE 2 LINES BELOW AS REQUIRED
    $email_to = "[email protected]";
    $email_subject = "Someone has submitted feedback on your website";

    function died($error) {
        // your error code can go here
        echo "We are very sorry, but there were error(s) found with the form you submitted. ";
        echo "These errors appear below.<br /><br />";
        echo $error."<br /><br />";
        echo "Please go back and fix these errors.<br /><br />";
        die();
    }

    // validation expected data exists
    if(!isset($_POST['first_name']) ||
        !isset($_POST['last_name']) ||
        !isset($_POST['email']) ||
        !isset($_POST['telephone']) ||
        !isset($_POST['comments'])) {
        died('We are sorry, but there appears to be a problem with the form you submitted.');       
    }

    $first_name = $_POST['first_name']; // required
    $last_name = $_POST['last_name']; // required
    $email_from = $_POST['email']; // required
    $telephone = $_POST['telephone']; // not required
    $comments = $_POST['comments']; // required

    $error_message = "";
    $email_exp = '/^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/';
  if(!preg_match($email_exp,$email_from)) {
    $error_message .= 'The Email Address you entered does not appear to be valid.<br />';
  }
    $string_exp = "/^[A-Za-z .'-]+$/";
  if(!preg_match($string_exp,$first_name)) {
    $error_message .= 'The First Name you entered does not appear to be valid.<br />';
  }
  if(!preg_match($string_exp,$last_name)) {
    $error_message .= 'The Last Name you entered does not appear to be valid.<br />';
  }
  if(strlen($comments) < 2) {
    $error_message .= 'The Comments you entered do not appear to be valid.<br />';
  }
  if(strlen($error_message) > 0) {
    died($error_message);
  }
    $email_message = "Form details below.\n\n";

    function clean_string($string) {
      $bad = array("content-type","bcc:","to:","cc:","href");
      return str_replace($bad,"",$string);
    }

    $email_message .= "First Name: ".clean_string($first_name)."\n";
    $email_message .= "Last Name: ".clean_string($last_name)."\n";
    $email_message .= "Email: ".clean_string($email_from)."\n";
    $email_message .= "Telephone: ".clean_string($telephone)."\n";
    $email_message .= "Comments: ".clean_string($comments)."\n";

// create email headers

$headers = 'From: [email protected]'."\r\n".
'Reply-To: '.$email_from."\r\n" .
'X-Mailer: PHP/' . phpversion();
@mail($email_to, $email_subject, $email_message, $headers);  
?>

<?php
// Second part starts.
// This part is displayed.

echo "
<h2>
Your form has been submitted
</h2>";

echo "<h4>Dear $first_name,</h4>
<p>Your feedback has been received by us and will be forwarded to the site administrator. You will receive your login details or a response soon.</p>";

echo "<br /><br /><br /><br /><br /><br /><br />
Click <a href=\"http://www.site.com\">here</a> to return to the site.";
// END of custom code

?> 

<?php
}
include $_SERVER['DOCUMENT_ROOT']."/wp-content/themes/studiopress/genesis/footer.php";
?>[/code]
The following is the actual form:
You can use the following form to contact the administrator of this site:

<form action="../phpscripts/send_form_email1.php" method="post" name="contactform">Note: If you're requesting login rights, please add information on how you're related to the family.&nbsp;
<table width="450px">
<tbody>
<tr>
<td valign="top"><label for="first_name">First Name *</label></td>
<td valign="top"><input type="text" maxlength="50" name="first_name" size="30" /></td>
</tr>
<tr>
<td valign="top"><label for="last_name">Last Name *</label></td>
<td valign="top"><input type="text" maxlength="50" name="last_name" size="30" /></td>
</tr>
<tr>
<td valign="top"><label for="email">Email Address *</label></td>
<td valign="top"><input type="text" maxlength="80" name="email" size="30" /></td>
</tr>
<tr>
<td valign="top"><label for="telephone">Telephone Number</label></td>
<td valign="top"><input type="text" maxlength="30" name="telephone" size="30" /></td>
</tr>
<tr>
<td valign="top"><label for="comments">Comments *</label></td>
<td valign="top"><textarea cols="30" maxlength="1000" name="comments" rows="6"></textarea></td>
</tr>
<tr>
<td></td>
<td style="text-align: left;" colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</tbody>
</table>
</form>[/code]
Version 0.2

I made it generic and detect the proper active theme:
&lt;?php

// If title is not displayed before loading the header, WordPress displays "Page not found" as the title

echo "&lt;head&gt;
&lt;title&gt;Your feedback has been submitted&lt;/title&gt;
&lt;/head&gt;";

// Include the Main WordPress blog header
include $_SERVER['DOCUMENT_ROOT']."/wp-blog-header.php";

//bloginfo(‘template_url’);
$homeurl=home_url();
$ddir= get_bloginfo( 'template_directory');
$current_theme_relative_path=substr_replace($ddir, "", 0, strlen($homeurl));
//echo "&lt;br/&gt;The relative path to the currently active theme is ".$newss;

// Include the specific theme header you need
//echo "Full path to header is ".$_SERVER['DOCUMENT_ROOT'].$newss."/header.php";
include $_SERVER['DOCUMENT_ROOT'].$current_theme_relative_path."/header.php";

// Your custom code STARTS here

// My code includes two functions. 
// The first part is the background activity which parses the form, checks for errors and then mails it if there arent any errors
// The second part is html code that is displayed to the user to inform them that the form has been submitted.

if(isset($_POST['email'])) {

    // EDIT THE 2 LINES BELOW AS REQUIRED
    $email_to = "[email protected]";
    $email_subject = "Someone has submitted feedback on your website";

    function died($error) {
        // your error code can go here
        echo "We are very sorry, but there were error(s) found with the form you submitted. ";
        echo "These errors appear below.&lt;br /&gt;&lt;br /&gt;";
        echo $error."&lt;br /&gt;&lt;br /&gt;";
        echo "Please go back and fix these errors.&lt;br /&gt;&lt;br /&gt;";
        die();
    }

    // validation expected data exists
    if(!isset($_POST['first_name']) ||
        !isset($_POST['last_name']) ||
        !isset($_POST['email']) ||
        !isset($_POST['telephone']) ||
        !isset($_POST['comments'])) {
        died('We are sorry, but there appears to be a problem with the form you submitted.');       
    }

    $first_name = $_POST['first_name']; // required
    $last_name = $_POST['last_name']; // required
    $email_from = $_POST['email']; // required
    $telephone = $_POST['telephone']; // not required
    $comments = $_POST['comments']; // required

    $error_message = "";
    $email_exp = '/^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/';
  if(!preg_match($email_exp,$email_from)) {
    $error_message .= 'The Email Address you entered does not appear to be valid.&lt;br /&gt;';
  }
    $string_exp = "/^[A-Za-z .'-]+$/";
  if(!preg_match($string_exp,$first_name)) {
    $error_message .= 'The First Name you entered does not appear to be valid.&lt;br /&gt;';
  }
  if(!preg_match($string_exp,$last_name)) {
    $error_message .= 'The Last Name you entered does not appear to be valid.&lt;br /&gt;';
  }
  if(strlen($comments) &lt; 2) {
    $error_message .= 'The Comments you entered do not appear to be valid.&lt;br /&gt;';
  }
  if(strlen($error_message) &gt; 0) {
    died($error_message);
  }
    $email_message = "Form details below.\n\n";

    function clean_string($string) {
      $bad = array("content-type","bcc:","to:","cc:","href");
      return str_replace($bad,"",$string);
    }

    $email_message .= "First Name: ".clean_string($first_name)."\n";
    $email_message .= "Last Name: ".clean_string($last_name)."\n";
    $email_message .= "Email: ".clean_string($email_from)."\n";
    $email_message .= "Telephone: ".clean_string($telephone)."\n";
    $email_message .= "Comments: ".clean_string($comments)."\n";

// create email headers

$headers = 'From: [email protected]'."\r\n".
'Reply-To: '.$email_from."\r\n" .
'X-Mailer: PHP/' . phpversion();
@mail($email_to, $email_subject, $email_message, $headers);  
?&gt;

&lt;?php
// Second part starts.
// This part is displayed.

echo "
&lt;h2&gt;
Your feedback/request has been submitted
&lt;/h2&gt;";

echo "&lt;h4&gt;Dear $first_name,&lt;/h4&gt;
&lt;p&gt;Your feedback has been received by us and will be forwarded to the site administrator. 
&lt;br/&gt;
You will receive your login details or a response soon.&lt;/p&gt;";

echo "&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
Click &lt;a href=\"http://www.vettathu.com\"&gt;here&lt;/a&gt; to return to the site.";
// END of custom code

//Useful wordpress functions
/*
echo "The current theme name is".get_current_theme()."&lt;br/&gt;";

echo "&lt;br/&gt;";
echo "The dir is ".$ddir."&lt;br/&gt;";

echo "The home url is".$homeurl."&lt;br/&gt;";
*/
//$newdirst=str_replace($homeurl,".",$temp_ddir);

/*
echo "Length of whole is ".strlen($ddir);
echo "Length of substring is ".strlen($homeurl);

*/

?&gt; 

&lt;?php
}
include $_SERVER['DOCUMENT_ROOT'].$current_theme_relative_path."/footer.php";

?&gt;

 


You are reading this post on Joel G Mathew’s tech blog. Joel's personal blog is the Eyrie, hosted here.