۱۳۸۷/۰۸/۲۶

بررسي جزئيات برنامه نويسي افزونه تاريخ فارسي براي outlook 2007 - قسمت اول


قبل از شروع بحث، سورس كامل پروژه را از اينجا دريافت كنيد (يك پروژه VSTO از نوع outlook add-in در VS.Net 2008 SP1).

توضيحات مربوطه را به دو قسمت تقسيم كرده‌ام. قسمت اول يافتن تاريخ‌هاي sent و فارسي كردن آنها و قسمت بعدي نحوه اضافه كردن يك ستون و مقدار دهي آن (در روزي ديگر).

متن ايميل‌هاي دريافتي در آوت‌لوك‌هاي جديد عموما به دو فرمت HTML و يا RichText دريافت مي‌شوند. حالت‌هاي ديگري هم مانند plain و unspecified هم موجود هستند كه حتي اگر ايميلي را به صورت plain ارسال نمائيد، با فرمت RichText نمايش داده خواهد شد (بنابراين بر اساس آزمايشات من بررسي اين دو فرمت كفايت مي‌كند).

براي اينكه قسمت‌هاي sent را پيدا كنيم در ابتدا بايد سورس صفحه را بررسي نمائيم (كليك راست و view source).
در حالت فرمت HTML داريم:

<p class=MsoNormal><b><span style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'>From:</span></b><span
style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'> Nasiri, Vahid <br>
<b>Sent:</b> <span lang=AR-SA dir=RTL>our date goes here</span><br>
<b>To:</b> xyz<br>
<b>Subject:</b> our subject<o:p></o:p></span></p>


و در حالت ايميل‌هاي RichText خواهيم داشت:

From: tst@tst.net<br>
Sent:<span lang=AR-SA dir=RTL>our date goes here</span><br>
To: Nasiri, Vahid<br>
Subject: <span lang=AR-SA dir=RTL>xyz</span><br>

خوب، براي پيدا كردن عبارت تاريخ قسمت sent چه بايد كرد؟ (our date goes here در اينجا)
استفاده از روش‌هاي متداول كار با رشته‌ها در اينجا به علت انبوهي از تگ‌هاي HTML اصلا مقرون به صرفه نيست و كند خواهد بود. خوشبختانه با وجود كتابخانه regular expressions در دات نت، پيدا كردن عباراتي كه از يك الگوي خاص پيروي مي‌كنند به سادگي و با سرعت بسيار بالايي قابل انجام است.
پيشنهاد من براي دو فرمت بالا به صورت زير بوده: (شايد شما الگوي ديگري را يافتيد، زيبايي اوپن سورس :))

private const string REGEXHTMLPATTERN = @"(?s)>\s(.+?)<br>";
private const string REGEXPLAINTEXTPATTERN = "(?s)Sent:(.+?)<br>";

براي مثال در حالت دوم هر چيزي كه بين sent و br قرار مي‌گيرد در كل متن بررسي خواهد شد (با استفاده از MatchCollection فضاي نام System.Text.RegularExpressions). در اينجا اگر Convert.ToDateTime آن عبارت موفق بود يعني تاريخ قابل تبديل است (البته قبل از تبديل تمام تگ‌هاي HTML احتمالي هم تميز خواهند شد) و ما آنرا با استفاده از تابع DateTimeToFarsiStr در كلاس cDate به نمونه شمسي تبديل كرده (لطفا به سورس برنامه مراجعه كنيد) و نهايتا آنرا در متن جايگزين مي‌كنيم.
سرعت استفاده از RegularExpressions فوق العاده بالا است و براي نمونه در ايميلي با بيش از 20 ريپلاي در كسري از ثانيه كل اين عمليات انجام خواهد شد.

تا اينجا بررسي كلي الگوريتم مورد استفاده قسمت اول به پايان مي‌رسد.

بيشترين وقتي كه در اين پروژه صرف شد نحوه پيدا كردن شيء MailItem جاري باز شده با استفاده از رخدادهاي آوت‌لوك بود (مدت مديدي را براي اين مورد وقت گذاشتم! چون عملا در هيچ كتابي به اين مباحث پرداخته نمي‌شود و بايد كل نت را زير و رو كرد). دو مورد را بايد بررسي كرد. الف) inspector ها (صفحه‌اي كه جهت ايجاد يك ايميل جديد يا ريپلاي به ايميل جاري باز مي‌شود، inspector نام دارد) ب) ActiveExplorer ها (صفحه‌اي كه ليست ايميل‌ها را نمايش مي‌دهد و اين صفحه مي‌تواند در فولدرهاي مختلفي كه شما ايجاد كرده‌ايد نيز نمايش داده شود بنابراين بررسي inbox به تنهايي كافي نيست)
نحوه ايجاد اشياء مربوطه و تحت نظر قرار دادن آنها را در روال ThisAddIn_Startup فايل ThisAddIn.cs مي‌توانيد مشاهده نمائيد. نكته مهمي كه اينجا وجود دارد، تعريف اين اشياء در سطح كلاس است. در غيراينصورت با اولين خانه تكاني garbage collector ، اشياء شما (بدليل نبود ارجاعي فعال به آنها) معدوم خواهند شد(!) و ديگر روال‌هاي رخداد گردان تعريف شده كار نخواهند.