DC++ Url Handler code - please help!

Problems compiling? Don't understand the source code? Don't know how to code your feature? Post here.

Moderator: Moderators

Locked
CerebusJam
Posts: 8
Joined: 2003-01-29 07:45
Contact:

DC++ Url Handler code - please help!

Post by CerebusJam » 2003-02-03 12:07

OK, folks - there's a very simple change to the code that I'd love to get going myself, but I'm unable to figure out the code. The official Direct Connect code can handle this, but DC++ has yet to do so - and I can't believe that it would take a huge stroke to get it done. I'll even donate $$ to get it tacked in the near term - even working code that I can use without an official release would be acceptable.

dchub://thisis.my.hub:port/user/path_to_album/album/file?size=bytesize

Clicking a link like this would queue up a file. Clicking a link like this

dchub://thisis.my.hub:port/user/path_to_album/album

would download the entire directory.

Right now, the only part of this that works is

dchub://thisis.my.hub:port/user

which attempts to get the file listing from that user. I can see in the code where this takes place - MainFrame::parseCommandLine in MainFrm.cpp - but I don't know the best way to code this, and I'm not familiar enough with the available functions to be able to get this implemented.

If it's a matter of $$, what dollar contribution would get this feature implemented? I swear, this'll only take a day or two to get done.

How cool would the ability to queue files/directories directly from a browser be? 8)

--C
Last edited by CerebusJam on 2003-02-03 15:07, edited 1 time in total.

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Re: DC++ Url Handler code - please help!

Post by sarf » 2003-02-03 13:20

CerebusJam wrote:[snip][shorted down to]
I want [url]dchub://thisis.my.hub:port/user/path_to_album/album?file=bytesize[/url] to add album file to my queue.
Piece of cake.

Code follows:

Code: Select all

void MainFrame::parseCommandLine(const string& cmdLine)
{
	string::size_type i = 0;
	string::size_type j = 0;
	string::size_type k = 0;
	string::size_type l = 0;
	string::size_type m = 0;

	if( (j = cmdLine.find("dchub://", i)) != string::npos) {
		i = j + 8;
		string server;
		string user;
		string path = Util::emptyString;
		string filename = Util::emptyString;
		string filesize = Util::emptyString;
		if( (j = cmdLine.find('/', i)) == string::npos) {
			server = cmdLine.substr(i);
		} else {
			server = cmdLine.substr(i, j-i);
			i = j + 1;
			if( (j = cmdLine.find_first_of("\\/ ", i)) == string::npos) {
				user = cmdLine.substr(i);
			} else {
				user = cmdLine.substr(i, j-i);
				if( (k = cmdLine.find_last_of("\\/ ", j)) != string::npos) {
					if(k > j)
					{
						path = cmdLine.substr(j, k-j);
						if( (l = cmdLine.rfind("?", k)) != string::npos) {
							filename = cmdLine.substr(k, l-k);
							// handle extensions (types or whatnot)
							if(( (m = cmdLine.rfind("&", l)) != string::npos) && (m > l)) {
								filesize = cmdLine.substr(l, m-l);
							}
							else
							{
								filesize = cmdLine.substr(l+1);
							}
							
						}
						else
						{
							path = cmdLine.substr(k+1);
						}
					}
				}
			}
		}

		if(!server.empty()) {
			HubFrame::openWindow(m_hWndMDIClient, &ctrlTab, server);
		}
		if(!user.empty()) {
			User::Ptr up = ClientManager::getInstance()->getUser(user)
			if(!path.empty())
			{
				string tempTarget = Util::emptyString;
				if(!filename.empty())
				{
					string fullFilePath = path+filename;
					string tempTarget = SETTING(DOWNLOAD_DIRECTORY) + filename;
					QueueManager::getInstance()->add(fullFilePath, filesize, up, tempTarget);
				}
				else
				{
#ifdef	DCPP_VERSION_WITH_DIRECTORY_ADDING
					string tempTarget = SETTING(DOWNLOAD_DIRECTORY) + Util::getLastDir(path);
					QueueManager::getInstance()->addDirectory(path, up, tempTarget);
#else
					QueueManager::getInstance()->addList(up);
#endif	DCPP_VERSION_WITH_DIRECTORY_ADDING
				}
			}
			else
			{
				QueueManager::getInstance()->addList(up);
			}
		}
	}
}
This would fix both your problems and does allow for expansion at a later date (as long as the commands did not use \ or /). If it works that is, as I haven't tested it, just coded it.
CerebusJam wrote:How cool would the ability to queue files/directories directly from a browser be? 8)

