Items of Interest
Switching from the official Edonkey Linux Core to MLDonkey
I have been using the setup I refer to in my Edonkey 2000 on Linux article until today. I discovered MLDonkey today, and I will not ever go back. MLDonkey is a Edonkey 2000 network compatible client and it is not based on the troublesome and often unpredictable Edonkey 2000 Core client. Instead, the authors took a different approach and reverse engineered the protocol from scratch. While they explain it is only partially reverse engineered, MLDonkey is completely functional and worked exceedingly well in my tests.

If you are curious, MLDonkey is written in a little known language called Objective Caml. There are two flavours of a GTK GUI for Linux. I perfer the first one over the second. Neither are particularly attractive or well designed, but the client's functionality more than makes up for its visual defects.

Obtaining MLdonkey on Debian GNU/Linux

apt-get install mldonkey-server mldonkey-gui

That's it!

If you want an X GUI, I highly recommend KMLDonkey. Its been unofficially packaged for Debian and is available for consumption. Simply download kmldonkey and libkmldonkey and install using dpkg. Thanks for the packages sirReal!

Configuring the Core and GUI

You may wish to define alternate locations for the incoming and temporary directories; both will become quite large. The default is to dump both of them in whatever the current working directory is when you start MLDonkey, which I doubt nearly anyone wants.

        (* The directory where downloaded files
  should be moved after commit *)
 incoming_directory = "/export/incoming/mld"

        (* The directory where temporary files should be put *)
 temp_directory = "/export/incoming/tmp"
You can provide a list of additional directories, besides your incoming directory, from which MLDonkey can share files. For instance, mine looks like the following:
        (* Directories where files will be shared *)
shared_directories = [ "/home/jasonb/share/mp3", "/mnt/c/files" ]
If you want MLDonkey to automatically move completed files into your incoming directory using a random filename you will like the auto commit feature. I prefer to choose the best filename myself when saving, so I have turned it off. I recommend you disable it too.
        (* Set to false if you don't want mldonkey to automatically put
  completed files in incoming directory *)
 auto_commit = false
By default, MLDonkey listens only on your loopback device, but deeper in this file you can change that but adding entries to the option below.
        (* list of IP address allowed to control the client
        via telnet/GUI/WEB *)
 allowed_ips = [
  "127.0.0.1", "192.168.5.2"]
If you decide to allow remote access so you can do things like add downloads to your list, you'll want to set these values:
        (* Your login when using a WEB browser *)
 http_login = ""

        (* Your password when using a WEB browser *)
 http_password = ""
The protocol used is HTTP, and these will be passed off to MLDonkey when you send it commands remotely. Set them to whatever you want.

The next two configuration directives are quite important. By default, MLDonkey will completely saturate your connection. That might be fine if you're on a huge pipe, but if you're on xDSL, Cable, or 56K it will be a problem.

        (* The maximal upload rate you can tolerate
        on your link in kB/s (0 = no limit)
        The limit will apply on all your connections
        (clients and servers) and both
        control and data messages. *)

 max_hard_upload_rate = 10

        (* The maximal download rate you can tolerate
        on your link in kB/s (0 = no limit)
        The limit will apply on all your connections
        (clients and servers) and both
        control and data messages. *)

 max_hard_download_rate = 50
You can set each option to whatever you'd like. MLDonkey will enforce what you choose. You might be tempted to set your upload rate to something extremely low, like 1. MLDonkey will not stop you, indeed cannot, for the source is available for anyone to change. But please, I emplore you to be responsible and fair to other members in the community.

Next up is an option which seems to be somewhat of a mystery to many people. It uses memory that I imagine you have other uses for, so I recommend you disable it. The default is true.

        (* keep seen files in history to allow local
        search (can be expensive in memory) *)

 use_file_history = false
The next set of options are self explanatory. If you just want the GUI to load up, set ask_for_gui to false and start_gui to true. If you wish to run MLDonkey as a daemon, you probably do not want it to attempt to start the GUI.
        (* Ask for GUI start *)
 ask_for_gui = false

        (* Automatically Start the GUI *)
 start_gui = false

        (* Directory where mldonkey binaries are installed *)
 mldonkey_bin = "/usr/bin"

        (* Name of GUI to start *)
 mldonkey_gui = "/usr/bin/mldonkey_gui"
Adding New Files to the Queue

There are a few ways to deal with this. You can use a KDE IOSlave, the included Perl script locally or remotely over SSH, or Internet Explorer with a Windows registery change. Sadly, X drag 'n drop is not one of the supported methods.

I haven't tried the KDE IOSlave with KDE2 or with KDE3.

You can add files via the console either locally or over the network, using the included Perl script, but some configuration is in order first. I recommend using mldonkey_submit. By default, you can only speak to MLDonkey via HTTP on port 4080 on the local loopback device with IP 127.0.0.1.

