дурак: условный формат даты в “index_format”

Можно использовать openssl для этого (и для других хеш-алгоритмов):

 $ openssl list-message-digest-commands
md4
md5
mdc2
rmd160
sha
sha1

 $ openssl rmd160 /usr/bin/openssl 
RIPEMD160(/usr/bin/openssl)= 788e595dcadb4b75e20c1dbf54a18a23cf233787
14
06.12.2013, 00:36
6 ответов

Если Вы используете версию "разработки" дурака (v1.5 +) - и Вы абсолютно должны - существует возможность использовать внешний фильтр, как описано в руководстве.

Сначала Вам нужен сценарий, который может произвести разные вещи согласно возрасту сообщения. Вот пример в Python:

#!/usr/bin/env python
"""mutt format date

Prints different index_format strings for mutt according to a
messages age.

The single command line argument should be a unix timestamp
giving the message's date (%{}, etc. in Mutt).
"""

import sys
from datetime import datetime

INDEX_FORMAT = "%Z {} %?X?(%X)&   ? %-22.22F  %.100s %> %5c%"

def age_fmt(msg_date, now):
    # use iso date for messages of the previous year and before
    if msg_date.date().year < now.date().year:
        return '%[%Y-%m-%d]'

    # use "Month Day" for messages of this year
    if msg_date.date() < now.date():
        return '%10[%b %e]'

    # if a message appears to come from the future
    if msg_date > now:
        return '  b0rken'

    # use only the time for messages that arrived today
    return '%10[%H:%m]'

if __name__ == '__main__':
    msg_date = datetime.fromtimestamp(int(sys.argv[1]))
    now = datetime.now()
    print INDEX_FORMAT.format(age_fmt(msg_date, now))

Сохраните это как mutt-fmt-date где-нибудь на Вашем ПУТИ.

Две вещи важны здесь:

  • Строка формата должна содержать одно происшествие {} который заменяется возвращаемым значением age_fmt() Python.
  • Строка формата должна закончиться a % так, чтобы Дурак интерпретировал его.

Затем можно использовать его в Вашем .muttrc следующим образом:

set index_format="mutt-fmt-date %[%s] |"

Дурак будет затем

  1. интерпретировать %[%s] согласно правилам для строк формата.
  2. звонить mutt-fmt-date с результатом 1. как аргумент (из-за | в конце).
  3. интерпретируйте то, что это возвращает из сценария как строка формата снова (из-за % в конце).

Протест: сценарий будет выполняться для каждого сообщения, которое должно быть о быть отображенным. Получающаяся задержка может быть довольно noticable при просмотре почтового ящика.

Вот версия в C, который работает несколько соответственно:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define DAY (time_t)86400
#define YEAR (time_t)31556926

int main(int argc, const char *argv[]) {
    time_t current_time;
    time_t message_time;

    const char *old, *recent, *today;
    const char *format;

    current_time = time(NULL);

    if (argc!=6) {
        printf("Usage: %s old recent today format timestamp\n", argv[0]);
        return 2;
    }

    old = argv[1];
    recent = argv[2];
    today = argv[3];

    format = argv[4];

    message_time = atoi(argv[5]);

    if ((message_time/YEAR) < (current_time/YEAR)) {
        printf(format, old);
    } else if ((message_time/DAY) < (current_time/DAY)) {
        printf(format, recent);
    } else {
        printf(format, today);
    }

    return 0;
}

Это сочетается с muttrc строкой:

set index_format='mfdate "%[%d.%m.%y]" "%8[%e. %b]" "%8[%H:%m]" "%Z %%s %-20.20L %?y?[%-5.5y]&       ? %?M?+& ?%s%%" "%[%s]" |'
16
27.01.2020, 19:50
  • 1
    у меня не было времени для отладки этого все же, но там, кажется, проблема с этим решением и предметами, которые содержат знак %. Патчи ценились бы! –   10.10.2014, 02:41
  • 2
    я создал щедрость. У Вас есть какие-либо идеи, как исправить ошибку? –  Martin Vegter 30.04.2017, 13:56

К сожалению, это, кажется, не возможно с текущими версиями Дурака.

$index_format поддерживает определенный набор спецификаторов формата, тянущих из различных метаданных сообщения. Это описано в руководстве Дурака (или вот документация "стабильной" версии для того же), и как Вы видите от таблицы, существует только несколько спецификаторов формата, которые являются условным выражением. Это %M, %y и %Y; %M является количеством скрытых сообщений, если поток сворачивается, и %y и %Y являются заголовками X-маркировки если существующий.

Фактическое форматирование даты и времени сообщения сделано strftime(3), который не поддерживает условное форматирование вообще.

Могло бы быть возможно сделать ужасное обходное решение путем непрерывной перезаписи файлов сообщений Date: заголовки, но я не хотел бы делать это, по крайней мере. Однако это - наименее плохая возможность, что я могу думать.