--C
Pretty limited in my opinion as the user might leave the hub, change nick or whatnot. This would allow hub-owners to link tools and other stuff from their homepage to a DC client they know will be in their own hub.

Sarf
---
When we talk about property, state, masters, government, laws, courts, and police, we say only that we don't want any of them.

CerebusJam
Posts: 8
Joined: 2003-01-29 07:45
Contact:

I wish that worked!

Post by CerebusJam » 2003-02-03 13:58

Thanks for trying, but that still only gets me the file list - and I'm using the new 0.23 version. I can't find that particular directive defined anywhere - but after commenting out that part, and only leaving the download directory code, I still can't make it work. A little debug assistance?

--C

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Re: I wish that worked!

Post by sarf » 2003-02-04 03:42

Argh. WinPT ate my message.

Sigh. Once more. There is a minor error in my code that needs to be corrected. Merely add a semicolon to the following line of code:

Code: Select all

      User::Ptr up = ClientManager::getInstance()->getUser(user)
I'll get back to you with the results of my testing when I get back home tonight.

Sarf
---
Thank you for shopping at S-Mart.

CerebusJam
Posts: 8
Joined: 2003-01-29 07:45
Contact:

Post by CerebusJam » 2003-02-04 08:32

Yep, caught that one - I know at least that much about coding. :) Let me know what you find out - I'm very grateful.

--C

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Post by sarf » 2003-02-04 15:04

CerebusJam wrote:Yep, caught that one - I know at least that much about coding. :) Let me know what you find out - I'm very grateful.

--C
Fixed it. Stupid me used find_last_of with an index = it didn't search far enough into the string. Cut'n'paste codin' when it is as at its lowest.

Here's the new (improved) code. I threw in handling of ?size=x handlng (before it was ?x).
Put
#define DCPP_VERSION_WITH_DIRECTORY_ADDING
in your SettingsManager.h if you have a version with directory adding (e.g. anything "better" than 0.181).

Code: Select all

void MainFrame::parseCommandLine(const string& cmdLine)
{
	string::size_type i = 0;
	string::size_type j = 0;
	string::size_type k = 0;
	string::size_type l = 0;
	string::size_type m = 0;

	if( (j = cmdLine.find("dchub://", i)) != string::npos) {
		i = j + 8;
		string server;
		string user;
		string path = Util::emptyString;
		string filename = Util::emptyString;
		string filesize = Util::emptyString;
		if( (j = cmdLine.find('/', i)) == string::npos) {
			server = cmdLine.substr(i);
		} else {
			server = cmdLine.substr(i, j-i);
			i = j + 1;
			if( (j = cmdLine.find_first_of("\\/ ", i)) == string::npos) {
				user = cmdLine.substr(i);
			} else {
				user = cmdLine.substr(i, j-i);
				j++;
				if( (k = cmdLine.find_last_of("\\/")) != string::npos) {
					if(k > j)
					{
						path = cmdLine.substr(j, k-j);
						k++;
						if( (l = cmdLine.rfind("?")) != string::npos) {
							filename = cmdLine.substr(k, l-k);
							// handle extensions (types or whatnot)
							if(( (m = cmdLine.rfind("&")) != string::npos) && (m > l)) {
								filesize = cmdLine.substr(l, m-l);
								l++;
							}
							else
							{
								filesize = cmdLine.substr(l+1);
							}
							if(filesize.find("size=") != string::npos)
							{
								filesize = filesize.substr(5);
							}
							
						}
						else
						{
							path = cmdLine.substr(k+1);
						}
					}
				}
			}
		}

		if(!server.empty()) {
			HubFrame::openWindow(m_hWndMDIClient, &ctrlTab, server);
		}
		if(!user.empty()) {
			User::Ptr up = ClientManager::getInstance()->getUser(user);
			if(path.empty())
			{
				QueueManager::getInstance()->addList(up);
			}
			else
			{
				string tempTarget = Util::emptyString;
				if(!filename.empty())
				{
					string fullFilePath = path+filename;
					tempTarget = SETTING(DOWNLOAD_DIRECTORY) + filename;
					QueueManager::getInstance()->add(fullFilePath, filesize, up, tempTarget);
				}
				else
				{
#ifdef  DCPP_VERSION_WITH_DIRECTORY_ADDING
					tempTarget = SETTING(DOWNLOAD_DIRECTORY) + Util::getLastDir(path);
					QueueManager::getInstance()->addDirectory(path, up, tempTarget);
#else
					QueueManager::getInstance()->addList(up);
#endif  DCPP_VERSION_WITH_DIRECTORY_ADDING				
				}
			}
		}
	}
}
Hope you like it.

