[quote="Chessnut"]So many people are asking about how they can "make a price script", or "make a stats script". Well, here is the answer. Learn how to use sockets and you can make those scripts.
Hard? No, not really. As long as you understand the basics of mIRC scripting, sockets will be very easy. The best way to learn them is to see an example of a socket, and work out what it's doing. The only hard bit about sockets is knowing the basics. Yeah, contradiction of terms there. Clever, eh? Let's start.
[b]What is a socket?[/b]
[quote="mIRC Help file"]Socket support allows you to create your own raw socket connections in order to send and receive information.[/quote]
That is essentially what a socket is. It allows you to connect to a server using a protocol. This will normally be the HTTP protocol which allows you to connect to a website, but there are many other uses for sockets, such as checking or sending emails, connecting to a FTP server etc etc.
In this tutorial, I will describe sockets which use the usual HTTP protocol, connecting on port 80 to a website, finding the information and relaying it back to mIRC. Examples could include a global time script, a "what's on TV?" script, a Runescape stats script - the list is pretty much endless.
[b]What events does a socket use?[/b]
A socket needs to have a unique name to stop it interfering with other sockets. If two sockets have the same name, things start going pearshaped, so try to keep them unique.
There are three main socket events:
[list][*]on *:SOCKOPEN:sockname: {
[*]on *:SOCKREAD:sockname: {
[*]on *:SOCKCLOSE:sockname: {[/list]
The "sockname" represents the name of the socket.
[b]How do I open a socket to connect to a website?[/b]
A socket is opened with the [i]sockopen[/i] command. It works in the following way:
[quote][color=darkblue]/sockopen [-de] [bindip] <name> <address> <port>[/color]
The /sockopen command initiates a connection to the specified address and port. You can specify either an ip address or a named address (which will be resolved to an ip address).
The -d switch means that you specified an ip address as the bind address.
The -e switch creates an SSL connection.[/quote]
So, the essential components are the socket name, the address you connect to, and the port you connect on. The -de switches and the bindip are not necessary for the majority of scripts (the -e switch is explained in the "Sockets through SSL" section of this tutorial). The address will be a website (it is important to remember that the http:// before the website is [b]not[/b] needed), and the port will almost always be port 80, the standard HTTP port.
For example, if we wanted to connect to the Google homepage, we would use:
sockopen googlesock www.google.com 80
From here, the SOCKOPEN event will trigger.
[b]What do I do once I have connected to a site?[/b]
SOCKOPEN acts when the socket is initiated, and it is in this event that you need to send [b]request headers[/b]. You are already connected, but now you need to tell the webserver what information you want. To do this, you use headers which are suited to the HTTP protocol. If you want any further reading on the HTTP protocol, and what request headers can be sent, read: [url]http://en.wikipedia.org/wiki/HTTP[/url].
This is a standard example of a SOCKOPEN event:
[code]on *:SOCKOPEN:sockname: {
sockwrite -nt $sockname GET /page.html HTTP/1.1
sockwrite -nt $sockname Host: www.server.com
sockwrite -nt $sockname $crlf
}[/code]
[i] sockwrite -nt $sockname[/i] means that you are writing to the socket. -n means that a $crlf will be appended to the end of the line, and -t means that if any &'s are used, they should be treated as normal text instead of binary variables. The $sockname is referring which socket to write the data to - in this case it should be the one which it is triggering with.
The GET is called a [b]method[/b] (also sometimes called a "verb" - no idea why.) POST can also be used, but when using the POST method, you MUST send the Content Headers ([i]Content-Length: <length of sumitted data>[/i] and [i]Content-Type: application/x-www-form-urlencoded[/i] ). GET is the most common method, but POST is explained later on in this tutorial.
Now we are connected to the host, we will need to connect to the individual page which has our information on. If we wanted to connect to the Runescape homepage, for example, our command and event would look something like
[code]1. on $*:text:/^[!@](players|online)/Si:#: {
2. if ($sock(RSplay)) .sockclose RSplay
3. set %RSplayway $iif($left($1,1) == @, msg $chan, notice $nick)
4. sockopen RSplay www.runescape.com 80
}
5. on *:SOCKOPEN:RSplay: {
6. sockwrite -nt $sockname GET /lang/en/aff/runescape/title.ws
HTTP/1.1
7. sockwrite -nt $sockname Host: www.runescape.com
8. sockwrite -nt $sockname $crlf
}[/code]
1. This is the trigger. It is a normal on text event. In this case it uses some very simple regex. The [i]^[!@][/i] means it will trigger when the first character is a ! or a @. The [i](players|online)[/i] means that it will trigger when the word directly after the ! or @ is either "players", or "online".
So in effect, the triggers are:
!players
@players
!online
@online
2. This line is relatively important. It is not necessary, but it means that if the socket is left open from the last time the script was initiated, it will close before it is re-opened.
If you attempt to open a socket when it is already open, you will get the [color=darkblue]* /sockopen: 'RSplay' socket in use (line 3, script1.mrc)[/color] error message.
Alternatively, if we do not want to interrupt the socket in progress, we can message the nick of the person that triggered it and tell them that someone is already using the script - and to wait their turn! If you wanted to allow multiple people to use the script at the same time, you would have to learn how to create [b]multi-socketed[/b] scripts. (Explained later)
3. I put in this line so that depending on the way the script is executed, it will output in a different way. If it is triggered with "!", it will notice the nick that initiated it, and if it is triggered with a "@", it will message the whole channel. The way it determines is stored in the variable "%RSplayway".
4. This line will open the socket in preparation for the headers to be sent. In this case we want to connect to www.runescape.com on port 80.
5. This is the event. In this case the event is triggered when the socket "RSplay" is opened.
6. This tells the server which page we would like to get. If we wanted to connect to the titlepage, it will be /lang/en/aff/runescape/title.ws. The HTTP/1.1 should be there to let the server know which [i]protocol version[/i] to use. The current HTTP protocol version is HTTP/1.1.
7. Sends the host we wish to get the page from. Will be the same as the host/server we specified in the sockopen command.
8. Will attach an extra $crlf to the end of the data, to let the server know that is all the data we wish to send.
Now we have sent all the data, the server will get us the page we want. Once we have got the page, if all is correct, we need to READ it to know what is on it.
[b]How do you read a socket?[/b]
This is the hardest step. The data you want is somewhere on the page, and you need to find it. You need to determine which line the data is on, and once found - output it.
The server, after sending the [i]response headers[/i], will send the source of the page line-by-line. This will normally be the HTML code the page is made up of.
To see what the HTML code looks like, open the page you are connecting to in any normal web browser, right-click and select "View Source".
[b]It is important to remember, that each time the server replies with a line, the SOCKREAD event is initiated. Yes - for EVERY LINE.[/b] This will become important and is explained later on.
The format for the SOCKREAD event will look something like below:
[code]on *:SOCKREAD:socketname: {
if ($sockerr) { halt }
else {
...
}
}[/code]
If there is a socket error, the script will need to stop running. While you are testing your socket, it may be helpful to have some way of letting yourself know if you encounter a socket error. Maybe use something such as:
[code] if ($sockerr) { echo -a SOCKET ERROR: $sockerr }[/code]
The most common causes for socket errors are that the website you are trying to connect to is down, that you have connected to the page incorrectly, or have sent incorrect headers.
The "..." is where most of the code will be. Inside here we will need to find the line, and collect the data we want.
Normally there will be an "if" statement to determine if the current read is the correct line. For example, if we wanted to retrieve the number of people playing Runescape from the site we looked at earlier, the SOCKREAD event would look something like the following:
[code]1. on *:SOCKREAD:RSplay: {
2. if ($sockerr) { halt }
3. else {
4. var %sockreader
5. sockread %sockreader
6. if (There are currently * people playing!* iswm %sockreader) {
7. tokenize 32 %sockreader
8. %RSplayway At the moment, there are $4 people playing Runescape.
9. unset %RSplayway
10. sockclose RSplay
}
}
}[/code]
1. This is the event that will trigger the commands.
2. If there is a socket error, we need to halt the script. We could also add something here to tell the user that there is something wrong here as well.
3. If there isn't an error reading the socket, do the following...!
4. This will create a local variable "%sockreader"
5. This will store the line that is currently being read by the socket in the variable which we just created - %sockreader.
-------------
Up until this point, the steps are almost the same for every socket script. You will read the socket, check if there is an error, and create a variable with the data that is being read. After this, it is a case of finding the line, and getting the data.
If we have a look at the HTML of the page, we will see:
[quote="Runescape page source"]...
<img src="http://www.runescape.com/lang/en/aff/runescape/img/title2/rslogo2.gif" alt="RuneScape"><br>
[b]There are currently 202853 people playing![/b]
<iframe style="margin-top: 10px;" src="http://advert.runescape.com/lang/en/aff/runescape/banner.ws?size=728" frameborder="0" scrolling="no" width="742" height="92"
allowtransparency="true"></iframe>
...[/quote]
There is the information we want, and luckily the line it is on isn't surrounded by any HTML, which makes the process easier. In fact, we can just simply tokenise the line by the "space character", and retrieve the fourth token.
-------------
6. To check we have the correct line, we will need to use an if statement.
7. For the reason mention above, we can tokenise this line by character 32 - the "space character". Seeing as the number of players is the fourth word, it will be the fourth token
8. Now we display the output, using the variable we created earlier to determine how it should be displayed. The $4 represents the fourth token in the tokenized line.
9. It is wise to unset the variables we set to avoid clogging up the Variables tabs, and preventing conflicts.
10. Try to remember to close the socket afterwards.
[b]What is the SOCKCLOSE event for?[/b]
The SOCKCLOSE event initiates when the socket is closed by the remote connection, NOT by you using the [i]/sockclose SOCKNAME[/i] command.
I have personally hardly ever used it because it is much simpler and faster to output the data as you collect it.
[b]POST Method[/b]
[i]Kinda Advanced[/i]
This method is very similar to the GET method, described earlier, but instead of using:
[code]sockwrite -nt $sockname GET /lang/en/aff/runescape/title.ws
HTTP/1.1
sockwrite -nt $sockname Host: www.runescape.com
sockwrite -nt $sockname $crlf[/code]
We would have to use POST instead of GET, we would send the data AFTER the $crlf, and we would have to send two extra content headers:
[code] sockwrite -nt $sockname Content-Type: application/x-www-form-urlencoded
sockwrite -nt $sockname Content-Length: LENGTH OF STUFF TO SEND[/code]
The advantages of using the POST method over the GET method is that we can send much more data than through the GET method, and some sites will only allow you to use the POST method when connecting. We can also use this method to log into sites, although this requires a very good grasp of sockets.
Seeing as the data is sent after the rest of the headers, and we need to send the content headers, a good idea would be to store the data in a variable. An example, using the Google site:
[code]var %data = $+(?hl=en&q=,%searchstring,&btnI=I%27m+Feeling+Lucky)
sockwrite -nt $sockname POST /search HTTP/1.1
sockwrite -nt $sockname Host: www.google.com
sockwrite -nt $sockname Content-Type: application/x-www-form-urlencoded
sockwrite -nt $sockname Content-Length: $len(%data)
sockwrite -nt $sockname $crlf %data[/code]
[b]Sockets through SSL[/b] [i](Secure Socket Layer)[/i]
For websites which use the HTTPS (secure) protocol, we have to open the socket slightly differently.
Any site which starts with https://..... will need to use SSL when connecting to it. This is very similar to the HTTP protocol, in that exactly the same headers are sent, which can use either the POST or GET method, but the [i]sockopen[/i] command is slightly different. It would look something like this:
[code]sockopen -e SOCKNAME www.site.com 443[/code]
As you can see, the port is different for the HTTPS protocol, and we have to specify the [b]-e[/b] switch which creates an SSL connection to encrypt the data send through it. The [b]on sockopen[/b] and [b]on sockread[/b] events will be exactly the same as the normal HTTP protocol.
[b]Multi-sockets[/b]
[i]Advanced[/i]
Scripts which use one or more sockets (multi-socketed) are useful for many reasons, the main being that they allow more than one person to use the script at a time, instead of using the if ($sock(sockname)) .sockclose sockname, which will close the previous socket if it is open.
The basic principle behind them is that when you open the socket, you open a unique socket. It is important to remember that the global variables will have to be unique as well. Even if it is multi-socketed, the variables will screw up if they are the same, when they are accessed by two different sockets. Multi-sockets can be achieved in the following ways.
[list][*]Adding a random number or string to the end of the socket name and global variables
[*]Adding the user's nick, mask or channel to the end of the socket name and global variables[/list]
For example, a multi-socketed version of the Runescape Players script using a random 6 digit number is as follows:
[code]on $*:text:/^[!@](players|online)/Si:#: {
var %sckid = $right($ticks,6)
set %RSplayway. [ $+ [ %sckid ] ] $iif($left($1,1) == @, msg $chan, notice $nick)
sockopen RSplay. [ $+ [ %sckid ] ] www.runescape.com 80
}
on *:SOCKOPEN:RSplay.*: {
sockwrite -nt $sockname GET /lang/en/aff/runescape/title.ws HTTP/1.1
sockwrite -nt $sockname Host: www.runescape.com
sockwrite -nt $sockname $crlf
}
on *:SOCKREAD:RSplay.*: {
if ($sockerr) { halt }
else {
var %sockreader
sockread %sockreader
if (There are currently * people playing!* iswm %sockreader) {
tokenize 32 %sockreader
%RSplayway. [ $+ [ $right($sockname,6) ] ] At the moment, there are $4 people playing Runescape.
unset %RSplayway. [ $+ [ $right($sockname,6) ] ]
sockclose $sockname
}
}
}[/code]
May look confusing. What you are doing is in the [i]on text[/i] event, setting a local variable which is a random 6 digit string/number. This is then appended to each of the global variables, and the socket. This means that the socket it opens will be something like RSplay.482952, meaning that there is an incredibly small chance of the socket having the same name. When the SOCKREAD event occurs, the last six digits in the string are the ID, and they can be referenced with $right($sockname,6).
[b]Binary Variables (binvars)[/b]
[i]Advanced[/i]
I added this in with sockets, because this is where they are generally used.
A binary variable is a variable which is capable of storing much more information than an ordinary variable. In fact, they have no size limit. (Well, technically they can only be as big as your memory, but that's not really an issue.)
You read a socket into a binary variable by using:
[code]sockread &sockreader[/code]
This will save the line that was read by the buffer (the line of HTML), into the binvar, however large the line is, where &sockreader is the name of the binary variable. You can then use a series of commands to do something with this variable. They are explained very well in mIRC's help file, and that is definitely the best source of knowledge for binvars (/help binary variables), but I will try to explain a little more on their usage here.
When you read the line of data into the binary variable, you will need to use a similar method as with normal variables, in which you have an if statement to determine whether the data you want is in the line.
Instead of using:
[code]if (*There are currently* iswm %sockreader) {[/code]
As we would with normal variables, we will need to use something like:
[code]if ($bfind(&sockreader,1,There are currently)) {[/code]
Which will start reading from the 1st byte in the variable, and will return the position of the ASCII string "There are currently" if it matches.
Now we have identified the line, we need to read the data from the line we want. In this case, we would use the $bvar() identifier, which will output the data between a range of bytes.
[quote="mIRC Help File"]$bvar(&binvar,N,M)
Returns M ascii values starting from the Nth byte[/quote]
So, using the RS players script, the amount of players using binvars will be:
[code]$bvar(&sockreader,$bfind(&sockreader,1,There are currently),$calc($bfind(&sockreader,1,people playing!) - $bfind(&sockreader,1,There are currently))).text[/code]
Wow... seems a bit beefy, so lets break it down.
[i]$bvar(&sockreader,N,M).text[/i] - Will return the bytes between N and M, and return them in text format.
[i]$bfind(&sockreader,1,There are currently)[/i] - Will return the position in the binary file where "There are currently" starts.
[i]$bfind(&sockreader,1,people playing!)[/i] - Will return the position in the binary file where "people playing!" starts.
[i]$calc($bfind(&sockreader,1,people playing!) - $bfind(&sockreader,1,There are currently))[/i] - Will return how many bytes AFTER "There are currently", "people playing!" is. This is so that we know how many byes to read after "There are currently".
So when we put this all together, we get:
[code]$bvar(&sockreader,$bfind(&sockreader,1,There are currently),$calc($bfind(&sockreader,1,people playing!) - $bfind(&sockreader,1,There are currently))).text[/code]
So the final script should look something like:
[code]on $*:text:/^[!@](players|online)/Si:#: {
set %RSplayway $iif($left($1,1) == @, msg $chan, notice $nick)
sockopen RSplay www.runescape.com 80
}
on *:SOCKOPEN:RSplay: {
sockwrite -nt $sockname GET /lang/en/aff/runescape/title.ws HTTP/1.1
sockwrite -nt $sockname Host: www.runescape.com
sockwrite -nt $sockname $crlf
}
on *:SOCKREAD:RSplay: {
if ($sockerr) { halt }
else {
sockread &sockreader
if ($bfind(&sockreader,1,There are currently)) {
; If "There are currently" is in the binary variable...
var %RSplayers = $bvar(&sockreader,$calc($bfind(&sockreader,1,There are currently)),$calc($bfind(&sockreader,1,people playing!) - $bfind(&sockreader,1,There are currently))).text
; At the moment, %RSplayers will be: "There are currently 116594" because it is reading from the START of the string "There are currently", to the START of the string "people playing!
%RSplayway At the moment, there are $remove(%RSplayers,There are currently ) people playing Runescape.
; If we wanted to, we could use $bytes($remove(%RSplayers,There are currently ),b) to return it in a nicer format. We could also use $right(%RSplayers,$+(-,$len(There are currently ))), which will return the same result.
unset %RSplayway*
sockclose $sockname
}
}
}[/code]
Make sure to read the comments to see what is happening in the script, in the bits which involve binary variables.
There are other ways of doing binary variables, and I have made a Google script which connects to google, loops through the received buffer until it is empty, and write the whole of that buffer into a binary file. It will then loop through the binary file for the values needed, and output the results.
The advantage of using this method as opposed to the other method, is that the receive buffer is only capable of storing a maximum of 4096 bytes, which means some of the results get cut off when using the other method. Have a look at my Google Search Script in the "Further Reading" section.
[b]Using the /sockmark command[/b]
The /sockmark command is by far the most underrated command in mIRC scripting. Recently, I have found it to be a very useful command, and it is much cleaner than using variables.
Basically, you can think of a sockmark as a variable, which is unique to each socket. This makes it ideal for storing information such as the method of outputting the data (msg $chan or notice $nick), storing the value of $2-, etc etc.
The mark can store up to 512 characters, and it's usage is as follows:
[code]/sockmark SOCKNAME VALUE[/code]
The value can be anything, and if you want to store more that one piece of information, separate each bit of data with a token, and use $gettok($sock($sockname).mark,N,C) later - where N is the Nth token, and C is the token chr code.
To reference the value of the sockmark, as mentioned earlier, we use the [b].mark[/b] property of $sock:
[code]$sock(SOCKNAME).mark[/code]
Going back again to the players script, we can use the sockmark in the following way:
[code]on $*:text:/^[!@](online|players)/Si:#: {
if ($sock(RSplay)) .sockclose RSplay
sockopen RSplay www.runescape.com 80
sockmark RSplay $+($iif($left($1,1) == @, msg $chan, notice $nick),@,$nick)
}
on *:SOCKOPEN:RSplay: {
sockwrite -nt $sockname GET /lang/en/aff/runescape/title.ws HTTP/1.1
sockwrite -nt $sockname Host: www.runescape.com
sockwrite -nt $sockname $crlf
}
on *:SOCKREAD:RSplay: {
if ($sockerr) { $gettok($sock($sockname).mark,1,64) There was an error with the socket. Sorry, $gettok($sock($sockname).mark,2,64) $+ ! }
else {
var %sockreader
sockread %sockreader
if (There are currently * people playing!* iswm %sockreader) {
tokenize 32 %sockreader
$gettok($sock($sockname).mark,1,64) $gettok($sock($sockname).mark,2,64) - At the moment, there are $4 people playing Runescape.
unset %RSplayway
sockclose RSplay
}
}
}[/code]
There, that means there is no use for any global variable at all. The sockmark will look similar to the following:
[quote]msg #mIRC@Chessnut[/quote]
That's if I triggered the script on the channel #mIRC, with the nickname of Chessnut. As I said earlier, we can now use $gettok to split this sockmark up into two sections, by the character "@" (which is $chr(64). )
This means that the line:
[quote] $gettok($sock($sockname).mark,1,64) $gettok($sock($sockname).mark,2,64) - At the moment, there are $4 people playing Runescape.[/quote]
Will evaluate to:
[quote] msg #mIRC Chessnut - At the moment, there are 130353 people playing Runescape.[/quote]
[b]Deciding what data to send with the URL[/b]
Some of you might have noticed that scripts which work on user's input, will usually have a very long URL which they are socketing to, which consists of a number of names and values. For example, www.FreeTranslation.com uses the following string to connect:
[code]GET ?sequence=core&mode=html&charset=UTF-8&template=results_en-us.htm&language=LANG1/LANG2&srcText=TEXT HTTP/1.1[/code]
Now, if you have FireFox, an EXCELLENT extension for you to get is [url=https://addons.mozilla.org/firefox/966/]Tamper Data[/url]. It will automatically intercept all the headers you send to a website and display them, saving all the following steps.
The other way is very long. You need to look at the source of the page with the form on that you are socketing to. In this case, the html of the form for freetranslation.com is as followed:
[quote] <form id="frmTextTranslator" name="frmTextTranslator" method="post" action="http://ets.freetranslation.com/" onsubmit="return xl8Txt(this,true);">
<div>
<input type="hidden" name="sequence" value="core" /><input type="hidden" name="mode" value="html" /><input type="hidden" name="charset" value="UTF-8" /><input type="hidden" name="template" value="results_en-us.htm" />
<script type="text/javascript">WriteToolbar("document.frmTextTranslator.srctext",false);</script>
<select name="language" class="language" onchange="changeLanguage(this);selectItem(document.frmWebTranslator.language,this[this.selectedIndex].value);"><option value="English/Spanish">English to Spanish</option><option value="English/French">English to French</option><option value="English/German">English to German</option><option value="English/Italian">English to Italian</option><option value="English/Dutch">English to Dutch</option><option value="English/Portuguese">English to Portuguese</option><option value="English/Russian">English to Russian</option><option value="English/Norwegian">English to Norwegian</option><option value="English/SimplifiedChinese">English to Simplified Chinese</option><option value="English/TraditionalChinese">English to Traditional Chinese</option><option value="English/Japanese">English to Japanese</option><option value="Spanish/English">Spanish to English</option><option value="French/English">French to English</option><option value="German/English">German to English</option><option value="Italian/English">Italian to English</option><option value="Dutch/English">Dutch to English</option><option value="Portuguese/English">Portuguese to English</option><option value="Russian/English">Russian to English</option><option value="Japanese/English">Japanese to English</option></select><br />
<script type="text/javascript">selectItem(document.frmTextTranslator.language,getCookie('language'));</script>
<div style="clear:left"></div>
<textarea name="srctext" cols="30" rows="6" onfocus="focusField(this);">Type or paste some text here.</textarea><br />
<script src="/modules/js/special-characters.js" type="text/javascript"></script>
<div class="advanced-options-link">[<a href="http://platinum.freetranslation.com/" tabindex="-1" onclick="return trk(this,'SourceID=36');" onmouseover="window.status=s_AdvancedTranslationOptions;return true;" onmouseout="window.status=window.defaultStatus;return true;">Advanced Translation Options</a>]</div>
<div class="buttons"><input type="button" name="HumanTranslation" value="Human Translation" class="button" tabindex="-1" onclick="xl8Human(this.form,true);" /> <input type="submit" name="Submit" value="FREE Translation" class="button" style="font-weight:bold" /></div>
</div>
</form>[/quote]
The bits we are interested in are the ones with values and names (between the input/select/textarea tags). In this case:
[quote]<form id="frmTextTranslator" name="frmTextTranslator" method="post" action="[b]http://ets.freetranslation.com/[/b]" onsubmit="return xl8Txt(this,true);">
<input type="hidden" name="[b]sequence[/b]" value="[b]core[/b]" />
<input type="hidden" name="[b]mode[/b]" value="[b]html[/b]" />
<input type="hidden" name="charset" value="UTF-8" />
<input type="hidden" name="[b]template[/b]" value="[b]results_en-us.htm[/b]" />
<select name="[b]language[/b]" class="language" onchange="changeLanguage(this);selectItem(document.frmWebTranslator.language,this[this.selectedIndex].value);">
<option value="English/Spanish">English to Spanish</option><option value="English/French">English to French</option><option value="English/German">English to German</option><option value="English/Italian">English to Italian</option><option value="English/Dutch">English to Dutch</option><option value="English/Portuguese">English to Portuguese</option><option value="English/Russian">English to Russian</option><option value="English/Norwegian">English to Norwegian</option><option value="English/SimplifiedChinese">English to Simplified Chinese</option><option value="English/TraditionalChinese">English to Traditional Chinese</option><option value="English/Japanese">English to Japanese</option><option value="Spanish/English">Spanish to English</option><option value="French/English">French to English</option><option value="German/English">German to English</option><option value="Italian/English">Italian to English</option><option value="Dutch/English">Dutch to English</option><option value="Portuguese/English">Portuguese to English</option><option value="Russian/English">Russian to English</option><option value="Japanese/English">Japanese to English</option></select><br />
<textarea name="[b]srctext[/b]" cols="30" rows="6" onfocus="focusField(this);">Type or paste some text here.</textarea><br />
</form>[/quote]
Notice something familiar about the bits in bold? That's right - they are the bits of data sent with the URL.
From this, we can tell what page the form is going to (the first bolded bit) and all the names and values to send with the URL. In this case:
[code]GET ?sequence=core&mode=html&charset=UTF-8&template=results_en-us.htm&language=LANG1/LANG2&srcText=TEXT HTTP/1.1[/code]
[b]Parsers[/b]
PHP parsers are a beginner scripter's best friend. Chances are, your first few scripts will use parsers.
A parser is a PHP script that will collect data from a site, and display it in an easy to read format. An example of a parser which gets its data from the Runescape Highscores is: http://www.slushpuppy.silverinterlocution.org/rsstats.php?stats=zezima
The following is a list of all the parsers I am aware of:
Stats parsers: http://www.slushpuppy.silverinterlocution.org/rsstats.php?stats=RSNAME (Recommended), http://www.warnestuff.co.uk/stats.php?username=RSNAME , http://www.users.on.net/~adtory/stats.php?user=RSNAME
News parsers: http://www.o-ss.net/parsers/rsnews.php , http://www.mirc.ms/parsers/rsnews.php
Price parsers: http://oww.altscripts.net/parsers/price.php?i=14&c=02&m=07&i1=ITEM , http://slushpuppy.silverinterlocution.org/parsers/price.php?price=ITEM , http://www.o-ss.net/parsers/price.php?item=ITEM , http://www.mirc.ms/parsers/price.php?price=ITEM
Clan parsers: http://www.users.on.net/~adtory/clan.php?user=RSNAME , http://www.o-ss.net/parsers/clans.php?user=RSNAME
Grouphug parsers: http://code.gopzap.com/parsers/grouphug.php
Bash.org parsers: http://www.mirc.ms/parsers/bash.php
World parsers: http://www.o-ss.net/parsers/worlds.php , http://mrstk.com/genie/worlds.php , http://www.mirc.ms/parsers/world.php?world=RSWORLD
Word definition parsers: http://www.slushpuppy.silverinterlocution.org/parsers/define.php?define=WORD
Word spelling parsers: http://www.o-ss.net/parsers/spell.php?word=WORD
Pest control parsers: http://www.slushpuppy.silverinterlocution.org/pestcontrol.php?pestcontrol=RSNAME
Rank parsers: http://www.o-ss.net/parsers/ranks.php?skill=RSSKILL&rank=RANK , http://www.mirc.ms/parsers/skill.php?skill=RSSKILL&rsname=RSNAME
RS Poll parsers: http://www.o-ss.net/parsers/poll.php
RS player parsers: http://www.o-ss.net/parsers/players.php , http://www.mirc.ms/parsers/players.php
Random monster parsers: http://www.o-ss.net/parsers/monster.php?
Monster parsers: http://www.o-ss.net/parsers/monster.php?monster=MONSTER
Compare parsers: http://www.o-ss.net/parsers/compare.php?user1=RSNAME1&user2=RSNAME2&skill=SKILL
Urban parsers: http://parsers.o-ss.net/urban.php?word=WORD
Combat parsers: http://rsparsers.awardspace.com/stats.php?mode=cmb&user=RSNAME
World news parsers: http://www.o-ss.net/parsers/news.php
Feel free to contact me if you have a parser, or know of any parser, which can be added to this list.
[b]Finishing words[/b]
That's pretty much all there is to know about the basics of sockets. With a very simple example, this tutorial should have hopefully improved your understanding of sockets.
Here are a few very important things to remember about sockets:
[list][*]The SOCKREAD event will happen for EVERY line the buffer receives. This is why you should have an "if" statement in there. Without it, the script would tokenise EVERY line, then output the fourth token for EVERY line as it reads through them all. If your socket script starts spamming something, or outputs [b]HTTP/1.1 200[/b] OK or similar, chances are you have made a mistake here.
[*]It is always handy to give the variables you use in socket script, and indeed any scripts, a common prefix. For example: %google.way, %google.nick, %google.string etc etc. This will make it easier to see which variable is which in the Variables tab, and means they can all be unset at once using [i]unset %google.*[/i]
[*]If you wish to view each line the socket is receiving, which is very handy if you are having trouble finding the right line, or do not know if you are connected to the site properly, you could place the line: [i]if (%sockreader) echo -s %sockreader[/i] after the [i]sockread %sockreader[/i] command. This will output ALL of the response headers you receive into the status tab, and can be used for bug-fixing.
[*]Remember that on TEXT, on SOCKOPEN, on SOCKWRITE and on SOCKCLOSE are all separate events. To reference the second word in the on text event you can use $2, but if you want to reference that word in one of the socket events, it will have to be saved into a variable. For example:[/list]
[code] ...
sockwrite -nt $sockname http://www.google.co.uk/search?hl=en&q= $+ $2- $+ &btnG=Google+Search HTTP/1.1
... [/code]
[list]This will not be valid because $2 has no value. You should have saved $2- into a variable when the [i]on text[/i] event triggered, and used it in the SOCKOPEN event instead of the $2- shown above.[/list]
If you have any comments or questions, please feel free to post. I hope I have explained everything clearly, and I am always willing to answer any questions about this tutorial or sockets to the best of my ability.
[b]Further Reading[/b]
For more advanced reading, and details on the POST method, I suggest http://www.hawkee.com/phpBB2/viewtopic.php?t=10835
For another, equally good and very detailed mIRC socket tutorial, see Spitfire's! http://forum.swiftirc.net/viewtopic.php?p=36064
I have created a dialog script which will enable people to create their own socket scripts quickly and easily. It is brilliant to learn from and acts both as a script and a tutorial.
I strongly recommend having a look at it if you haven't already. The URL is http://forum.swiftirc.net/viewtopic.php?t=4749. In my opinion, it is a much better tutorial than this long and boring written tutorial. You can see exactly what is happening, and maybe compare the script it creates to this tutorial to find out what each step means.
I have also created a fair few scripts - some of which I have annotated to explain what I am doing step-by-step, and they work well as tutorials. Some of my published scripts are as follows:
[list][*]What's on TV Script: http://forum.swiftirc.net/viewtopic.php?t=4245
[*]Youtube Search Script: http://forum.swiftirc.net/viewtopic.php?t=3813
[*]Google Search Script: http://forum.swiftirc.net/viewtopic.php?t=5026 (Uses binvars!)
[*]Pastebin/Dialog Clipboard Uploader v0.2: http://forum.swiftirc.net/viewtopic.php?p=72744 (Uses binvars!)
[*]Artificial Intelligence Script: http://forum.swiftirc.net/viewtopic.php?t=3965 - NOT ANNOTATED
[*]Ban people not in clan: http://forum.swiftirc.net/viewtopic.php?t=3468 - NOT ANNOTATED[/list]
Good luck! Sockets may be difficult to grasp, but once you get the hang of them, there are endless possibilities.
- Chessnut[/quote]