Единственное действительное решение, о котором я могу думать, состояло бы в том, чтобы или реализовать такую поддержку в Дураке (который почти наверняка является, как Thunderbird делает это), или запишите замену strftime который поддерживает условное форматирование, и введите то использование LD_PRELOAD или подобный механизм. Последний, однако, будет влиять на весь дисплей даты и времени в Дураке, который проходит strftime, не только касающийся индекса сообщения.

7
27.01.2020, 19:50
  • 1
    При использовании версии 1.5 + (который Вы абсолютно должны), существует путь. Предложение перезаписи заголовков даты весело, хотя … –   28.01.2014, 21:33
  • 2
    @hop FWIW, Ваш ответ получил мой upvote. –  a CVn 13.05.2014, 23:44

Внесены некоторые изменения, но не решена проблема "% в теме"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define DAY (time_t)86400
#define WEEK (time_t)604800
#define MONTH (time_t)2678400
#define YEAR (time_t)31556926

/*I use this line in .muttrc: 
 * set index_format        = '/home/marcus/.mutt/mfdate "%9[%d.%m.%y]" "%9[%e.%b]" " [%6[%e.%b]]" "%8[%a %H:%m]" "    %[%H:%m]" "%Z %%s %?X?%2X&  ? %-20.20L %?M?+%-2M&   ? %.86s %> [%4c]asladfg" "%[%s]" |'*/
int main(int argc, const char *argv[]) {
    time_t current_time;
    time_t message_time;
    struct tm *ltime;
    unsigned int todays_seconds=0;
    unsigned int seconds_this_morning=0;


    const char *last_year, *this_year, *last_months, *last_week, *today;
    const char *format;

    current_time = time(NULL);
    ltime = localtime(&current_time);
    todays_seconds = ltime->tm_hour*3600 + ltime->tm_min*60 + ltime->tm_sec;
    seconds_this_morning = current_time - todays_seconds;

    if (argc!=8) {
        printf("Usage: %s last_year this_year today format timestamp\n", argv[0]);
        return 2;
    }

    last_year    = argv[1];
    this_year    = argv[2];
    last_months  = argv[3];
    last_week    = argv[4];
    today        = argv[5];

    format       = argv[6];

    message_time = atoi(argv[7]);

    /*
     *if ((message_time+YEAR) < current_time) {
     *    printf(format, last_year);
     *} else if ((message_time+MONTH) < current_time) {
     *    printf(format, this_year);
     *} else if ((message_time+WEEK) < current_time) {
     *    printf(format, last_months);
     *} else if ((message_time+DAY) < current_time) {
     *    printf(format, last_week);
     *} else {
     *    printf(format, today);
     *}
     */

    if ((message_time/YEAR) < (current_time/YEAR)) {
        printf(format, last_year);
    } else if ((message_time/MONTH) < (current_time/MONTH)) {
        printf(format, this_year);
    } else if ((message_time + WEEK) < current_time) {
    /*} else if ((message_time/DAY) < (current_time/DAY)) {*/
        printf(format, last_months);
    /*
     *} else if ((message_time+DAY) < current_time) {
     *    printf(format, last_week);
     */
    } else if ((message_time ) < seconds_this_morning) {
        printf(format, last_week);
    } else {
        printf(format, today);
    }

    return 0;
}
3
27.01.2020, 19:50

По какой-то причине более новые версии mutt (1.7 показали эту проблему) префикс строки даты с символами '14' и '32', которые не позволяют atoi преобразовывать строка в int. Изменение строки на

message_time = atoi(2+argv[7]);

Возможно, глупое решение, но у меня оно работает.

4
27.01.2020, 19:50

Немного отредактирована версия @Marcus c (до сих пор нет решения для % в теме вопроса):

// -*- coding:utf-8-unix; mode:c; -*-
/*
    Sets mutt index date based on mail age.

build:
    gcc mutt-index-date-formatter.c -o mutt-index-format
use this line in .muttrc:
    set index_format = 'mutt-index-format "%9[%d.%m.%y]" "%9[%e.%b]" "%8[%a %H:%m]" "%[%H:%m]" "%3C [%Z] %?X?%2X& -? %%s %-20.20L %?M?+%-2M&   ? %s %> [%4c]asladfg" "%[%s]" |'*/
// ////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define DAY (time_t)86400
#define WEEK (time_t)604800
#define YEAR (time_t)31556926