Sarf
---
Okay, you guys having sex here, let's see some skill rolls!

CerebusJam
Posts: 8
Joined: 2003-01-29 07:45
Contact:

Hmmm...

Post by CerebusJam » 2003-02-05 08:07

Still doesn't work. Even if I'm already logged into the hub, it prompts me again to log in, and it never actually gets the dir, just the file list. Is there a problem with paths with spaces in them?

--C

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Re: Hmmm...

Post by sarf » 2003-02-05 12:31

Alright. I'll take this at face value. Snigger if you will.
CerebusJam wrote:Still doesn't work. Even if I'm already logged into the hub, it prompts me [to log in again]
The code below might explain why you get a new hub window:

Code: Select all

      if(!server.empty()) {
            HubFrame::openWindow(m_hWndMDIClient, &ctrlTab, server);
      }
The server must be EXACTLY the same "server-string" as the client you currently are on. If you connect to the hubs IP, for example, then tries to use "cerebus.elite.mega.super.duber.hub.no-ip.org" as a server then you'd get two hub windows because DC++ considers "123.123.123.42" different from the DNS name. If it is exactly the same, however, you should merely have the focus set to the hub window.
CerebusJam wrote:and it never actually gets the dir, just the file list. Is there a problem with paths with spaces in them?

--C
Well, it might be that you either a) has not defined DCPP_VERSION_WITH_DIRECTORY_ADDING or b) addDirectory does not work. I've not checked the "download directory" code myself as I (until recently) only developed for the 0.181 version. If not, then post again, using an example URL and what happens. I succeeded in queuing a file from a specific user (as well as queueing the filelist) when I tested it, but as said, could not test the directory downloading feature.

Sarf
---
Above all things, revere yourself.

izaram
Posts: 5
Joined: 2003-03-19 04:02

Post by izaram » 2003-05-10 02:10

