Twitter TweetBot

By FordLawnmower on Nov 23, 2009

Script was requested by Greggaz.

Once set up, this script will allow you and other users to update their Twitter status by typing !tweet whatever you want the update to say here. You can do this from a common channel with the bot or in PM.

Pretty simple? Well the setup is a little harder and it has to be to protect your passwords.


  • Download and install OpenSSL:
  • Paste this code to a new remote and save with a unique filename
  • From a second client Open a query window with the bot.
  • Type //say .AddAuth $encode(TwitterName:TwitterPassword,m)
  • Optionally you can type: .AddAuth TwitterName:TwitterPassword (Not Recommended)

If you have done this correct the bot will respond with a verified message.
If you did it wrong the bot will respond with the instructions till you get it right.
Keep in mind that the bot now assumes that you are typing in the query box.
Assuming you got this done, the bot will now know you by @hostname.etc. If you don't have a static ip, you will have to register again with the bot each time your ip changes.

Additional Instructions:
Type +tweet in each channel you want to allow people to !tweet in.(Requires Ops)
-tweet to stop in a channel.
There is a On/Off switch on the right click menu under TweetBot

Thanks to Amiga600 @ For not letting this script die.
Once your password is confirmed by the bot, just type !tweet update here to send your update to twitter.

;twitter TweetBot by Ford_Lawnmower #Script-Help
menu Channel,Status {
  .$iif($group(#TweetBot) == On,$style(1)) TweetBot Trigger
  ..$iif($group(#TweetBot) == On,$style(2)) On: .enable #TweetBot
  ..$iif($group(#TweetBot) == Off,$style(2)) Off: .disable #TweetBot
On $*:Text:/^[\.]AddAuth/Si:?: {
  if (!$sslready) echo -gst Error: OpenSSL is not installed. You must install OpenSSL to use this script. $&
  elseif (!$timer($+(Tweetbot,$network,$nick))) {
    .timer $+ $+(Tweetbot,$network,$nick) 1 5 noop
    if (!$2) || ($strip($2) == help) AuthError .msg $nick $nick
    else {
      var %s $strip($2), %UserInfo $iif($gettok(%s,2,58),%s,$decode(%s,m))
      twitter_get_access_token .msg $nick XxXxXxX XxXxXxX $replace(%UserInfo,$chr(58),$chr(32)) $address($nick,1)
#TweetBot on
On $*:Text:/^(\+|-|!|@)Tweet.*/Si:#,?: {
  var %action $regml(1)
  if (%action isin +-) && ($regex($nick($chan,$nick).pnick,/(!|~|&|@)/)) {
    if (%action == +) {
      if ($istok(%TweetBotChanList,$+($network,$chan),32)) { .msg $chan $nick $chan is already running the TweetBot script }
      else { 
        .enable #TweetBot
        Set %TweetBotChanList $addtok(%TweetBotChanList,$+($network,$chan),32)
        .msg $chan $nick has activated the TweetBot script for $chan .
    else {
      if (!$istok(%TweetBotChanList,$+($network,$chan),32)) { .msg $chan $nick $chan is not running the TweetBot script }
      else { 
        Set %TweetBotChanList $remtok(%TweetBotChanList,$+($network,$chan),1,32)
        .msg $chan $nick has deactivated the TweetBot script for $chan . 
  elseif (!#) || ($istok(%TweetBotChanList,$+($network,$chan),32)) {
    if (!$timer($+(TweetBot,$network,$nick))) {
      .timer $+ $+(TweetBot,$network,$nick) 1 6 noop
      if (!$2) AuthError .notice $nick $nick
      elseif ($hget(TwitterData,$address($nick,1))) tweet .notice $nick $address($nick,1) $strip($2-)
      else AuthError .notice $nick $nick
#TweetBot end
;Syntax twitter_statuses_update echo -a consumer_key consumer_secret oauth_token oauth_token_secret status update here
;Note that echo -a can be changed to msg $chan or notice $nick ( must be two words )
alias -l twitter_statuses_update {
  var %ots $ctime, %sockname $+(twitter_statuses_update,$network,$ticks,$r(1,10000)), %once $md5(%sockname)
  var %os $signature(post,,$3,$4,$5,$6,%once,%ots,$+(status=,$tuenc($7-)))
  sockopen -e %sockname 443
  sockmark %sockname $1-2 /1.1/statuses/update.json $space2comma($+(oauth_nonce=,$qt(%once)) $osmqt $+(oauth_timestamp=,$qt(%ots)) $+(oauth_consumer_key=,$qt($tuenc($consumer_key))) $&
    $+(oauth_token=,$qt($tuenc($5))) $+(oauth_signature=,$qt($suenc(%os))) $overqt) $+(status=,$tuenc($7-))
;Syntax twitter_get_access_token echo -a consumerkey consumersecret username password UserAddress
alias -l twitter_get_access_token {
  var %ots $ctime, %sockname $+(twitter_statuses_update,$network,$ticks,$r(1,10000)), %once $md5(%sockname)
  var %os $signature(post,,$3,$4,0,0,%once,%ots,$+(x_auth_mode=client_auth&x_auth_password=,$suenc($6),&x_auth_username=,$suenc($5)))
  sockopen -e %sockname 443
  sockmark %sockname $1-2 /oauth/access_token $space2comma($+(oauth_nonce=,$qt(%once)) $osmqt $+(oauth_timestamp=,$qt(%ots)) $&
    $+(oauth_consumer_key=,$qt($tuenc($consumer_key))) $+(oauth_signature=,$qt($suenc(%os))) oauth_version="1.0") $&
    $+(x_auth_username=,$suenc($5),&x_auth_password=,$suenc($6),&x_auth_mode=client_auth) $7
on *:sockopen:twitter_statuses_update*: {
  if ($sockerr) echo -st Socket Error $nopath($script)
  else {
    tokenize 32 $sock($sockname).mark
    sockwrite -n $sockname POST $3 HTTP/1.1
    sockwrite -n $sockname Host: $sock($sockname).addr
    sockwrite -n $sockname User-Agent: IRCTweet
    sockwrite -n $sockname Authorization: $+(OAuth realm=,$qt($3),$chr(44),$4)
    sockwrite -n $sockname Content-Type: application/x-www-form-urlencoded
    if ($5) {
      sockwrite -n $sockname Content-Length: $len($5)
      sockwrite -n $sockname
      sockwrite -n $sockname $5
    sockwrite -n $sockname
on *:sockread:twitter_statuses_update*: {
  if ($sockerr) { $gettok($sock($sockname).mark,1-2,32) Unknown Socket error $nopath($script) }
  else {
    var %twitter_statuses_updatevar | sockread -f %twitter_statuses_updatevar
    ;echo -gat %twitter_statuses_updatevar
    if (HTTP/1.1 401 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Password/Username Error --> %twitter_statuses_updatevar
      AuthError $gettok($sock($sockname).mark,1-2,32)
      sockclose $sockname | return
    elseif (HTTP/1.1 502 isin %twitter_statuses_updatevar) || (HTTP/1.1 503 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Server Busy Error --> %twitter_statuses_updatevar
      sockclose $sockname | return
    elseif (HTTP/1.1 500 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Server Side Error --> %twitter_statuses_updatevar
      sockclose $sockname | return      
    elseif (HTTP/1.1 403 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Connection Actively Refused --> %twitter_statuses_updatevar
      sockclose $sockname | return      
    elseif (HTTP/1.1 400 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Unknown Error --> %twitter_statuses_updatevar
      sockclose $sockname | return
    elseif (HTTP/1.1 200 isin %twitter_statuses_updatevar) {
      $gettok($sock($sockname).mark,1-2,32) Updating Status Please Wait.........
    elseif (status: 200 OK isin %twitter_statuses_updatevar) {
      if ($gettok($sock($sockname).mark,3,32) == /1.1/statuses/update.json) {
        .timer 1 3 $gettok($sock($sockname).mark,1-2,32) Your Status has been updated :)
        sockclose $sockname | return
    elseif ($regex($sockname,%twitter_statuses_updatevar,/oauth_token=(.*)&oauth_token_secret=(.*)&user_id=(.*)&screen_name=([^&]*)/)) {
      tokenize 32 $sock($sockname).mark
      var %item $iif($6,$6,$regml($sockname,4)), %key $r(1,10)
      hadd -m TwitterData %item $regml($sockname,4) $pack(%key,$encode($regml($sockname,1),m)) $pack(%key,$encode($regml($sockname,2),m)) %key
      hsave TwitterData TData.hsh
      $1-2 $regml($sockname,4) was added under record %item
      if ($2 !ischan) && ($window($2)) window -c $v1
      sockclose $sockname | return
;Syntax tweet echo -a address tweet
alias -l tweet {
  if ($hget(twitterdata,$3)) {
    var %Output $1-2, %tweet $left($4-,140)
    tokenize 32 $v1
    twitter_statuses_update %Output XxXxXxX XxXxXxX $decode($pack($4,$2),m) $decode($pack($4,$3),m) %tweet
  else $1-2 Tweet error. Unknown User.
;Syntax $signature(POST/GET,URL,consumer_key,consumer_secret,oauth_token,oauth_token_secret,oauth_nonce,oauth_timestamp,PostData)
alias -l signature {
  tokenize 32 $1-
  var %method $+($upper($1),&), %url $+($tuenc($2),&), %ck $tuenc&($+(oauth_consumer_key=,$3)), %ot $iif($5,$tuenc&($+(oauth_token=,$5)))
  var %once $tuenc&($+(oauth_nonce=,$7)), %ots $tuenc&($+(oauth_timestamp=,$8)), %post $iif($9-,$tuenc($+(&,$9-)))
  return $hmac-sha1($+($4,&,$iif($6,$6)),$+(%method,%url,%ck,%once,$tuenc&($osm),%ots,%ot,$tuenc($over),%post),$+($ticks,$r(1,1000)))
alias -l AuthError {
  $1-2 You must supply your twitter information to me in private. Syntax: .AddAuth username:password
  $1-2 You may also use the more secure method if you are using mIRC by typing in the following in MY Query window.
  $1-2 //say .AddAuth $!encode(username:password,m)
  if ($window($3)) window -c $v1
alias -l osm return oauth_signature_method=HMAC-SHA1
alias -l osmqt return oauth_signature_method="HMAC-SHA1"
alias -l over return oauth_version=1.0
alias -l overqt return oauth_version="1.0"
alias -l tuenc return $regsubex($replace($1-,+,$chr(32)),/([^a-z0-9\._-])/ig,% $+ $base($asc(\t),10,16,2))
alias -l tuenc& return $tuenc($+($1,&))
alias -l suenc return $regsubex($1-,/([^a-z0-9\._-])/ig,% $+ $base($asc(\t),10,16,2))
alias -l space2comma return $replace($1-,$chr(32),$chr(44))
alias -l consumer_key return $decode($pack(3,gF7{f[MrbFoLRik@WhkLZV2wP3F>),m)
alias -l pack {
  var %up $1
  return $regsubex($2-,/(.)/g,$chr($xor(%up,$asc(\t))))
;Syntax hmac-sha1 key message or $hmac-sha1(key,message,filename)
alias  -l hmac-sha1 {
  if (!$file($mircdirhmacsha1/signature.exe)) {
    echo -gst *Error* Missing signature application! Attempting to download....
  else {
    var %file $qt($+($mircdirhmacsha1/,$3))
    .remove %file
    run -np $mircdirhmacsha1/signature.exe $1-
    var %count 1
    if ($file(%file).size != 28 && %count < 150000) {
      inc %count
      goto check
    else {
      var %return $read(%file)
      .remove %file
      $iif($isid,return,echo -a) %return
On *:start: {
  if (!$isfile($qt($mircdirhmacsha1/signature.exe))) GetsignatureApp
  if (!$sslready) echo -gst Error: OpenSSL is not installed. You must install OpenSSL to use TweetBot. $&
  hmake TwitterData 5
  if ($exists(TData.hsh)) hload TwitterData TData.hsh
On *:unload: {
  if ($hget(TwitterData)) hfree $v1
  if ($exists(TData.hsh)) .remove TData.hsh
  if ($exists($mircdirhmacsha1\signature.exe)) .remove $mircdirhmacsha1\signature.exe
  if ($isdir($mircdirhmacsha1)) .rmdir $mircdirhmacsha1
alias GetsignatureApp GetApp /signature $nospace($mircdirhmacsha1\) signature.exe
alias -l GetApp {
  echo -gat Downloading App. Please wait........
  var %dir $nospace($3)
  if ($isfile($qt($+(%dir,$4)))) { .remove $qt($+(%dir,$4)) }
  var %sockname $+(Get.App,$ticks,$r(1,$ticks))
  if (!$isdir($qt(%dir))) { mkdir $qt(%dir) }
  sockopen %sockname $1 80
  sockmark %sockname $1-
On *:sockopen:Get.App*:{
  sockwrite -nt $sockname GET $gettok($sock($sockname).mark,2,32) HTTP/1.0
  sockwrite -n $sockname Host: $+($gettok($sock($sockname).mark,1,32),$str($crlf,2))
  .fopen -o $gettok($sock($sockname).mark,4,32) $qt($+($nospace($gettok($sock($sockname).mark,3,32)),$gettok($sock($sockname).mark,4,32)))
On *:sockread:Get.App*:{
  if (!$gettok($sock($sockname).mark,5,32)) {
    var %GetApp | sockread -f %GetApp
    if (!%GetApp) { sockmark $sockname $sock($sockname).mark 1 }
  else {
    sockread -f &GetApp
    .fwrite -b $gettok($sock($sockname).mark,4,32) &GetApp
On *:sockclose:Get.App*: {
  if (!$sockerr) { 
    .timer 1 3 echo -gat Download Complete!
    .timer 1 4 .fclose $gettok($sock($sockname).mark,4,32)
alias -l nospace {
  if ($chr(7) isin $1-) return $replace($1-,$chr(7),$chr(32))
  else return $replace($1-,$chr(32),$chr(7))


Sign in to comment.
Cheiron   -  Jul 14, 2014

Script wont work for us... have followed the instructions and stuff.. we have got the +tweet , -tweet working.. but it wont recognise the //say .AddAuth $encode(TwitterName:TwitterPassword,m) command and locks the bot clean up

  • Invalid format: $iif (line 14, twitter2.ini)
    var %s $strip($2), %UserInfo $iif($gettok(%s,2,58),%s,$decode(%s,m))
FordLawnmower  -  Jul 27, 2014

@Cheiron : I would guess that you have $decode disabled in your bots settings.
Look under Tools->Options->Other->Lock and see if decode is disabled.

Sign in to comment

Unova Zeus   -  Jul 14, 2014

@FordLawnmower I Have Been Reported As Abusing In My Server By Other Users For Using This Script Becz When They Use This Command: //say .AddAuth $encode(TwitterName:TwitterPassword,m)
their pass and username is been noticing to me by my bot ??/ help me with this script plz :) !

FordLawnmower  -  Jul 27, 2014

@Unova Zeus : This will show the encoded info in your bots pm. It will not show the pass and username.

Sign in to comment

FordLawnmower   -  Jun 14, 2014


MashhitDK   -  Nov 11, 2013

Just wanted to say thanks... am gonna test this later on <3

I keep getting error / /run: unable to open file 'location goes here' (line 173, Twitter.mrc)
Checked the path to make sure it was there which it was... so can't locate the problem ?

Grimnir   -  Jun 13, 2013

Tweeting from the bot?
I am having difficulty figuring out how to tweet directly from the bot, I was able to do it under the old version of the script using this
"alias quick_update twitter_statuses_update echo -a $consumer_key $consumer_secret $oauth_token $oauth_token_secret $1-"
That doesn't seem to work any more

FordLawnmower  -  Jun 13, 2013

I think this is the script you need @Grimnir

SquigY0  -  Sep 07, 2014

Does the script that you linked here no longer work? Looks like consumer key and oauth are called something different in the apps dev screen now

Sign in to comment

PackardBell   -  Jun 13, 2013

@FordLawnmower ; twitter got's this api. But does Facebook also has one?
cause the only FB-scripts are for personal use (without the .addauth ... )

FordLawnmower   -  Jun 09, 2013

Updated to comply with the new Twitter api 1.1
I also found a bug that was causing 401 Unauthorized. I had no url encoding on passwords, so if they had special characters it generated a 401.

PackardBell  -  Jun 10, 2013

tried the new script:
[10/06/13|13:25:15] Password/Username Error --> HTTP/1.1 401 Unauthorized
[10/06/13|13:25:15] You must supply your twitter information to me in private. Syntax: .AddAuth username:password
[10/06/13|13:25:15] You may also use the more secure method if you are using mIRC by typing in the following in MY Query window.
[10/06/13|13:25:15] //say .AddAuth $encode(username:password,m)

still won't work @FordLawnmower

FordLawnmower  -  Jun 11, 2013

I've tested this with no issues @PackardBell . Did you follow the instructions ?

PackardBell  -  Jun 12, 2013

yeah, if finally works. :) Thx a lot!

RicJames  -  Jun 12, 2013

How did you get it to work? I'm getting the same error. My password has a ! in it.

FordLawnmower  -  Jun 12, 2013

@RicJames . I have tested the script with ! in passwords, with no issues.
Are there any other special characters in your password or username ?
Did you follow the instructions ?

RicJames  -  Jun 13, 2013

I followed the instructions 100%, the only other thing is some numbers.

PackardBell  -  Jun 13, 2013

A friend of mine tried it today. He kinda failed with the $encode shizzle. But it works.
1 remark: try change your name with twittername and check out ;)

FordLawnmower  -  Jun 13, 2013

@PackardBell . I'm not sure what you are talking about. You have to use your real twitter screenname to authenticate.
It's not possible to change your screenname.

FordLawnmower  -  Jun 13, 2013

@RicJames . There are no issues with numbers in passwords. I need something more to go on to help you.
Are you using a old version of mIRC ?
Do you still have an old version of this script loaded ?
Have you tried loading the script to a clean mIRC, with no other scripts ?

PackardBell  -  Jun 13, 2013

@FordLawnmower I know you can't change it. But some people mix them up while trying to auth.

FordLawnmower  -  Jun 13, 2013

I understand you now :)

RicJames  -  Jun 13, 2013

I tried it with another clean mirc and it worked. I guess that means one of my snippet's is conflicting with the process. Any idea what kind of script would cause the conflict?

FordLawnmower  -  Jun 13, 2013

I would guess that it's another version of this same script @RicJames .
Try searching from the scripts editor for twitter_statuses_update . Check the box that says "Search all files in this section"
If you have more than one file using sockets with this name, it will cause a problem.
mIRC will use the one that was loaded first.

Sign in to comment

FordLawnmower   -  Dec 24, 2012

Updated to fix a bug, when used on mIRC versions older than 7

RicJames   -  Nov 14, 2012

(15|Nov 3:29:37pm) .AddAuth XXXXaGljYWxGcmVlZG9tOk15xxxxxxxx=
(15|Nov 3:29:50pm) Password/Username Error --> HTTP/1.1 401 Unauthorized
(15|Nov 3:29:53pm) You must supply your twitter information to me in private. Syntax: .AddAuth username:password
(15|Nov 3:29:55pm) You may also use the more secure method if you are using mIRC by typing in the following in MY Query window.
(15|Nov 3:29:58pm) //say .AddAuth $encode(username:password,m)

RicJames   -  Nov 14, 2012

@FordLawnmower Yep I tried it with the m and still the same result.

FordLawnmower   -  Nov 13, 2012

@RicJames Are you you typing the command like this?

//say .AddAuth $encode(TwitterName:TwitterPassword,m)

The original instructions were missing the ",m"

RicJames   -  Nov 13, 2012

@FordLawnmower Yes. I tried the troubleshooting steps you suggested above but none seem to work.

FordLawnmower   -  Nov 10, 2012

@RicJames At what point are you getting this error ? .Addauth ?

RicJames   -  Nov 09, 2012

@FordLawnmower I keep getting Password/Username Error --> HTTP/1.1 401 Unauthorized any ideas on how to fix?

FordLawnmower   -  Oct 16, 2012

Thanks for noticing it was broken NwoChat. I use these scripts , but I use a version I made with php. I call it through loopback and I had already added /1/ to it. I would have never noticed it was broken.

NwoChat   -  Oct 16, 2012

Thanks Ford for putting this together, and the other one... I was able to figure out I missed changing it in every location needed! :)

FordLawnmower   -  Oct 15, 2012


FordLawnmower   -  Oct 15, 2012

Thanks for the info Hawkee. I didn't notice this was broken. I will update it right away.

NwoChat   -  Oct 12, 2012

Thanks Hawkee, I looked at this and in my troubleshooting last night I actually did manage to change it to that.

However am now getting: Password/Username Error --> HTTP/1.1 401 Unauthorized

I checked my system time as I remember that being an issue in the past and I pretty sure my time is not off on the computer.

Hawkee   -  Oct 12, 2012

Twitter recently changed their URLs, so you'll need to update every API URL. Basically you need to add /1/ after and make sure you're using So,

will become this:

NwoChat   -  Oct 12, 2012

I'm having the same problem as Steak... I ended up finding the old script and using that, but now that won't work either. :(

Getting 401 error, and no context options to add tweetmaster etc.

steak   -  Apr 21, 2012

Not sure if this script is still active but I tried it yesterday and loved it. It worked like a charm. Coming in today it worked once and now it keeps wanting to authenticate. I re authenticated and even reloaded the script, nothing. Every time it returns: Password/Username Error --> HTTP/1.1 401 Unauthorized. Any thoughts?

PS. I don't get the fancy context options when right clicking on a user either. I guess that feature is no longer implemented.

FordLawnmower   -  Oct 09, 2011

Your point is well taken ^WeSt.
I added a unload event to remove left over files.
If you explain your problem with the .Addauth command I will try to help.

^WeSt   -  Oct 09, 2011

Yes but if the unload is from the SE menu it is good to add this event to remove the extra files!

Jethro   -  Oct 08, 2011

^WeSt, the on unload event won't do a thing if people don't manually unload a script.

^WeSt   -  Oct 08, 2011

.Addauth does not working on me! also recomment to add an ON UNLOAD event to remove all the download files and variables that used if used!

hxck   -  Oct 07, 2011

Thanks for this one Ford, works like a charm. :)

FordLawnmower   -  May 12, 2011

@Aha2Y Please try the edited code at the top. I made a small change to prevent regional issues with timestamps.

FordLawnmower   -  May 12, 2011

@Aha2Y This isn't outdated. I use this script every day. Just tested again with a clean paste into mIRC 7.17 on Win7 x86 & XP Service Pack 2, mIRC 6.35 on Win7 x86, and mIRC 7.19 on OpenSuse 11.3 w/wine.
Many things can cause the 401 error. 1st check your mIRC settings. Tools->Options->Other->Lock: Make sure "decode" and "Run" are NOT disabled.
Another issue that could cause this is an invalid timestamp. This script uses $gmt but it is only correct if your system clock is set correctly. Twitters api is picky about this , so it is better if you change your time settings to automatically update with a time server.
If none of this helps you, please post back here and include your Operating system type. Please specify 32 or 64 bit.

Jordyk19   -  May 12, 2011

Script outdated.

21:00:28 Password/Username Error --> HTTP/1.1 401 Unauthorized

100% sure that i filled it right.

Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.