לקוח MSN נייד – בלי לנתק את המחשב ובלי לאבד לוגים.

11 באוקטובר 2007

אחד התוספים הנפוצים ל-MSN Messenger נקרא Messenger Plus. נתקלתי לפני כשנה וחצי בתכונה נחמדה שלו – Scripting בשפת JS.
את JS אני מכיר על בוריה, ואת המימוש של ActiveX שלה גם עוד מימי עבודתי בסביבת ASP הפרה היסטורית, וכך באחד מימי שישי בתקופת הטירונות, הורדתי את ה-CHM שלהם (נמצא בתפריטים של התוכנה) שמספק נתונים סבירים על סביבת הפיתוח והתחלתי לעבוד. חיפשתי פיתרון שיאפשר לי לצ'וטט בעזרת מכשירים ניידים בלי לנתק את הבית ובלי הזמן הארוך שלוקח להתחבר.


בשלב הבא עשיתי דבר מאוד מאוד פשוט, ומאוד מאוד בסיסי:
לקחת את כל ההודעות שאני מקבל, ולזרוק אותם ל-DB כלשהו. הוספתי גם טבלאות עבור אנשי הקשר והוספתי פה ושם קוד (שלא כתוב לפי כל כללי הכתיבה התמה) שאמור לעדכן ב-DB את מצב אנשי הקשר.


function OnEvent_ChatWndReceiveMessage(ChatWnd, Origin, Message, MessageKind )
{
 var e = new Enumerator(ChatWnd.Contacts);
 for(; !e.atEnd(); e.moveNext())
 {
  var Contact = e.item();
  if (Contact.Name == Origin) Origin = Contact.Email;
 }
 if (Origin.indexOf("@")==-1) {return false;} // לא מצאנו את המשתמש משום מה
 var oConn = new ActiveXObject("ADODB.Connection");
 oConn.Open(sConn);
 oConn.Execute("insert into Messages (m_new,m_date,m_from,m_type,m_message) values (1,Now(),'"+SSQL(Origin)+"',0,'" +SSQL(Message)+"')");
 oRs = oConn.Execute("select count(m_id) from messages where m_new=1 and m_from='"+ Origin +"'");
 iNum = oRs(0)*1;
 oRs.Close(); oRs = null;
 oConn.Execute("update Contacts set c_LastMsg = Now(), c_Count = "+iNum+"  Where c_email='"+ Origin +"'");
 oConn.Close();
 oConn = null;
 aChatLastUpdate[ChatWnd.Handle] = new Date()
}

שליפה מ-DB זו לא בעיה קשה. בזמן קצר (וב- ASPX עם HTML קלאסי, למרות שאולי Mobile Web Forms היה מתאים יותר) בניתי אפליקציה שתפקידה לקרוא את הנתונים מה-DB ולהציג לפלאפון.


עכשיו נשאר לי לדאוג לכך שאוכל גם לכתוב ולא רק לקרוא.
חזרתי לסקריפט, כתבתי שם טיימר שמדי 10 שניות מתחבר לשרת ובודק אם יש הודעות בטבלה שעוד לא נשלחו, ואם כן – שישלח אותם.
בגלל מבנה ה-Messenger זה קצת יותר מורכב ממה שזה נשמע (יש שם נושא של ניהול Sessions שהם בעצם חלונות שיחה מול משתמשים) ולאחר עוד קצת זמן גם זה עבד.