Hello, I'm reviving this "old" thread because I've been working on this code and I want to submit a patch to arne, so I present my code here for peer review (sorry it's quite large).

Changes on MainFrm.cpp

Code: Select all

string decodeURL(const string& s) {

	string sbuf;

	static const string validHexChars ="0123456789ABCDEF";
	string hexString;
	string::size_type x = 0;

    int l  = s.length() ;
    int ch = -1 ;
    int b, sumb = 0;
    int hb, lb;

	for (int i = 0, more = -1 ; i < l ; i++) {
		/* Get next byte b from URL segment s */
		switch (ch = s.at(i)) {
		case '%':
			hexString = s.substr(i + 1, 2);
			if ( (x = hexString.find_first_not_of(validHexChars, 0)) == string ::npos) {
				ch = s.at (++i) ;
				hb = (isdigit((char) ch)
					? ch - '0'
					: 10+tolower((char) ch) - 'a') & 0xF;
				ch = s.at (++i) ;
				lb = (isdigit ((char) ch)
					? ch - '0'
					: 10+tolower((char) ch)-'a') & 0xF ;
				b = (hb << 4) | lb ;
			}
			else {
				b = ch;
			}
				break;
			//case '+':
			//	b = ' ' ;
			//	break ;
			default:
				b = ch;
		}

		/* Decode byte b as UTF-8, sumb collects incomplete chars */
		if ((b & 0xc0) == 0x80) {						// 10xxxxxx (continuation byte)
			sumb = (sumb << 6) | (b & 0x3f) ;			// Add 6 bits to sumb
			if (--more == 0) sbuf += ((char) sumb) ;	// Add char to sbuf
		} else if ((b & 0x80) == 0x00) {				// 0xxxxxxx (yields 7 bits)
			sbuf += ((char) b) ;						// Store in sbuf
		} else if ((b & 0xe0) == 0xc0) {				// 110xxxxx (yields 5 bits)
			sumb = b & 0x1f;
			more = 1;									// Expect 1 more byte
		} else if ((b & 0xf0) == 0xe0) {				// 1110xxxx (yields 4 bits)
			sumb = b & 0x0f;
			more = 2;									// Expect 2 more bytes
		} else if ((b & 0xf8) == 0xf0) {				// 11110xxx (yields 3 bits)
			sumb = b & 0x07;
			more = 3;									// Expect 3 more bytes
		} else if ((b & 0xfc) == 0xf8) {				// 111110xx (yields 2 bits)
			sumb = b & 0x03;
			more = 4;									// Expect 4 more bytes
		} else /*if ((b & 0xfe) == 0xfc)*/ {			// 1111110x (yields 1 bit)
			sumb = b & 0x01;
			more = 5;									// Expect 5 more bytes
		}


		/* We don't test if the UTF-8 encoding is well-formed */
	}

	return sbuf ;
    
}


void MainFrame::parseCommandLine(const string& cmdLine) {
	string::size_type i = 0;
	string::size_type j = 0;
	string::size_type k = 0;
	string::size_type l = 0;
	string::size_type m = 0;
	string::size_type x = 0;

//	string tmpCmdLine = decodeURL(cmdLine);
	
	if ( (j = cmdLine.find("dchub://", i)) != string::npos) {
		i = j + 8;

		string server;
		string user;
		string path = Util::emptyString;
		string filename = Util::emptyString;
		string filesize = Util::emptyString;

		if( (j = cmdLine.find('/', i)) == string::npos) {
			server = cmdLine.substr(i);
		}
		else {
			server = cmdLine.substr(i, j-i);
			i = j + 1;

			// Changed for compatibility 
			// if( (j = cmdLine.find_first_of("\\/ ", i)) == string::npos) {
			if( (j = cmdLine.find_first_of("$ ", i)) == string::npos) {
				user = cmdLine.substr(i);
			}
			else {
				user = cmdLine.substr(i, j-i);
				j++;

				if( (k = cmdLine.find_last_of("\\/")) != string::npos) {
					if(k > j) {
						path = cmdLine.substr(j, k-j);
						k++;
						if( (x = path.find("/")) != string::npos) {
							while (x != string::npos) {
								path.replace(x, 1, "\\");
								x = path.find("/");
							}
						}
						if ( (path.at(path.length() - 1)) != '\\') {
							path += "\\";
						}

						if( (l = cmdLine.rfind("?")) != string::npos) {
							filename = cmdLine.substr(k, l-k);
							if(( (m = cmdLine.rfind("&")) != string::npos) && (m > l)) {
								filesize = cmdLine.substr(l, m-l);
								l++;
							}
							else {
								filesize = cmdLine.substr(l+1);
							}
							if(filesize.find("size=") != string::npos) {
								filesize = filesize.substr(5);
							}
						}
						else {
							path = cmdLine.substr(j) ;

							if( (x = path.find("/")) != string::npos) {
								while (x != string::npos) {
									path.replace(x, 1, "\\");
									x = path.find("/");
								}
							}
							if ( (path.at(path.length() -1)) != '\\') {
								path += "\\";
							}
						}
					}
				}
			}
			if(!server.empty()) {
				HubFrame::openWindow(m_hWndMDIClient, &ctrlTab, server);
			}
			if(!user.empty()) {
				User::Ptr up = ClientManager::getInstance()->getUser(user);

				if(path.empty()) {
					try {
						QueueManager::getInstance()->addList(up);
					} catch (...) {
						// ...
					}
				}
				else {
					string tempTarget = Util::emptyString;

					path = decodeURL(path);
					filename = decodeURL(filename);

					if(!filename.empty()) {
						string fullFilePath = path + filename;
						tempTarget = SETTING(DOWNLOAD_DIRECTORY) + filename;
						try {
							QueueManager::getInstance()->add(fullFilePath, filesize, up, tempTarget);
						} catch(Exception e) {
							ctrlStatus.SetText(0, e.getError().c_str());
						}
					}
					else {
						tempTarget = SETTING(DOWNLOAD_DIRECTORY);
						try {
							QueueManager::getInstance()->addDirectory(path, up, tempTarget);
						} catch(Exception e) {
							ctrlStatus.SetText(0, e.getError().c_str());
						}
					}
				}
			}
		}
	}
}
As you can see on the line I commented out that says "Changed for compatbility" the dchub:// URL now should look like this:

dchub://hub.address.net:1234/Username$/path/to/file.ext?size=1234

We need to delimit username and path with a '$' because slashes '/' are allowed as part of the username.

You also might be wondering what the decodeURL function is doing there. Well, I had to put it there because of browser incompatibilities. Opera, Mozilla and probably other browsers encode URLs when they contain extended characters. For example, a file called "Olé" will be passed to DC++ by Opera as "Ol%C3%A9" which is the URL encoded UTF-8 equivalent. The easiest way I found to work around this is to make DC++ decode all url encoded chars. This function was ported over from the one provided by w3.org.

Anyway, I think that pretty much covers it. Any comments/feedback will be greatly appreciated.
--

Izaram

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Post by sarf » 2003-05-10 14:50

izaram, I can't see any problems with that when I looked at it... however, I haven't tried it "in real life", but since I gather that you have... go for it.

Be advised, however, that you probably should ignore the fact that slashes are permitted in nicks. If some person puts up a link to themselves (or anyone else) they'd better make sure that the "target nick" does not contain slashes - if naught else, it'll make your work easier.

By the by - nice work on that decodeURL function. Never considered the special cases myself (I would've been content with handling %20).

Sarf
---
I don't want to see anybody die, but there are a few obituary notices I could read with pleasure.

GargoyleMT
DC++ Contributor
Posts: 3212
Joined: 2003-01-07 21:46
Location: .pa.us

Post by GargoyleMT » 2003-05-11 18:24

http://www.neo-modus.com/?page=News wrote:The application registers the dchub:// protocol with the OS.
It can be used from anywhere, Safari, iChat, Explorer ...
Examples -
* dchub://hubaddress/
* dchub://hubaddress:hubport/
* dchub://hubaddress:hubport/username/
* dchub://hubaddress:hubport/username/folder/folder/file.ext
That's for v1.1 of the NMDC OSX client...

izaram
Posts: 5
Joined: 2003-03-19 04:02

Post by izaram » 2003-05-11 19:59

Hey GargoyleMT. Sorry, I'm not sure what your message implies. Are you pointing out the same thing that sarf mentions?
--

Izaram

sarf
Posts: 382
Joined: 2003-01-24 05:43
Location: Sweden
Contact:

Post by sarf » 2003-05-12 10:51

As far as I can tell, GargoyleMT seems to imply that using $ to terminate nicks may be a bad thing, since the newest Neo-Modus does not use it.

Sarf
---
Real men write self-modifying code.

Sedulus
Forum Moderator
Posts: 687
Joined: 2003-01-04 09:32
Contact:

Post by Sedulus » 2003-05-12 13:21

nmdch converts \ / : * ? " < > in nicknames to underscores (chars not allowed in windows FS filenames)
(dch++ rejects logins with those chars, ptokax allows 'em all including spaces)
http://dc.selwerd.nl/hublist.xml.bz2
http://www.b.ali.btinternet.co.uk/DCPlusPlus/index.html (TheParanoidOne's DC++ Guide)
http://www.dslreports.com/faq/dc (BSOD2600's Direct Connect FAQ)

GargoyleMT
DC++ Contributor
Posts: 3212
Joined: 2003-01-07 21:46
Location: .pa.us

compatibility = com + pat + i + bi + lity

Post by GargoyleMT » 2003-05-13 22:35

izaram wrote:Hey GargoyleMT. Sorry, I'm not sure what your message implies. Are you pointing out the same thing that sarf mentions?
I'm just showing you how the most recent client by Jon Hess implements the dchub url. If you want to make your own style, go ahead, but NMDC compatibility is potentially a very important factor.

queenisdead
Posts: 2
Joined: 2003-05-19 05:45

Post by queenisdead » 2003-05-19 05:52

hi,

has anyone made the change with izaram code ?
Is there a compile version with this feature to test ?

I'll be very interesting to give a try to this feature, but unfortunately, i have no compiler here. :( . thanks i advance for your answer :wink:

queenisdead
Posts: 2
Joined: 2003-05-19 05:45

Post by queenisdead » 2003-05-22 03:44

Again, i said this feature is a great idea.
But have you thinking about implementing a function to create this link ? (ie. copy to clipboard when right click on a folder or file or root, on your own list opened)

Yes surely :wink: . See you later

Locked