int main(int argc, const char *argv[]) {
    time_t current_time;
    time_t message_time;
    struct tm *ltime;
    unsigned int todays_seconds=0;
    unsigned int seconds_this_morning=0;

    const char *last_year, *this_year, *last_months, *last_week, *today;
    const char *format;
    char *concat_str;

    current_time = time(NULL);
    ltime = localtime(&current_time);
    todays_seconds = ltime->tm_hour*3600 + ltime->tm_min*60 + ltime->tm_sec;
    seconds_this_morning = current_time - todays_seconds;  // unix time @ 00:00

    if (argc != 7) {
        printf("Usage: %s last_year this_year last_week today format timestamp\n", argv[0]);
        return 2;
    }

    last_year    = argv[1];
    this_year    = argv[2];
    last_week    = argv[3];
    today        = argv[4];

    format       = argv[5];

    message_time = atoi(2 + argv[6]);

    if (message_time >= seconds_this_morning) {
        asprintf(&concat_str, "    %s", today);
        printf(format, concat_str);
    } else if (message_time >= seconds_this_morning - DAY) {
        asprintf(&concat_str, "ydy %s", today);
        printf(format, concat_str);
    } else if (message_time > seconds_this_morning - WEEK) {
        printf(format, last_week);
    } else if (message_time/YEAR < current_time/YEAR) {
        printf(format, last_year);
    } else {
        printf(format, this_year);
    }

    return 0;
}

Это форматирует даты следующим образом (все время в формате 24h):

  • 02:04 для сегодняшней почты
  • ydy 02:04 для вчерашней почты
  • Чт 02:04 за последние 7 дней почты
  • 27.Mar для почты текущего года
  • 13.12.16 для почты прошлых лет

Полный формат индекса в этом примере — #no [флаги] #no_of_attachments даты отправителя субъект msg_size

4
27.01.2020, 19:50

Эта переменная index_format

set index_format='mfdate "%[%s]" "%4C %Z %[!%b %d %Y] %-17.17F (%3l) %s" |'

вместе с этим модифицированным mfdate.c, представленным в этом ответе от пользователя hop:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define DAY (time_t)86400
#define YEAR (time_t)31556926

int main(int argc, const char *argv[]) {
  time_t current_time;
  time_t message_time;

  const char *old = "old";
  char *recent = "recent";
  char *today = "today";
  const char *format;

  current_time = time(NULL);

  if (argc != 3) {
    printf("Usage: %s format\n", argv[0]);
    return EXIT_FAILURE;
  }

  format = argv[2];

  message_time = atoi(argv[1]);

  if ((message_time/YEAR) < (current_time/YEAR)) {
    printf("%s,%s", old, format);
  } else if ((message_time/DAY) < (current_time/DAY)) {
    printf("%s,%s", recent, format);
  } else {
    printf("%s,%s", today, format);
  }

  return EXIT_SUCCESS;
}

у меня корректно работает в mutt 1.6.1 и как видите проблем со знаком % в теме нет , если это вот в чем заключалась настоящая проблема: enter image description here

Это первоначальная «просто рабочая» версия, потому что, внимательно изучив ваш первоначальный вопрос, я не уверен, что это то, что вы хотите. Однако, если это то то, что вам нужно, дайте мне знать, и мы подумаем, как сделать его лучше.

РЕДАКТИРОВАТЬ:

Он также может работать с вашим предпочтительным index_format:

set index_format='mfdate "%[%s]" "%%Z %%{%%Y %%b %%e  %%H:%%M} %%?X?(%%X)&   ? %%-22.22F  %%.100s %%> %%5c" |'

mfdate.c:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define DAY (time_t)86400
#define YEAR (time_t)31556926

int main(int argc, const char *argv[]) {
  time_t current_time;
  time_t message_time;

  const char *old = "old";
  char *recent = "recent";
  char *today = "today";
  const char *format;

  current_time = time(NULL);

  if (argc != 3) {
    printf("Usage: %s format\n", argv[0]);
    return EXIT_FAILURE;
  }

  format = argv[2];

  message_time = atoi(argv[1]);

  if ((message_time/YEAR) < (current_time/YEAR)) {
    printf("%s,%s%%", old, format);
  } else if ((message_time/DAY) < (current_time/DAY)) {
    printf("%s,%s%%", recent, format);
  } else {
    printf("%s,%s%%", today, format);
  }

  return 0;
}

enter image description here

EDIT:

Позвольте мне объяснить, как это работает:

mfdate принимает 2 аргумента:

"%[%s]"

и:

"%%Z %%{%%Y %%b %%e  %%H:%%M} %%?X?(%%X)&   ? %%-22.22F  %%.100s %%> %%5c"

Первый аргумент только время сообщения, как описано в Документация index_format в .muttrc:

# %[fmt]  the date and time of the message is converted to the local
#         time zone, and ``fmt'' is expanded by the library function
#         ``strftime''; a leading bang disables locales

В этом случае fmt заменяется на %s, поскольку %s означает количество секунд с начала Эпохи, как описано в man strftime. То Первый аргумент используется для вычисления того, сколько лет сообщению и что ярлык: старый, недавний или сегодня должен быть.

Второй аргумент — оставшаяся часть index_format Переменная. Он используется в mfdate только для печати, но дополнительный % используется добавлено в конец printf, потому что, как сказано в руководстве по Mutt:

Возвращаемая строка будет использоваться для отображения. Если возвращенная строка оканчивается на %, он будет пропущен через средство форматирования во второй раз.

Каждый % удваивается здесь, потому что мы хотим передать литерал % в второе форматирование сделал mutt.

0
27.01.2020, 19:50

Теги

Похожие вопросы