function OnEvent_Timer(TimerID)
{
if (TimerID=="poll")
{

var oConn = new ActiveXObject("ADODB.Connection");
try {
oConn.Open(sConn);
}
catch(e) { MsgPlus.AddTimer("poll",10000); return false;}

var oRs = oConn.Execute("select * from Messages where m_type=1");
while(!oRs.Eof) {
var Window;
var sFrom = oRs("m_from")
var e = new Enumerator(Messenger.CurrentChats);
for(; !e.atEnd(); e.moveNext()) {
var ChatWnd = e.item();
var e = new Enumerator(ChatWnd.Contacts);
for(; !e.atEnd(); e.moveNext()) {
var Contact = e.item();
if (Contact.Email == sFrom) Window = ChatWnd;
}
}
if (Window==null) Window = Messenger.OpenChat(sFrom); // אם אין חלון שיחה פתוח
Window.SendMessage(oRs("m_message")); // שלח את ההודעה בפועל
aChatLastUpdate[Window.Handle] = new Date();
oConn.Execute("delete from Messages where m_id="+ oRs("m_id")); // מחיקת ההודעה מהדיבי
oRs.MoveNext();
}


זה עבד יפה, אבל אני רציתי קצת יותר.
רציתי גם לשלוף (ולעדכן) את המצב שלי, גם זה ישירות בדיבי
(יש כאן תמיכה באפשרות להגדיר מצבים נוספים לקנפוג מרחוק, בפועל נעשה שימוש רק באחד מהם):

oRs = oConn.Execute("select * from data where d_update=1")
while(!oRs.Eof) {
switch(oRs("d_id")*1) {
case 1:
Messenger.MyStatus = oRs("d_value");
break;
}
oRs.MoveNext();
}
oRs.Close(); oRs = null;
ובהמשך
MsgPlus.AddTimer("poll",10000);
oConn.Close(); oConn = null;
}

בפועל יש שם עוד לא מעט קוד, שמטפל בסגירה אוטומאטית של חלונות ה-Messenger שכלל ההודעות שנכתבו בהם נקראו על ידי הלקוח המרוחק, או שסתם נשארו פתוחים, או שהם של משתמשים נודניקים שאני לא רוצה/יכול לחסום, אבל זה לא רלוונטי ולכן דילגתי.

עוד כמה פונקציות:
// עדכון פרטי איש קשר, כשמתחבר/מתנתק או משנה מצב/שם:
function OnEvent_ContactSignin(Email) {ContactUpdate(Email)}
function OnEvent_ContactSignout(Email) {ContactUpdate(Email)}
function OnEvent_ContactStatusChange(Email) {ContactUpdate(Email)}
function OnEvent_ContactNameChange(Email) {ContactUpdate(Email)}

function ContactUpdate(Email)
{
var oConn = new ActiveXObject("ADODB.Connection");
oConn.Open(sConn)
var e = new Enumerator(Messenger.MyContacts);
for(; !e.atEnd(); e.moveNext())
{
var Contact = e.item();
if (Contact.Email==Email) {
var oRs = oConn.Execute("select c_id from Contacts where c_email='"+Contact.Email+"'");
if (oRs.Eof) oConn.Execute("Insert Into Contacts (c_name,c_email,c_status) values('"+SSQL(Contact.Name) +"','"+Contact.Email+"',"+Contact.Status+")");
else oConn.Execute("Update Contacts set c_name = '"+SSQL(Contact.Name) +"', c_status = "+Contact.Status+" where c_email = '"+Contact.Email+"'");
}

}
oConn.Close()
oConn = null;

}

// כניסה למערכת: עדכון כלל פרטי המשתמשים במערכת
function OnEvent_Signin(sEmail) {
var oConn = new ActiveXObject("ADODB.Connection");
oConn.Open(sConn)
var e = new Enumerator(Messenger.MyContacts);
for(; !e.atEnd(); e.moveNext())
{
var Contact = e.item();
var oRs = oConn.Execute("select * from Contacts where c_email='"+Contact.Email+"'");
if (oRs.Eof) oConn.Execute("Insert Into Contacts (c_name,c_email,c_status) \
values('"+SSQL(Contact.Name) +"','"+Contact.Email+"',"+Contact.Status+")");
else oConn.Execute("Update Contacts set c_name = '"+SSQL(Contact.Name) +"', c_status = "+Contact.Status+" where c_email = '"+Contact.Email+"'");
}
oConn.Close()
oConn = null;
}

function SSQL(str) {return str.replace(/\'/g,""")} // גרשיים עבור SQL

MsgPlus.AddTimer("poll",1000); // הפעלת הטיימר


עכשיו נשאר רק לשכתב את זה בצורה יותר נחמדה שתגרום לפחות "קפיאות" של המסנג'ר ותאפשר עבודה גם על שרתים מרוחקים – עבודה מול איזה WebService דרך XMLHTTP.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

2 תגובות

  1. Moshe L11 באוקטובר 2007 ב 20:23

    אם למישהו יש רעיון טוב איך להדביק לכאן קוד שיראה נורמלי – אשמח לשמוע.

    הגב