Let's open /usr/bin/mldonkey_submit, a Perl script that utilizes the LWP::UserAgent module, and make a few changes. First, comment out the following lines. You won't need them (I replaced the letter i with |, as Perl's gobble until next newline construct was being interpreted as an italics tag):

$vars{'HTTPURL'} = "http://localhost:4080";

my $cfg = "/etc/sysconfig/mldonkey";
open(|,"<$cfg") || die "Can't read $cfg: $!\n";
chomp (my @lines = (<|>));
close |;
foreach (@lines) {
        next if (/^#/);
        if (/([^=\s]+)=([^=\s]+)/) {
                $vars{$1}="$2";
        }
}
Next you'll want to uncomment the following three variables and change them to suit your configuration:
$vars{'HTTPURL'} = "http://127.0.0.1:4080";
$vars{'HTTPUSER'} = "mld";
$vars{'HTTPPASS'} = "mld";
By default, HTTPURL, HTTPUSER, and HTTPPASS have no values. You'll want to set both HTTPUSER and HTTPPASS to the values you used in the downloads.ini file above. You'll want to set your HTTPURL to what I have above, which should work by default.

Once that's done, you can invoke mldonkey_submit by running as shown in the following example:

$ mldonkey_submit 'ed2k://|file|filename.ext|1234|h@3h|'

You must use single quotes, or you'll confuse your shell. You can specify as many ed2k links as you want, on a single line, seperated by spaces. These will then find their way into your download list, soon to be downloaded and left in your incoming/ directory.

The script has problems with MD4 hashes that have uppercase letters. That's easily fixed. Simply add the following line to your mldonkey_submit script.

while (my $uri = shift @ARGV) {
        $_ = URI::Escape::uri_unescape($uri);
		# This line below must be added
        $_ = lc($_);
        if (/^ed2k:\/\/\|file\|[^|]+\|(\d+)\|([\dabcdef]+)\|/) {
Another possibility is to add ed2k links directory from Microsoft Internet Explorer on a machine running DOS based or NT based Windows. There is a small registry hack you can apply that will send ed2k links, via HTTP, to MLDonkey in the same manner the Perl script above does.

For this to work, however, MLDonkey will have to be configured to listen on one of your machine's accessable IP addresses. Since HTTP is used, I strongly recommend you do not access it across the Internet though it may be tempting to do so. Your login and pass will go out in clear text and anyone can then login and do evil things to your MLDonkey client. (If you need remote access across the Internet and don't want to setup a full IPSec VPN, I recommend you use OpenSSH for encryption and port forwarding. I wrote a nice article on this a few months ago for VNC which applies nicely here too.)

If you try to download a file, but it never shows up in your download list, it's possible it's because you already downloaded it. MLDonkey keeps a list of all the files you've fetched for some misguided reason. If you're sure you need to obtain a file again, you will need to telnet into the console on port 4000. Issue a download command and then force the download:

jasonb@nebula:~/.mldonkey$ telnet localhost 4000
MLdonkey command-line:
> dllink ed2k://|file|fooo|5240856498|DCEB6B3F9A117413BE7E2EAE1CB12660|
Exception Failure("File already downloaded
  (use 'force_download' if necessary)") for network Donkey
> force_download
download forced
All should then be well.

init.d script and MLDonkey user

It's always nice to have daemons run as their own user via sysv init.d. If you're not happy with the mechanism provided by the mldonkey-server package, you can use the configuration below, modified to point to the actual location of your mlnet binary.

Here's the setup I use with my MLDonkey core.

#!/bin/sh

# mlnet start/stop script
# Assumes no passwords, full access on localhost via telnet
# Best used on a secured, personal workstation

set +x

PATH=/bin:/usr/bin:/sbin:/usr/sbin
MLUSER=mlnet
DAEMON=/home/$MLUSER/bin/mlnet
MLRUNPATH=/home/$MLUSER/.mldonkey

test -x $DAEMON || exit 0

case "$1" in
  start)
        echo -n "Starting MLDonkey daemon: mlnet"
        if nc -z localhost 4000 >/dev/null 2>&1
        then
        echo
        echo " already running."
        exit
        else
        su $MLUSER -c "cd $MLRUNPATH ; $DAEMON >/dev/null 2>&1 &"
        echo "."
        fi
        ;;
  stop)
        echo -n "Stopping MLDonkey daemon: mlnet"
        if nc -z localhost 4000 >/dev/null 2>&1
        then
                echo "kill" | nc localhost 4000 >/dev/null 2>&1
                echo "."
        else
                echo " not running.";
        fi
        ;;
  force-reload|restart)
        $0 stop
        $0 start
        ;;
  *)
        echo "Usage: /etc/init.d/lpd {start|stop|restart|force-reload}"
        exit 1
esac

exit 0
The above script expects the username to be mlnet and the home directory to be by the same name.
jasonb@nebula:~$ id mlnet
uid=1003(mlnet) gid=1003(mlnet) groups=1003(mlnet),1500(share)
I created a group called share which both myself and mlnet are a member of.
jasonb@nebula:~$ ls -l /home/shared/incoming/
total 12
drwxrwsr-x    2 root     share        4096 2003-12-09 19:12 burn
drwx------    2 root     share           6 2003-07-26 14:57 lost+found
drwxrwsr-x    2 root     share        4096 2003-12-05 23:20 mld
drwxrwsr-x    2 root     share        4096 2003-12-15 17:08 tmp
The relevant directories are owned by the share group with the stick group bit set.

You will want to create a .mldonkey/ directory in the mlnet user's directory, as this is the runtime directory for the binary.

If it isn't working, try changing to the mlnet user and running the binary manually without the -daemon option.

Useful Resources

Copyright and Revision Information

11-23-02 - Initial draft
11-26-02 - Added ed2k download information
03-24-03 - Notice about (hopefully) pending updates
05-10-03 - Rewrote large portions such that they're actually meaningful and relevant now
07-24-03 - Added information about forcing a download
12-15-03 - Added stuff about init.d scripts
03-29-04 - Commented out stuff about building MLdonkey; It's in Debian now
02-24-06 - Modified init.d script; -daemon option is gone now

This document is copyright (c) Jason Boxman, 2002-2006. All rights reserved.