'
' Now this was fun to program! Created in only 2 and a half hours, fast! As it should be.
'
' Update your Twitter account using this nice tool. Remembers username and password.
'
' Peter van Eerten, March 2010 - GPL. Needs HUG 0.21 or higher.
'
' Version 1.0: initial release
' Version 1.1: show remaining characters instead of length of message - July 2010.
'---------------------------------------------------------------------------------------------------------------------------
CONST BASE64$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
SETENVIRON "LANG", "C"
INCLUDE "hug.bac"
'---------------------------------------------------------------------------------------------------------------------------
' Function to setup basic HTTP encoding - ripped from myself :-)
FUNCTION Base64_Encode$(STRING data$)
LOCAL enc$
LOCAL byte1, byte2, byte3, base1, base2, base3, base4
WHILE LEN(data$) > 0 DO
' Find ASCII values
IF LEN(data$) EQ 1 THEN
byte1 = ASC(MID$(data$, 1, 1))
byte2 = 0
byte3 = 0
ELIF LEN(data$) EQ 2 THEN
byte1 = ASC(MID$(data$, 1, 1))
byte2 = ASC(MID$(data$, 2, 1))
byte3 = 0
ELSE
byte1 = ASC(MID$(data$, 1, 1))
byte2 = ASC(MID$(data$, 2, 1))
byte3 = ASC(MID$(data$, 3, 1))
ENDIF
' Create Base64 values
base1 = byte1 / 4
base2 = (byte1 & 3) * 16 + (byte2 & 240) / 16
base3 = (byte2 & 15) * 4 + (byte3 & 192) / 64
base4 = byte3 & 63
' Find Base64 characters
IF LEN(data$) EQ 1 THEN
enc$ = CONCAT$(enc$, MID$(BASE64$, base1 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base2 + 1, 1))
enc$ = CONCAT$(enc$, "==")
data$ = ""
ELIF LEN(data$) EQ 2 THEN
enc$ = CONCAT$(enc$, MID$(BASE64$, base1 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base2 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base3 + 1, 1))
enc$ = CONCAT$(enc$, "=")
data$ = ""
ELSE
enc$ = CONCAT$(enc$, MID$(BASE64$, base1 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base2 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base3 + 1, 1))
enc$ = CONCAT$(enc$, MID$(BASE64$, base4 + 1, 1))
data$ = RIGHT$(data$, LEN(data$) - 3)
ENDIF
WEND
RETURN enc$
END FUNCTION
'---------------------------------------------------------------------------------------------------------------------------
' Make sure not to exceed 140 characters
SUB Check_Length
LOCAL content$
content$ = GRAB$(update_txt)
IF LEN(content$) > 140 THEN
content$ = MID$(content$, 1, 140)
TEXT(update_txt, "")
TEXT(update_txt, content$)
END IF
TEXT(amount_label, CONCAT$("Remaining characters: ", STR$(140 - LEN(content$))))
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Should password field be visible
SUB Toggle_Visible
SET(pass_entry, GET(vis_chk))
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Update the Twitter account
SUB Upload_Content
LOCAL text$, http$, len$, data$, response$
text$ = CONCAT$("status=", GRAB$(update_txt))
len$ = STR$(LEN(text$))
' Create the HTTP request
http$ = CONCAT$("POST /1/statuses/update.xml HTTP/1.1\r\nAuthorization: Basic ", Base64_Encode$(CONCAT$(GRAB$(name_entry), \
":", GRAB$(pass_entry))), "\r\nUser-Agent: BaCon Twitter Client\r\nHost: api.twitter.com\r\nAccept: */*\r\nContent-Length: ", \
len$, "\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n", text$)
OPEN "api.twitter.com:80" FOR NETWORK AS twitter
SEND http$ TO twitter
REPEAT
RECEIVE data$ FROM twitter
response$ = CONCAT$(response$, data$)
SYNC
UNTIL ISFALSE(WAIT(twitter, 500)) OR LEN(data$) IS 0
CLOSE NETWORK twitter
IF INSTR(response$, "Status: 200 OK") THEN
TEXT(update_txt, "")
SHOW(infodlg)
ELSE
SHOW(errdlg)
END IF
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Closes info dialog
SUB Close_Dialog(NUMBER widget)
HIDE(widget)
FOCUS(update_txt)
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Get account info
SUB Get_Data
LOCAL config TYPE FILE*
LOCAL text$
IF FILEEXISTS(CONCAT$(GETENVIRON$("HOME"), "/.twitter.txt")) THEN
OPEN CONCAT$(GETENVIRON$("HOME"), "/.twitter.txt") FOR READING AS config
READLN text$ FROM config
TEXT(name_entry, text$)
READLN text$ FROM config
TEXT(pass_entry, text$)
CLOSE FILE config
END IF
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Save account info
SUB Program_Quit
LOCAL config TYPE FILE*
OPEN CONCAT$(GETENVIRON$("HOME"), "/.twitter.txt") FOR WRITING AS config
WRITELN GRAB$(name_entry) TO config
WRITELN GRAB$(pass_entry) TO config
CLOSE FILE config
QUIT
END SUB
'---------------------------------------------------------------------------------------------------------------------------
' Main program
' Create main window
win = WINDOW("Twitter Updater", 400, 300)
' Account field
frame1 = FRAME(390, 110)
ATTACH(win, frame1, 5, 5)
TEXT(frame1, " Account ")
name_label = MARK("Username: ", 70, 30)
ATTACH(win, name_label, 15, 30)
name_entry = ENTRY("", 290, 30)
ATTACH(win, name_entry, 95, 30)
pass_label = MARK("Password: ", 70, 30)
ATTACH(win, pass_label, 15, 70)
pass_entry = PASSWORD(200, 30)
ATTACH(win, pass_entry, 95, 70)
vis_chk = CHECK("Visible", 70, 30)
ATTACH(win, vis_chk, 305, 70)
' See if configfile exists
Get_Data
' Update field
frame2 = FRAME(390, 120)
ATTACH(win, frame2, 5, 125)
TEXT(frame2, " Update ")
update_txt = EDIT(370, 80)
ATTACH(win, update_txt, 15, 150)
amount_label = MARK("Remaining characters: 140", 180, 30)
ATTACH(win, amount_label, 110, 255)
' Buttons
send_btn = STOCK("gtk-save", 85, 35)
ATTACH(win, send_btn, 5, 255)
quit_btn = STOCK("gtk-quit", 85, 35)
ATTACH(win, quit_btn, 310, 255)
' Dialogs
errdlg = MSGDIALOG("The account could not be updated!", 250, 120, 3, 2)
infodlg = MSGDIALOG("Twitter updated!", 270, 120, 0, 2)
' Callbacks
CALLBACK(quit_btn, Program_Quit)
CALLBACK(update_txt, Check_Length)
CALLBACK(vis_chk, Toggle_Visible)
CALLBACK(send_btn, Upload_Content)
CALLBACK(errdlg, Close_Dialog)
CALLBACK(infodlg, Close_Dialog)
IF LEN(GRAB$(name_entry)) > 0 THEN FOCUS(update_txt)
ELSE FOCUS(name_entry)
' Endless GTK loop
DISPLAY